# M10 ใบงาน D: ตัวรับออฟไลน์ที่ตรวจซ้ำได้

อ่านสัญญาก่อนโค้ด รักษา expected ที่เผยแพร่ไว้เป็นอิสระจากฟังก์ชัน receive แล้วรันกับสำเนาในโฟลเดอร์งานของตน ผลของผู้จัดทำใช้แทนชิ้นงานผู้เรียนไม่ได้

## งาน หลักฐานและเกณฑ์รายรหัส

| รหัส | ก่อนเริ่มและงานเติม | เป้าหมาย | งาน/หลักฐาน | เกณฑ์ตรวจ |
|---|---|---|---|---|
| APP-M10-D-K01 | รู้ JSON/CSV และชนิดข้อมูล; ทวน [รวมระบบ](https://drone.pk-research.work/knowledge/integration/) แล้วอธิบาย boolean ต่างจาก integer | อธิบายสัญญาและลำดับตรวจผ่านอินเทอร์เฟซ | ผัง input→validation→disposition→output พร้อมสมมติฐาน prior | ครบขอบ/ลำดับทุกขั้น; แยก digest จากความน่าเชื่อถือผู้ส่ง; ไม่มี protocol compatibility claim |
| APP-M10-D-S01 | อ่านไฟล์และรัน Python ได้หรือบันทึกข้อจำกัด; ทวน [ทดสอบ](https://drone.pk-research.work/knowledge/testing/) แล้วเขียน expectedก่อนรัน | รันแลบออฟไลน์อย่างทวนซ้ำได้ หรือบันทึก NOT_RUN ตามจริง | C01–C12 actual ไฟล์ดิบ/คำสั่ง/exit/แฮช baseline-current/replay และ D01–D08 proposals | ผลจริงเทียบ expectedอิสระ; repeatไบต์ตรง; หากรันไม่ได้บันทึกเหตุและยังไม่มีหลักฐานSการรัน |
| APP-M10-D-E01 | พร้อมแยก actual/expected; ทวน [หลักฐาน](https://drone.pk-research.work/knowledge/imagery-analysis/evidence-report/) แล้วแก้claimปลอดภัยเพราะSHA | รายงานระดับหลักฐานและจำกัดข้อมูล/การทำงาน | claim/status กับขอบ input/output และ actual NOT_RUN ของส่วนไม่ทดสอบ | ไม่มี network/flight/human/learner claim; ไม่executeข้อมูล; ไม่อ้างsandbox security certification |
| APP-M10-D-C01 | พร้อมเก็บ baselineและตอบข้อทัก; ทวน [รวมระบบ](https://drone.pk-research.work/knowledge/integration/) แล้วระบุtriggerเปลี่ยนschema | ควบคุมการแก้และคืนไฟล์พร้อมตรวจซ้ำ | D-v0/D-v1 change log สำเนาที่แก้/ต้นฉบับคืน/แฮช/recheck/owner | ไม่ทับต้นฉบับ; schema/TTL/plan/softwareเปลี่ยนทวนใหม่; แจ้งผลเก่าหมดความเกี่ยวข้อง |

CLO/PLO เว้นว่าง **pending_design** ทุก ID ใช้ผลจากชิ้นงานจริง การส่งใหม่ให้คงรุ่นเดิม เพิ่มรุ่น v1 ระบุข้อทัก สิ่งที่แก้ เหตุ หลักฐานและผู้รับผิดชอบ แล้วส่งตรวจรหัสเดิมใหม่ E ตรวจพฤติกรรมลดข้อมูล/พักข้ออ้าง C ตรวจการเก็บรุ่น รับคำทักและติดตามข้อค้าง ไม่อนุมานจากการเขียนว่าเข้าใจ

## D01–D08 ข้อเสนอขยายที่ยังไม่รัน

ทุกแถวเป็น **actual NOT_RUN** แยกจาก C01–C12 ไม่เพิ่มผลผ่านจากการมีแผน

| ID | เงื่อนไขทดสอบที่เสนอ | expected ที่ต้องตรวจ | actual |
|---|---|---|---|
| D01 | คีย์ JSON ซ้ำ/เกิน/ขาด | nonzero ก่อนสร้าง output | NOT_RUN |
| D02 | เวลาเป็น boolean/ติดลบ/NaN | ปฏิเสธทั้ง fixture | NOT_RUN |
| D03 | payload เกิน4096ไบต์/fixtureเกิน64KiB | ปฏิเสธก่อนผล | NOT_RUN |
| D04 | incoming ทั้งหมดอายุและdigestผิด | expired ตามprecedence | NOT_RUN |
| D05 | priorผิดdigest/ผู้รับ/รุ่น | ปฏิเสธสมมติฐานก่อนผล | NOT_RUN |
| D06 | message_idเดิมแต่เปลี่ยนrecipient/time/TTLที่ยังvalid | conflictเมื่อถึงขั้นตรวจซ้ำ; identity/timeอาจปฏิเสธก่อน | NOT_RUN |
| D07 | outputมีอยู่/symlink ancestor | nonzero ไม่ทับข้อมูลเดิม | NOT_RUN |
| D08 | expectedมีIDซ้ำ/ขาด/unknown disposition | nonzeroก่อนoutput | NOT_RUN |

## สถานะและขอบหลักฐาน

รุ่น 1.17.24 · 12 ตุลาคม 2026 · [บท M10](https://drone.pk-research.work/knowledge/drone-applications/communications-support/)

K = Knowledge ความรู้; S = Skills ทักษะ; E = Ethics จริยธรรม; C = Character ลักษณะบุคคล

B ผู้เริ่มต้น; O ผู้ปฏิบัติงาน/ผู้วางแผน; D ผู้พัฒนา/ผู้ปรับแต่ง

ชุดนี้ใช้เตรียมการเรียน ยังไม่มีผู้เรียนทดลอง ผลผู้เรียนเริ่มที่ **NOT_RUN** ผู้ตรวจสาขา **not_assigned** การทบทวน **pending_field_review** และเกณฑ์ความพร้อม P3 ยังเปิด CPX-Sim พักอยู่ คำว่า accepted ในแลบหมายถึงผ่านเงื่อนไขตัวรับจำลองเท่านั้น ไม่อนุญาตบิน เปิดเผยข้อมูล หรือใช้ข้อความตัดสินใจในเหตุฉุกเฉิน

หลักฐานสี่ระดับต้องลงแยก: (1) authored_offline_teaching_fixture คือข้อมูลและ expected ที่แต่งขึ้น (2) host_offline_simulation คือผลที่รันจริงบนคอมพิวเตอร์ ต้องแนบไฟล์ดิบ เวลา คำสั่งและแฮช (3) RF/link/flight/human receipt เป็น NOT_RUN (4) ผลผู้เรียนเป็น NOT_RUN จนมีชิ้นงานจริง การตรวจของผู้จัดทำหรือสคริปต์ผ่านไม่ใช่การรับรองสมรรถนะผู้เรียน ผลตรวจเผยแพร่ให้ดูบันทึกจริงของผู้จัดทำ ห้ามเติม PASS จากตาราง expected

## โจทย์ที่ทุกบทบาทใช้ร่วมกัน

TEAM-R เป็นทีมสมมติ ต้องการข้อความสรุปคำขอสิ่งของตาม PLAN-1 ก่อนหมดอายุและมีสิทธิ์รับข้อมูล ระบุคนใช้ผล ผลิตภัณฑ์ข้อมูล กำหนดเวลา ความครบ ความหมาย รุ่นแผน และผู้อนุญาตเผยแพร่ก่อนเลือกช่องทาง ไม่มีบุคคลหรือพิกัดจริงใน fixture

แยกช่องควบคุมการบิน (command/control), ข้อมูลสถานะอากาศยาน (telemetry), ข้อมูลภารกิจจากอุปกรณ์บรรทุก (payload/data) และการส่งมอบระหว่างองค์กรออกจากกัน การพบสัญญาณแสดงตัว การรับคำสั่ง จำนวนไบต์ที่ส่ง ตัวรับตรวจผ่าน ข้อความตอบรับ และผู้รับนำไปใช้ เป็นคนละหลักฐาน ต้องบันทึกว่าข้อความตอบรับมาจากส่วนใดและยืนยันอะไร เมื่อช่องข้อมูลขาดให้ใช้ทางเลือกข้อมูลตามแผน ส่วนความปลอดภัยการบินต้องทำตามแผน lost-link ของอากาศยาน/ผู้ปฏิบัติงานที่ได้รับอนุมัติจริง แบบฝึกนี้ไม่สั่งการบินหรือกำหนดการตอบสนองสากล

การเลือกมีสามแกนอิสระ: รูปแบบอากาศยาน เช่น multirotor/ปีกตรึง/VTOL; เจ้าของระบบหรือผู้ให้บริการ; สถาปัตยกรรมส่งข้อมูล เปรียบเทียบสาย/เครือข่ายภาคพื้น ผู้ส่งข้อมูลออฟไลน์ ผู้ให้บริการ การเก็บพักแล้วส่งต่อ และจุดทวนอากาศแบบ tethered ตามความเข้ากันได้ สิทธิ์ ทรัพยากรและข้อจำกัดจริง การมีสายยึดไม่ได้ยืนยันเครือข่ายพร้อมใช้งาน ต้องมีสถานีรับ พลังงาน คนดูแล และสิทธิ์เข้าถึงทั้งสองปลายทาง ชื่อประเภทไม่รับรองระยะหรือความต่อเนื่อง

**ตัวอย่างคำนวณที่แต่งขึ้น:** ข้อมูลดิบไม่บีบอัด 2 MiB = 2 × 1,048,576 ไบต์ = 16,777,216 บิต ที่อัตราสมมติ 256 kbit/s = 256,000 บิตต่อวินาที ใช้เวลาส่งเนื้อข้อมูลอย่างน้อย 16,777,216 ÷ 256,000 = **65.536 วินาที** ยังไม่รวมส่วนหัว การลองซ้ำและช่วงขาด หากโจทย์สมมติต้องได้ใน 30 วินาที ให้ลดข้อความ/บีบอัดโดยรักษาความหมาย ปรับผลิตภัณฑ์ หรือใช้ช่องทางอื่น ไม่สรุปว่าต้องเพิ่มกำลังส่ง อัตรา (ต่อวินาที) ต่างจากขนาดทั้งหมด; latency คือเวลาหน่วงของกระบวนการที่ระบุจุดเริ่ม/จบ; age คือเวลาปัจจุบันลบเวลาสร้าง ความต่อเนื่องบริการต้องรวมไฟฟ้า คน บริการและการส่งต่อด้วย

## แปดขั้นจากคำขอถึงการทวนรุ่น

1. กำหนดผู้รับ ผลิตภัณฑ์ข้อมูลและกำหนดเวลา พร้อมความครบ ความหมายและสิทธิ์ใช้
2. เลือกอากาศยาน บริการและเครือข่าย โดยเทียบทางเลือกภาคพื้นด้วยเกณฑ์เดียวกัน
3. ยืนยันคน พลังงาน ลิงก์และสิทธิ์ทั้งสองปลายทาง แยก requested จาก confirmed
4. ทวนอินเทอร์เฟซข้อมูล เวลา คุณภาพและแผนแบ่งปัน พร้อมผู้มีอำนาจอนุญาต
5. เตรียมและทดสอบช่องทาง/ตัวรับตามขอบที่อนุญาต แบบฝึกนี้ทดสอบบนเครื่องออฟไลน์เท่านั้น
6. ดำเนินภารกิจและทางเลือกสำรองตามแผนที่อนุมัติ ภายใต้ผู้ปฏิบัติงานรับผิดชอบ
7. ให้ตัวรับทวนข้อมูล แล้วขอคนรับยืนยันแยกกัน บันทึกต้นทางและความหมายของ acknowledgement
8. เก็บรุ่น ข้อแก้และบทเรียน ทวนเมื่อเงื่อนไขเปลี่ยน และแจ้งผู้ถือสำเนาเก่า

## สัญญาข้อมูลฉบับเต็ม

Schema คือข้อกำหนดชื่อ/ชนิด/ขอบของข้อมูล; fixture คือชุดกรณีแต่งเพื่อฝึก; disposition คือผลจัดการของตัวรับ; TTL คืออายุที่ยอมรับได้ตามโจทย์แต่ง; digest คือค่าตรวจเนื้อไบต์ SHA-256 ไม่ยืนยันผู้ส่งหรือสิทธิ์; duplicate คือข้อความซ้ำครบเนื้อหา; collision ในที่นี้คือรหัสเดิมแต่ข้อมูลต่าง; replay คือรันซ้ำด้วยอินพุตเดิม ไม่ใช่ส่งซ้ำเข้าอากาศยาน

JSON ต้องเป็น UTF-8 ไม่เกิน 64 KiB ปฏิเสธชื่อคีย์ซ้ำ NaN/Infinity และคีย์ขาด/เกินทุกระดับ โครงสร้างรองรับไม่เกิน 16 กรณี แต่ชุดสอนและ expected นี้กำหนด **C01–C12 ครบครั้งเดียวตามลำดับ** ทุกกรณีเริ่มสถานะใหม่ ไม่สะสมผลข้ามกรณี

| ระดับ | ชื่อฟิลด์ทั้งหมดและความหมาย |
|---|---|
| บนสุด | schema_version = toy-m10-1; evidence_basis = authored_offline_teaching_fixture; cases = รายการกรณี |
| กรณี | case_id = C01–C12; now_s = เวลาตรวจจำนวนเต็ม 0–86400 วินาทีสัมพัทธ์; connected = true/false; message = ข้อความเข้า; prior_accepted = null หรือข้อความเดิมที่สมมติว่ารับแล้ว |
| ข้อความ | message_id = รหัสข้อความ; kind = mission_data หรือ heartbeat; recipient = ผู้รับ; plan_version = รุ่นแผน; created_s = เวลาสร้าง; ttl_s = อายุที่อนุญาต; payload = เนื้อความ; payload_sha256 = digest ที่ผู้แต่งประกาศ |
| ขอบข้อความ | IDs ใช้ ASCII ตัวอักษร/ตัวเลขนำ ตามด้วยตัวอักษร/ตัวเลข/_/- ยาวรวม 1–32; created_s จำนวนเต็มตั้งแต่ 0; ttl_s จำนวนเต็ม 1–3600; boolean ใช้แทนจำนวนเต็มไม่ได้; payload เป็นข้อความ UTF-8 ไม่เกิน 4096 ไบต์; digest เป็นเลขฐานสิบหกตัวเล็ก 64 ตัว |

ตัวรับสอนกำหนด TEAM-R และ PLAN-1 ค่าจำนวนทั้งหมดเป็นขอบการสอน ไม่ใช่ข้อกำหนดวิทยุ/การบิน นาฬิกาเป็นวินาทีสัมพัทธ์แต่ง ไม่ใช่เวลาวัดจริง ตรวจโครงสร้างทั้งไฟล์ก่อนสร้างผล จากนั้นตรวจ kind → ผู้รับ → รุ่นแผน → เวลาในอนาคต → อายุ → digest → รหัสซ้ำ/ขัดแย้ง → การเชื่อมต่อ → accepted ตามลำดับนี้

อายุ = now_s − created_s; เมื่อ age >= ttl_s ปฏิเสธ แม้เท่ากันพอดี ตรวจ digest จาก UTF-8 ของ payload ตรงตามประกาศเท่านั้น ผู้แก้ข้อความอาจแก้ digest ให้ตรงด้วย จึงไม่พิสูจน์ source authenticity (ตัวตนต้นทาง), authorization (สิทธิ์) หรือความจริงของเนื้อหา

prior_accepted เป็นสมมติฐานการสอนว่ารับข้อความนั้น ณ created_s ไม่ใช่ log จากการรันครั้งก่อน ต้องมีรูปแบบถูก kind mission_data ผู้รับ/แผนปัจจุบัน digest ตรงและ created_s ไม่เกิน now_s การหมดอายุปัจจุบันของข้อความเข้าตรวจเป็นอันดับก่อนการซ้ำ หาก message_id ตรงและ **ทุกฟิลด์ข้อความตรง** ให้ duplicate_ignored หากรหัสตรงแต่ต่างฟิลด์ให้ id_conflict โดยรักษาต้นฉบับไว้ เมื่อไม่เชื่อมต่อให้ queued_offline ซึ่งไม่ใช่ accepted ไม่มีคิวถาวรหรือเครือข่ายในสคริปต์ กรณี reconnect จำลองด้วยอินพุตอิสระและตรวจใหม่ ณ เวลานั้น

## ค่าตั้งต้นและผลคาดหวังทั้ง 12 กรณี

ฐานทุกกรณี: message_id MSG-01, kind mission_data, recipient TEAM-R, plan_version PLAN-1, created_s 10, ttl_s 30, payload `TRAINING supply request summary`, payload_sha256 `2e179f75c3337e8c64641e91c7e91e16fc882a8cdc514282b508f7a2f5abd4aa`, now_s 20, connected true, prior_accepted null เว้นที่ระบุด้านล่าง C02/C03 ใช้ prior เป็นข้อความฐานเต็ม

| กรณี | เปลี่ยนจากฐาน / เหตุ | expected_disposition |
|---|---|---|
| C01 | ข้อความปกติ อายุ 10 | accepted |
| C02 | prior ฐานเหมือนข้อความเข้าทุกฟิลด์ | duplicate_ignored |
| C03 | prior ฐาน; payload ใหม่ TRAINING corrected supply request พร้อม digest ใหม่ | id_conflict |
| C04 | now_s 40; อายุ 30 เท่ากับ TTL | expired |
| C05 | recipient TEAM-X | wrong_recipient |
| C06 | connected false | queued_offline |
| C07 | now_s 25 และ connected true; สมมติกลับมาก่อนหมดอายุ | accepted |
| C08 | now_s 45 และ connected true; สมมติกลับมาหลังหมดอายุ | expired |
| C09 | digest ประกาศเป็นเลข 0 ครบ 64 ตัว | integrity_mismatch |
| C10 | plan_version PLAN-0 | stale_plan |
| C11 | kind heartbeat เป็นซองที่ถูกชนิดแต่ไม่ใช่ข้อมูลภารกิจ | not_mission_data |
| C12 | created_s 30 มากกว่า now_s 20 | future_timestamp |

C03 digest ใหม่คือ `9263c89c28ed47f5fbd062c6c34b6a7cf5f803d90260eed0cd9a0ead731d9d58` ตารางนี้เป็น expected ที่เขียนก่อนผลรัน C07/C08 ไม่ได้ต่อคิวจริงจาก C06 การใช้ MSG-01 ซ้ำข้ามกรณีไม่ชนกันเพราะ reset อิสระ

## ดาวน์โหลดและการรันที่ทวนได้

หลักฐานเสริมจากการตรวจของผู้จัดทำ: [ผลตัวรับที่รันจริงบนเครื่อง](https://drone.pk-research.work/downloads/drone-applications/communications-support-host-results.csv) และ [สรุปผลเครื่อง](https://drone.pk-research.work/downloads/drone-applications/communications-support-host-summary.json) เป็นสองไฟล์นอกชุดเรียนแปดไฟล์ รวมเผยแพร่สิบไฟล์ อ่านระดับหลักฐานในไฟล์ก่อนอ้างผล ผลเหล่านี้เป็น host-only ไม่ใช่ผลผู้เรียน วิทยุ การบินหรือการยืนยันของคน ผู้เรียนยังลง NOT_RUN จนทำและเก็บผลของตนเอง

เก็บแปดไฟล์ในโฟลเดอร์เดียวกัน: [beginner](communications-support-beginner.md), [operator](communications-support-operator.md), [developer](communications-support-developer.md), [rubric](communications-support-rubric.md), [readme](communications-support-readme.md), [fixture JSON](communications-support-fixture.json), [expected CSV](communications-support-expected.csv), [Python lab](communications-support-lab.py) ไม่ต้องติดตั้งแพ็กเกจ Python ใช้ standard library เท่านั้น หากเครื่องไม่มี Python หรือไม่มีสิทธิ์รัน ให้ทำตาราง expected บนกระดาษและลง actual NOT_RUN พร้อมเหตุ

ตรวจเนื้อโค้ดก่อนรันในโฟลเดอร์งานเฉพาะของตน คำสั่งตัวอย่างเมื่ออยู่ในโฟลเดอร์แปดไฟล์และยังไม่มี run-01/run-02:

```text
python communications-support-lab.py --output-dir run-01
python communications-support-lab.py --output-dir run-02
```

ผลสร้างเฉพาะ receiver-results.csv และ summary.json ใน output directory ใหม่ที่ต้องระบุ; โฟลเดอร์แม่ต้องมีอยู่แล้ว สคริปต์ไม่ทับโฟลเดอร์เดิม ปฏิเสธ symlink/reparse ancestor ไม่มีชื่อไฟล์จาก fixture ไม่มี execute/eval/subprocess/network และไม่ต่อวิทยุ/อากาศยาน การตรวจพาธนี้เป็นการป้องกันความผิดพลาดในแลบท้องถิ่น ไม่ใช่การรับรองต้านผู้โจมตีที่แข่งแก้ระบบไฟล์

Expected CSV มี case_id,expected_disposition ครบ C01–C12 ค่าผลอนุญาตเฉพาะสิบคำในตาราง Actual CSV มี case_id,expected_disposition,actual_disposition,matched,evidence_level โดย matched เป็น true/false และระดับ host_offline_simulation Summary มี schema_version,case_count,matched_count,evidence_level,radio,flight,human_receipt,learner_results รายการท้ายสี่ช่องเป็น NOT_RUN Exit 0 คือ actual ตรง expected ทุกกรณี; 1 คือมีผลต่าง; 2 คือ input/output ถูกปฏิเสธ โครงสร้างผิดทั้ง fixture ต้องหยุดก่อนมีผลลัพธ์ใหม่ หากระบบไฟล์เขียนล้มเหลว อาจมีโฟลเดอร์ผลไม่ครบ ให้บันทึก failure และใช้ชื่อใหม่

เก็บแฮช SHA-256 ของ lab/fixture/expected ก่อนรันเป็น baseline และหลังรันเป็น current แนบคำสั่งจริง stdout/stderr exit code และเวลาแยกจากผลที่ไม่มี timestamp เปรียบเทียบไฟล์ผลทั้งสองรอบแบบไบต์ต่อไบต์ ต้องตรงเมื่ออินพุตไม่เปลี่ยน บันทึกเครื่องมือ/รุ่น Python ด้วย ใน PowerShell ใช้ `Get-FileHash -Algorithm SHA256 <file>` และตรวจความเท่ากันของค่า Hash อย่าแต่งค่าแฮชหรือคัด expected มาเป็น actual

การทดลองเปลี่ยนให้ทำกับ **สำเนา** ระบุรุ่นก่อน/หลัง เปลี่ยนทีละเงื่อนไข เก็บต้นฉบับไว้ เมื่อคืนให้ใช้ไฟล์ baseline ที่ไม่แก้แล้วตรวจแฮชและรันใน output ใหม่ การคืนรุ่นนี้คืนเฉพาะไฟล์แบบฝึก ไม่ใช่ rollback firmware หรือผลิตภัณฑ์ ห้ามสรุปการอนุญาต/ความพร้อมบินจากผลนี้

## แหล่งอ้างอิงและสิทธิ์

แนวคิดที่ใช้ประกอบอ่านอย่างจำกัดในบทหลัก: [COM01 MAVLink Command Protocol](https://mavlink.io/en/services/command.html), [COM02 MAVLink Heartbeat](https://mavlink.io/en/services/heartbeat.html), [COM03 RFC 9171](https://www.rfc-editor.org/rfc/rfc9171.html) ระบุเป็นแหล่งข้อมูล ไม่อ้างว่าตรวจมาตรฐานครบ/errata/security หรือเข้ากันได้กับโปรโตคอล Schema/TTL/คณิตศาสตร์/กรณีในชุดนี้เป็นงานแต่ง ไม่ใช่ MAVLink หรือ RFC 9171 wire implementation

งานสอนที่เรียบเรียงใหม่ โดย PK-Research / Drone-Hub ใช้ [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) ให้เครดิตชื่อชุด รุ่น แหล่งและสิ่งที่แก้ สื่อ/เอกสารของเจ้าของภายนอกคงสิทธิ์เดิม ใบอนุญาตนี้ไม่ขยายสิทธิ์ให้สื่อเหล่านั้น
