Skip to content

Latest commit

 

History

History
445 lines (397 loc) · 25.1 KB

File metadata and controls

445 lines (397 loc) · 25.1 KB

Verification

This document owns the current test layers, review evidence, physical acceptance boundary, and release gate.

Several words below are used in a narrower sense than ordinary English, and most are also names in the code or on the wire. GLOSSARY.md gives the plain meaning of each one and where the name appears. ../README.md and PRODUCT.md avoid these terms entirely.

Software checks

Check the generated device contract from the repository root:

python3 tools/protocol_codegen.py --check

Check the complete asset/scene branch with its owning verifier:

tools/spritekit/venv/bin/python tools/spritekit/verify.py

That verifier checks the tracked scene header and native parser vector before it discovers or runs any spritekit test.

Check the host bridge from packages/code-chan:

npm ci
npm run typecheck
npm test

npm test uses Node's recursive discovery and its pretest checks both generated contracts. Test count is not a completion criterion; changed tests must be audited for their production path, oracle, mocks, and adversarial meaning.

Check firmware from firmware/stackchan:

pio test -e native
pio run -e cores3-stackchan
pio run -e cores3-stackchan -t buildfs

The asset and scene tests prepare outputs in memory or write only below a temporary directory. They do not refresh tracked vectors, asset build directories, or firmware installation data.

The scene-package generator must also be run without --check before buildfs or uploadfs, because the generated installation directory is ignored.

What the checks establish

Host checks exercise the real HostBridgeRuntime, DeviceProtocolSession, ForegroundCoordinator, selected producer adapter, loopback ingress, and transport boundary. They cover:

  • hello, initial snapshot, and operational synchronization before hook service;
  • epoch rejection, protocol fault, and transport loss;
  • graceful close requiring the exact accepted goodbye_ack and completed local write, identical retry after a lost receipt, rejection and deadline failure, listener retention through serial cleanup, and listener reacquisition after both successful and failed close;
  • executable termination that coalesces repeated SIGINT and SIGTERM, retains both handlers throughout the awaited close, and preserves close failure after removing them;
  • scheduled synchronous non-blocking serial reads, retry classification, complete line delivery, terminal failure once, and no descriptor access by a scheduled read after close;
  • prompt lease ownership, same-turn continuation, simultaneous sessions, and ignored foreign sessions;
  • concurrent hook-handler exclusion across prompt admission, coordinator correlation, and device publication;
  • main-response Stop closing tool and attention activity and canceling permission while active children, incomplete child delivery, and undelivered background results continue draining;
  • producer-bound adapter, device-session, coordinator, event, and response types, with runtime rejection of a mismatched composition;
  • Claude-only status-line usage ingress that a Codex bridge refuses, a relay that fails closed below Claude Code 2.1.196, and an exact bounded canonical loopback sample — unexpected keys, uncanonical or oversized identifiers, and out-of-range metrics are rejected as HTTP 400 while a valid but stale sample is a 200 with no state change; host projection of the bounded 0100 percentages to the canonical prompt identity; and session admission that binds a sample to the current foreground working turn and drops a stale or foreign one;
  • the opt-in status-line installer: a version preflight that refuses an old or missing claude before any settings read or write, exact-entry ownership that preserves a foreign or moved-checkout entry, an untracked local-settings target that leaves the tracked file byte-identical, and byte-invariant failure on malformed settings;
  • canonical device-protocol snapshot invariants declared in device.json and emitted to both codecs from one contract edit, with generic codegen that does not branch on message field names, and field-specific scene alphabets shared by the native parser and the Python builder;
  • producer-specific terminal evidence, with Codex root/child completion kept separate from Claude Stop, StopFailure, and continuation behavior, and notifications unable to complete either producer;
  • Claude background-result paths with both child-before-Stop and Stop-before-child ordering, one later response wakeup, one final outcome, and no state change from an unowned child terminal;
  • distinct Codex parent and child turns, exact child start/stop pairs, child-tool non-promotion, duplicate child-turn rejection, and no device answer for Codex or Claude child permissions;
  • Codex Stop root completion and exact SubagentStop child completion in the supported non-continuing hook composition, including both arrival orders, duplicate idempotency, and a draining child that a later prompt cannot erase;
  • Codex user interruption without Stop or SessionEnd keeping the same episode, with a further prompt from that session joining it so its evidence correlates and its terminal event settles it, and with no elapsed-time release on any path;
  • exclusion of documented Claude child-owned prompt, tool, and notification hooks from parent lifecycle state;
  • completed-lineage non-revival and session idle/end release;
  • impossible, duplicate, stale, and wrong-turn producer sequences;
  • permission admission, timeout, abort, exact device response, and no-answer settlement, including service-queue progress while the physical decision is pending and after abort or expiry;
  • Codex documented turn IDs and Claude documented prompt IDs;
  • exact codec shapes, limits, duplicate-key rejection, and UTF-8 framing.

