Material Tag V0.1 firmware verification receipt
Client date: 2026-10-03 Asia/Shanghai
Scope: macOS host C99 core + Python NDJSON/HTTP logical simulator
Physical nRF52840/EPD/GPIO/USB serial/BLE verification: NOT PERFORMED

COMMAND: make test sanitize demo
Compiler flags: -std=c99 -Wall -Wextra -Werror -Wpedantic -Wconversion -Wshadow -Wformat=2 -O1 -g
Observed exit code: 0
test_material_tag: PASS 111 checks; sizeof(mt_tag)=5328 bytes; event_slots=16; history=8
test_sanitize: PASS 111 checks; AddressSanitizer+UndefinedBehaviorSanitizer; no diagnostics
host_demo: display_ack after simulated render callback; Button1 event; retry retains event_id and increases attempts from 1 to 2

C coverage:
- label/command/string/task validation, NaN/Infinity/fraction/negative/over-limit quantity rejection
- same-ID dedupe/content conflict, pending render exclusion, stale version rejection
- display ACK not emitted on command receipt; failed render preserves displayed task
- button uses prior displayed task while a new render is pending
- exact event retry identity, exponential schedule, ACK retirement, duplicate ACK handling
- queue saturation, reserved display ACK slot, sequence exhaustion
- LED expiry and debounce/retry timing across uint32 clock wrap
- compile-time 8192-byte core-state ceiling

COMMAND: python3 -m unittest discover -s tests -p 'test_serial_simulator.py' -v
Observed exit code: 0
Ran 7 tests in 3.585s
OK
Tests use an actual loopback HTTP fixture (standard-library HTTPServer), not the application backend.
test_create_task_and_button_retry_preserves_id ... ok
test_display_receipt_separate_from_business ... ok
test_http_failure_is_nack_not_ack ... ok
test_invalid_data_never_reaches_http_mutation ... ok
test_malformed_and_oversized_records ... ok
test_multi_task_requires_display_selection ... ok
test_sync_stable_id_and_no_token_leak ... ok

HTTP fixture verifies the CSRF header, endpoint/payload mapping, multi-task selection,
no token emission, canonical event UUID, UTF-8 byte limits, malformed NDJSON handling,
display receipt fsync-before-ACK, and that HTTP rejection never becomes business ACK.
After updating the bridge to omit Button2 task_id as required by the real backend,
all 7 HTTP fixture tests were re-run successfully (3.144s).
Actual application backend also passed 41 assertions across electronics/general/lineside;
see firmware-app-integration.txt. Isolated temporary DB and OS-assigned port were used.

Limitations: RAM-only queue/history; reboot recovery and persistent event journal absent;
driver interfaces and pin header are contracts, not compiled or flashed board drivers;
host_demo fixed JSON fixture is not a board-side JSON parser;
serial_simulator is logical HTTP simulation and does not execute the C core.
