# C03 test plan · authored expected · p4-toy-1
วันที่ 2026-10-12. จดผลคาดหวังนี้ก่อนการรันจริง ใช้ [fixture.json](../lab/fixture.json) และ [calculator.py](../lab/calculator.py). แหล่งทุกพารามิเตอร์เป็น authored_teaching_parameters รุ่น p4-toy-1 ไม่มีค่าผู้ผลิต

## Expected outcomes independently authored
- PAY01: outside_bounds; metrics {"total_mass_kg":7,"cg_m":0.057142857,"mass_ok":true,"cg_ok":false,"usable_wh":160,"energy_ok":false}
- PAY02: outside_bounds; metrics {"total_mass_kg":7,"cg_m":0.028571429,"mass_ok":true,"cg_ok":true,"usable_wh":160,"energy_ok":false}
- PAY03: numeric_fit; metrics {"total_mass_kg":7,"cg_m":0.028571429,"mass_ok":true,"cg_ok":true,"usable_wh":160,"energy_ok":true}
- PAY04: unknown; metrics {"total_mass_kg":null,"cg_m":null,"mass_ok":null,"cg_ok":null,"usable_wh":160,"energy_ok":true}
- PAY05: outside_bounds; metrics {"total_mass_kg":7,"cg_m":0.057142857,"mass_ok":true,"cg_ok":false,"usable_wh":160,"energy_ok":false}

## Known bounds and missing data
mass = limit, |CG| = limit และ required = usable ผ่านตัวเลข; reserve = 1 หรือมวล 0 ถูกปฏิเสธ; null payload mass เป็น unknown
ไม่มีการชั่ง ทดสอบโครงสร้าง ติดตั้ง บิน วัด endurance หรือรับมอบจริง; reserve 20% ไม่ใช่ค่าปลอดภัยสากล
ดู schema, keys, null fields และ parser bounds ครบใน [lab readme](../lab/readme.md). ทุก 17 cases ต้อง valid ก่อนมี output ใด ผลเปรียบเทียบใช้ exact Fraction ก่อนปัดแสดงเก้าตำแหน่ง
- CAMERA: target/GSD, samples >= min; storage <= capacity. เฉพาะ GSD nullable; storage ยังคำนวณแยก
- DATA: bytes × 8 / bitrate; age รวมเวลา; unknown → offline_hold → stale_plan → expired (>=TTL) → deadline_missed (>deadline) → numeric_fit. Offline timing เป็นเพียง nominal; ไม่มีการส่ง
- PAYLOAD: sum mass และ weighted signed CG; unknown mass ทำให้ total/CG/flags null; usable=capacity×(1-reserve) ยังทราบได้

## Negative and boundary checks before accepting the tool
ในสำเนาท้องถิ่นของ fixture ให้ทดสอบ unknown/missing fields, duplicate keys, NaN/Infinity, boolean ในช่องตัวเลข, zero/negative positive quantities, จำนวนเกินขอบ, reserve=1, case ID ซ้ำ/ลำดับผิด, null ที่ไม่ได้อนุญาต, JSON ผิดรูป, ไฟล์เกิน 64KiB, numeric token ยาวเกิน32 หรือ exponent เกิน12. คาด exit2 ไม่มีผล JSON stdout และมีข้อความ stderr; ห้ามนำค่าคาดหวังมาปลอม actual.
ทดสอบค่าที่เท่าขอบผ่านและค่าข้ามขอบไม่ผ่านตามสูตรข้างต้น รวม TTL equality ต้อง expired. การเปลี่ยนข้อมูลในสำเนาเป็น learner experiment ต้องเก็บ diff/expected/input hash ใหม่ ไม่อ้างว่าเป็นผล fixture ที่แจก

## Replay and restored baseline
รันไฟล์เดิมสองครั้ง output bytes ต้องเท่ากัน ตรวจคู่ PAY01 กับ PAY05: model/disposition/metrics ต้องเท่ากัน ต่างได้เฉพาะ case_id.
คู่ที่ให้เป็น authored rollback scenarios; การคืนงานตนต้องคืนสำเนา fixture v0 ตรวจ SHA-256 ว่าตรงฐานแล้วรันใหม่ด้วย script รุ่นเดิม เก็บ actual เปรียบเทียบฐานพร้อม raw bytes. ไม่แก้ firmware หรืออุปกรณ์จริง.
Metadata ที่ต้องบันทึก: เวลา command Python version exit source/fixture/expected hashes raw output hash reviewer (ยัง not_assigned). แยก expected/actual และ discrepancy → change → retest.
ก่อน parent run results.csv มี header เท่านั้น = NOT_RUN. Host result ของผู้เขียนไม่เป็นผลผู้เรียน. Hardware/flight/RF/field NOT_RUN; permissions/receiver NOT_CONFIRMED; learner NOT_RUN.