Native firmware checks execute the production parsers, wire builders, DeviceConnection, ExpressionLifecycle, BodyActuationProcess, BodyMotionProgramProcess, BodyCalibrationProcess, DisplayOutputProcess, LedOutput, SoundOutput, the board power target, scene package parser, scene controller, compositor, layout validator, and touchscreen classifiers. They cover:

  • source and epoch exclusion, acknowledged startup, uncertain USB liveness, goodbye receipt replay without effect replay, stale-close exclusion after a replacement owner, fault, and current-owner routing;
  • complete snapshot replacement, activity/outcome replay suppression, and permission answerability;
  • display initialization and operation deadlines at strict-before, exact, and late boundaries, using the same predicate in result admission and periodic observation;
  • generation supersession, stale and duplicate results, wake during suspend, and result-queue failure;
  • one boot-to-terminal display owner across the dark boot gate, presenter initialization, calibration frames, normal scene frames, local fault presentation, suspension, and explicit darkness; first-visible ordering is wake, complete frame transfer, then confirmed backlight enable, while every failure and dark path uses the common panel-sleep and confirmed-rail-disable tail;
  • calibration display failure before body-output admission performs no body mutation, while the same failure after admission requests exactly one typed body cleanup and preserves the display-specific cause;
  • explicit calibration-record provenance and boot selection; compatible full-envelope validation; state- and region-bounded calibration input; torque-disabled preparation; fresh stationary pose evidence; a separate release-gated motion confirmation; invalidation of capture-only record version 1; production-motion-owner synchronization; exact right, center, left, and center pose order; persistence only after four live ControllerSettled outcomes; exact persistence readback; and cleanup without persistence on load limit, device fault, rejection, unavailable evidence, deadline, persistence failure, and uncertain output disable;
  • body activation with the rail-enable command confirmed before evidence-driven torque-disable retries, installed two-axis minimum/maximum position-limit and directional-dead-zone acquisition, measured raw pose admission, and exact two-axis hardware goal-register write/read confirmation;
  • the production StackChanBodyMotion owner against an independent scripted servo-bus model: missing, malformed, unordered, and pose-excluding installed limits; directional dead zones outside their documented domain; target rejection outside a confirmed installed range; bounded interpolation; exact final-goal readback; stable controller-stop sampling independent of residual; exact-target feedback remaining pending while moving=1; both exact-target and 25-step residual feedback producing ControllerSettled after stable moving=0 samples; retained directed-progress evidence; current/load-backed pitch LoadLimited; non-zero-status DeviceFault; invalid feedback; and unavailable final-goal or feedback evidence retained across intervening valid samples;
  • lifecycle consumption of typed actuation outcomes, strict activation and quiescence deadlines, exact body_activation_timeout, separate readiness and neutral-presentation results, newer semantic-program supersession, recoverable ordinary NotPresented, and all-attempt quiescence, including completed versus incomplete disable-command tails; native adversarial cases reject software-only goal acceptance and preserve the implicated axis through the matching bounded local fault-frame projection. Native evidence does not claim the powered interval before torque-disable confirmation is physically motionless;
  • production application ordering from goodbye admission through connected expression release, disconnected publication, disconnected semantic-program admission, and only then goodbye_ack, plus the calibrated neutral pose's expected raw target;
  • one production body-actuation caller across runtime and calibration; independent child/lifecycle generations, stale-result exclusion, immediate state-evidence semantic supersession, and rapid working-to-idle-to-turn- outcome replacement; the exact fixed-pitch left/right/center working sequence, controller-settlement-gated center followed immediately by the next sweep's first pose, bounded targets, distinct interactive presentation-fault meaning, and wrap-safe presentation deadlines;
  • independent LED and sound hardware writers: expression and outcome replacement, transient cancellation, RGB darkness, observed speaker stop, bounded missing-evidence failure, and wrap-safe presentation scheduling; application composition checks that ordinary sleep requests auxiliary cleanup before body quiescence;
  • the production shutdown composition: one stopping status, expression-owned body quiescence and display suspension, adoption of in-flight sleep safety work without duplicate owner commands, no graceful result before both body and display safety evidence, one PMIC call on graceful, child-fault, and deadline paths, first-fault retention, failed-request reporting, and duplicate-hold exclusion;
  • permission-control isolation, wake-only touchscreen presses, and body-touch non-authorization;
  • exact unversioned scene-package shape, package size, palette and pixel bounds, layout visibility, control separation, background connectors, and render layer order;
  • generated scene-catalog freshness and accepted-set parity: every builder limit comes from the package descriptor, while firmware resource identity, kind, playback, timing, and role validation comes from the same tracked scene and asset lineage;
  • the exact final manifest emitted by the Python builder, through a tracked generated vector, deserializes with the production firmware parser and passes the production fixed-role validator;
  • working caption composition from manifest labels, the 09 and % glyphs, the bounded worst-case caption, rejection of over-budget usage labels, and the display-only reclassification of a usage-only snapshot change so it refreshes the caption without waking body, servos, LED, or sound;
  • hook projection idempotence: projecting an already-projected hook returns the same value, whatever the projection reduces. The relay and the bridge both project, so losing this degrades what terminal events prove and turns stop settling. The check exists because that regression was observed on hardware, not as a hypothetical;
  • retained-episode expression: a stopped response whose obligations are still outstanding is waiting, shows its manifest caption, carries no usage, keeps its turn identity, plays no cue, and leaves the device free to sleep; a Codex root that finished while its exact child is live reaches the same shared meaning, and a child that starts after the response stopped is admitted rather than faulted.

