# 0.4.0 Voice / Unified Target / Session Settings verification

Date: 2026-10-03 (Asia/Shanghai). Base: `9f06a4b` on `main`.
Firmware, FastAPI, CONTROL_VERSION and Protocol are **0.4.0**.

## Verified software behavior

- **NO DECISION = KEEP WAITING.** No automatic approval, rejection or expiration.
  Registry monotonic-clock regression, Pi accepted-socket controlled-timer test,
  Codex connection-generation regression, device host C++ tests and Admin tests
  all retain pending approvals until an explicit decision or cancellation.
- Pi socket registration is bounded to five seconds, accepted decisions are not.
  Pi channel failure blocks separately from human rejection. Codex cancellation
  uses native cancel or drops an invalid generation; it never replays decisions.
- Pi/Codex unified targets, persisted legacy target interpretation, agent_state /
  agent_activity, dynamic Agent page, model and effort, completed notifications.
- 600 ms long press / 30 ms debounce, no trailing click, Approval priority,
  push-to-talk and settings modals, SEND/CANCEL transcript confirmation.
- Shared ES8311/I2S0 capture at 44.1 kHz / 16-bit mono; 40 ms chunks, eight-frame
  bounded queue, overflow cancellation, independent 20-second capture limits.
- Memory-only WAV assembly, injectable STT interface, OpenAI-compatible multipart
  adapter, STT failure does not send input, stale IDs/target changes/disconnects/
  Approval cannot resurrect pending transcripts.
- Actual authenticated **TLS WSS** synthetic-device tests for Pi and Codex:
  selected target → agent_state → PCM chunks → **fake STT** → transcript → explicit
  SEND → adapter input. Fake results are not evidence of real transcription.
- Model settings validated through adapter capability metadata; busy sessions
  return 409. Quick catalog preserves current/recent/native default order and
  contains at most six models. Admin retains the full catalog.

## Real agent smoke

Pi proof: `/tmp/device-settings-040-4i94r3wr/result.json`.
Same session `01a0ff6c-27c2-7487-87d5-5eda3644a113`, native model read/set,
`PI_SETTINGS_READY`, and model readback after SDK runtime close all passed.
The tested provider has only one confirmed working model, `haihub/deepseek-flash`;
this was an **idempotent** set. SDK's other configured-key catalog entries were
not claimed as authenticated/working inference models.

Codex proof: same result file, temporary thread
`01a0ff6c-351b-74b3-aabf-f0bd7bb4f9ad`. `model/list`, native model set, advertised
`low` effort, authoritative `thread/read`, subsequent `CODEX_SETTINGS_READY` turn
and post-unsubscribe readback passed. Native catalog: gpt-6-astra, gpt-5.6-sol,
gpt-5.6-terra, gpt-5.6-luna, gpt-5.5. Tested gpt-6-astra advertised efforts:
low / medium / high / xhigh / max / ultra. No fixed effort enum is embedded in UI.
A separate-client real Codex turn was also observed through native rejoin:
`EXTERNAL_TURN_OBSERVED`, DONE, same turn ID (PASS). Observation rejoins only
already-loaded threads; selecting dormant history does not start a runtime.

Limits: the shared daemon retained the thread after unsubscribe; this does not
prove pre-next-turn durability across daemon restart. Gateway uses only official
settings/resume APIs and does not add shadow settings persistence or edit Agent
session/config files. Existing Pi TUI sessions need `/reload` for the new approval
handshake/settings extension. New SDK hosts load it automatically.

Real approval regression: `/tmp/device-lab-approval-smoke-pxqviu94/result.json`.
Pi inspection bypass, Admin rejection, synthetic-device B rejection, A approval,
and Codex rejection/approval all passed on isolated temporary files. Pending
requests did not mutate files. Infinite waiting is covered with controlled clocks,
not a real 120-second sleep.

## STT availability

**REAL STT SMOKE: SKIPPED. REAL STT READY: NO.**
No GATEWAY_STT provider is configured. Read-only probes found an existing OpenAI
credential but its `/v1/models` request returned HTTP 401; the configured Pi
provider's model-list probe returned HTTP 404. Neither proves usable audio
transcription. No credential was printed, copied into the repository, fabricated
or obtained from another account. Fake STT passes are labelled separately.

Configure an authorized transcription provider in the repo-external 0600 Gateway
env to perform a real WAV → expected transcript smoke. Audio will be sent to that
configured provider. See [voice/privacy instructions](voice-input-design.md).

## Checks and firmware

- `./scripts/test-server.sh`: 2 host C++ executables; 15 JS tests; 33 Python tests;
  HTTP/WS smoke; Pi and Codex authenticated TLS WSS fake-STT voice smoke.
- `./scripts/build.sh m5stack-stopwatch`: PASS, ESP-IDF 5.5.4 / ESP32-S3.
- `git diff --check`: PASS.
- `dist/m5stack-stopwatch/firmware.bin`: **1,128,976 bytes**, 73% app partition free.
- `dist/m5stack-stopwatch/merged-flash.bin`: **1,194,512 bytes**.
- Merged SHA256: `8a3cc192916a675052288ee4a8c0b8581a96c335e7ae2ced8f8c94ba696449fc`.

Artifacts contain local provisioning and remain Git-ignored. They are generated
at `dist/m5stack-stopwatch/` for the existing Mac flashing workflow.

## Readiness

VOICE TRANSPORT READY: YES

REAL STT READY: NO

PI SETTINGS READY: YES (idempotent real-model smoke)

CODEX SETTINGS READY: YES

READY FOR PHYSICAL VOICE/SETTINGS VERIFICATION: YES

Physical validation is still **PENDING**, including the prior 0.3.0 audio/A-B
baseline. Verify actual microphone input, clipping/gain, start/end cues, absence
of speaker feedback, long-release/page behavior, Approval preemption, settings
visibility and DONE/FAILED/APPROVAL audio. A real STT provider is required for
physical end-to-end transcription. No next-stage features were started.