The board-shutdown composition check uses the real application, connection, expression, body, and display owners and replaces only physical hardware ports. Its oracle requires connected graceful shutdown to combine exact stopping acknowledgement with body and display safety in either arrival order. It also proves that a missing acknowledgement cannot reach PMIC before the aggregate deadline, while stopping-send failure, child fault, and deadline paths each retain their defined one-shot fail-safe result. A target return never proves physical power removal.

The CoreS3 target build proves that target-specific M5Unified, FreeRTOS, StackChan-BSP, panel, body, and PMIC code compiles together. buildfs proves the generated package can be assembled into the configured LittleFS image. Neither command proves a physical effect.

Review gate

A passing command is evidence only for its exercised boundary. Review must also establish:

  • one owner contains each invariant-bearing process;
  • adapters and the application loop cannot reorder or bypass that owner;
  • stale, duplicate, malformed, late, or cross-owner input cannot reach a side effect;
  • time represents a request or failure boundary, never successful completion;
  • generated contracts, source, tests, and public documents use the same current vocabulary;
  • obsolete classes, pull-style shutdown requests, version readers, aliases, fallback layouts, and migration paths are absent;
  • tests use production composition where the invariant crosses components and do not derive their oracle from the implementation under test.

Final software inspection includes git diff --check, contract freshness, the complete changed-tree review, and a stale-symbol search. The generated native scene parser vector is tracked contract evidence. Installation output, dependency directories, .WORK/ material, and device captures remain untracked.

Physical acceptance

Compilation and native doubles are not physical acceptance. Hardware acceptance requires one recorded working-tree hash, generated scene hash, firmware binary hash, identified CoreS3, matching filesystem-first installation, and direct observation of the affected display, touchscreen, body touch, servo, LED, sound, USB, and PMIC boundaries.

What the return channel can and cannot establish

The device answers on ten messages: hello_ack, goodbye_ack, snapshot_ack, device_initializing, device_operational, device_stopping, device_fault, decision, touch, and effect_ack. PROTOCOL.md owns their meaning.

That set establishes what the device was told and that it accepted the telling. It reports no panel-sleep state, no servo position or motion, and nothing about legibility. No amount of host-side driving substitutes for looking: whether the body actually rests, whether the panel actually sleeps, and whether a caption is actually readable are irreducibly visual, and an acceptance run must budget a person for them rather than infer them from an acknowledged snapshot.

State the division before the run, not after. A case whose evidence is an acknowledgement may be recorded from the trace; a case whose evidence is a physical effect is recorded only from observation, and an unobserved case is recorded as unobserved rather than as passed.

Artifact identity

The recorded firmware binary is byte-reproducible: the same sources rebuilt at a different time yield the same firmware.bin, so an unchanged hash after a rebuild is a reproducibility signal and not evidence of a stale install. The LittleFS image is not byte-reproducible, so the generated scene content hash, not the image hash, is the scene's identity in an acceptance record.

Record both, and record what a hash covers. A working-tree hash that moves because documentation changed does not invalidate an installed pair; state the reason the hash moved instead of silently re-pinning it, and state whether an unchanged generated hash was measured again or carried forward by inference from unchanged inputs.

Cases

The current integrated source is not physically accepted until all applicable cases below pass from that one installed state:

  1. From one new firmware installation without a code-chan calibration record, confirm that the local calibration screen appears without a bridge or ordinary scene, that the head can be aligned while torque remains disabled, and that the first confirmation captures but does not store the observed home after stable live evidence. Clear both hands, press START SAFE MOTION TEST, and verify that no motor starts before release. Observe the bounded right, center, left, and safe-center sequence without a device fault, load-limit fault, or abrupt motion. Confirm the success screen appears only after the return evidence and reports both outputs disabled, then release the restart touch and boot normally. One complete disconnected prompt with uncorrupted tracked image resources must become visible before ordinary servo motion, body LEDs, sound, body touch, or permission input are enabled. Body activation must reach the interactive neutral pose inside its bound without abrupt or cumulative yaw.
  2. Two consecutive automatic ordinary-suspend and touchscreen-wake cycles and two short-button suspend/wake cycles without a bridge. The disconnected prompt must remain free of hero, drones, decisions, arrival, and sleep effect. Each first touchscreen press is wake-only, all four wakes must avoid abrupt yaw, and every cycle must end in the same interactive neutral prompt.
  3. Two connected idle short-button suspend/wake cycles. Body output must park, sound stop, code-chan LEDs darken, the suspend projection appear, and touchscreen and short-button wake must each restore one complete visible frame before body output resumes.
  4. A Codex bridge sequence: acknowledged producer-ready, first-prompt working showing the WORKING caption, two-session exclusion, same-turn continuation, subagent draining, harmless approve and reject, terminal outcome, and session-end release.
  5. The same sequence with a Claude bridge, including one physical rejection that proves the harmless operation did not execute. With the Claude status-line command installed, confirm the working caption shows the remaining usage percentages and returns to WORKING when no sample is current, and that the usage read-out never alters hero motion, drones, or sound.
  6. A task longer than 60 seconds for each producer must remain working until real terminal or session evidence arrives. An interruption that emits no supported terminal evidence must emit no outcome. For a passive Codex Desktop interruption, submit the next prompt on the same session and confirm it joins the episode rather than being refused: its evidence must correlate without an error prompt, and its terminal event must settle the episode. The bridge has to be restarted only when a session dies while its response is still active, because nothing can then arrive to release it.
  7. Bridge or link loss with permission pending must return no answer, remove controls, reject late device input, and permit a later fresh epoch to synchronize without inherited replica or deduplication state.
  8. Five consecutive external Codex bridge start/stop cycles must each complete hello, snapshot, and operational synchronization without a runtime-status timeout. Each stop must receive its current-epoch close acknowledgement, cancel transient output, return the head to neutral, remove stale working presentation, and leave the disconnected prompt rather than BRIDGE UNCERTAIN. Then verify USB Uncertain presentation after silence and recovery from a valid current-epoch message.
  9. Battery-powered long hold: exactly one stopping observation, safe rest, sound stop, code-chan LED darkness, servo torque and power disable, display suspension, and physical power removal. The PMIC indicator is identified separately from code-chan-controlled LEDs.
  10. USB-powered long hold: record the same ordered safety effects, the host's device_stopping response and successful terminal result before the PMIC removes USB, the PMIC request evidence, whether rails are physically removed while VBUS remains, and the state after cable removal. A lit PMIC or charge indicator is not reported as a code-chan LED failure. A live but non-interactive terminal state with no documented recovery is a failure, not successful shutdown.
  11. Inject display and body failures through non-actuating owner tests and verify exact canonical fault presentation, no duplicate body-motion wait after the disable-command tail completes, and that no late result enables output or issues a second PMIC request after the deadline-owned fail-safe tail. Do not physically block a servo to induce a timeout.
  12. Record a 30-second cadence sample and verify stable 24 Hz presentation without catch-up bursts or partial frames.

Physical observations must distinguish firmware execution evidence from electrical outcome. An accepted AXP2101 register write proves the firmware reached the PMIC boundary; it does not by itself prove that board rails fell. Conversely, disappearance of serial or display alone does not prove code-chan LED and servo shutdown order.

Release handoff

The supported distribution model is a source checkout with the documented Node.js, Python, PlatformIO, hook, serial, scene-generation, filesystem, and firmware procedures. No npm publication is required.

Public redistribution is not release-complete while the repository has no tracked LICENSE. License selection is a user product decision and is not inferred by implementation work.

Current open evidence

The current integrated source still requires the applicable unaccepted cases from the hardware matrix above. The identified installation has recorded acceptance for repeated suspend/wake, current Codex and Claude harmless permission decisions, and pending-permission link loss. The host lifecycle correction after that recording does not change firmware, the device protocol, or permission authorization, so those observations remain applicable.

On 2026-08-03, the preceding Claude host source physically kept a background child active across the main response boundary, produced no intermediate completion effect or sound, continued through the later result, emitted one final completion, and remained at CLAUDE READY without a later MISS. The 2026-08-04 attempt/commit replacement instead remained working after its final Stop because the expected idle notification did not arrive. The current source removes that notification dependency and restores producer-bound Stop settlement, so both observations are supporting evidence but do not accept the replacement lifecycle implementation.

The current producer-lifecycle boundary remains open until one stable Codex root-plus-child completion sequence and one Claude background-child episode verify no intermediate ready/effect/sound, exactly one final outcome, no later MISS, and normal bridge close with the final installed configuration. Battery-powered long hold and the post-change 30-second cadence sample also remain open. These are missing physical evidence, not software pass claims.

The Claude physical permission path is confirmed on hardware, including its trigger. During an ordinary session on Claude Code 2.1.216 a PermissionRequest delivery arrived unprompted, the device presented the decision controls, and an approve decision returned over serial. That decision could only have come from the device: the coordinator's answer entry point is reachable from the serial decision message alone, with no timeout, default, or auto-approve path.

This corrects an earlier reading. A previous long session on the same version saw no PermissionRequest arrive at all, and that was recorded as an open question of whether the version still emits the event or had moved interception into a PreToolUse decision. The event is not gone — it fires on this version and the whole path works. What actually varies is whether anything is asked, which depends on the session's permission mode and remembered allowances. Absence of physical prompts is therefore a configuration observation, not an adapter defect, and no adapter change is warranted. Codex needs no equivalent investigation on this basis.