The phone now rings on cue from the game with NO firmware change. A
call_on_scene map (phone_directory.yaml: {SCENE_X: number}) tells the
gateway which scenes are scripted incoming calls; since the runtime
already pushes the scene to /game/step, the gateway auto-rings the PLIP
with that NPC on scene entry (deduped, once per entry). Factored a
_ring_board helper (shared by /game/call + auto-ring). Map ships empty
(no surprise rings) with commented examples for the designer.
Les puzzles de zacus_v3.yaml n'avaient ni `act`, ni `objective`, ni
`firmware_step` (requis par le validateur schema V2). Ajout calqué sur
zacus_v2 : Diapason→acte 1, Piano LEFOU→acte 2, QR Archives→acte 2 ;
valeurs déduites du contenu existant (scène, runtime_steps, solution).
Le scénario valide, compile et simule désormais le playthrough complet.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Les guillemets typographiques servaient de pseudo-délimiteurs YAML :
les valeurs chargées contenaient littéralement “…” (endpoints LLM/TTS,
names des puzzles) et la séquence du piano valait [“L”,“E”,…] au lieu
de [L,E,F,O,U]. Conversion “”→", ‘’→', …→... ; tirets et « » français
conservés. Parse vérifié avant/après (yaml.safe_load).
Server-side fuzzy alias table applied to the final STT transcript
before forwarding to /voice/intent. Closes the metier-vocabulary
gap of generic STT models (U-SON, LA 440 Hz, Zacus, ...) without
needing per-request prompt biasing — which moshi-server's Rust
runtime does not expose anyway.
Loader is soft on pyyaml (degrades to no-op if missing) and on
the yaml file itself (logs + skips on parse error). Patterns are
case-insensitive with auto word-boundaries, with a (?...) escape
hatch for advanced regex.
Per-puzzle entries layer on top of globals — firmware passes
puzzle_id in the hello frame; legacy clients omit it and get
just the global polish. Loaded once at module import; restart
voice-bridge to reload.
Unit tested on 5 representative transcripts (eu son nez -> U-SON,
diapazon -> diapason, le rasus -> Zacus, le la 440 hertz -> LA 440 Hz).
Adds slice D_P4 of the hints engine: an adaptive level *floor* derived
from the group profile (TECH / NON_TECH / MIXED / BOTH), the elapsed
stuck-time, and the per-puzzle failed-attempt counter. The floor is
combined at the call site as
level_served = max(level_requested, count + 1, level_floor_adaptive)
and clamped to NPC_MAX_HINT_LEVEL.
Configuration lives in game/scenarios/hints_adaptive.yaml (override
via HINTS_ADAPTIVE_PATH). When the file is absent, adaptive mode is
silently disabled (warning logged) so the engine keeps running with
the existing P3 logic.
Adds two firmware-driven endpoints:
- POST /hints/puzzle_start seeds puzzle_started_at_ms (idempotent,
with optional force=true to restart)
- POST /hints/attempt_failed bumps failed_attempts_for_puzzle, 404s
on unknown puzzle_id
/hints/ask gains an optional group_profile field and now reports
level_floor_adaptive, stuck_minutes, failed_attempts and
group_profile_used in every response (refusal envelope included).
Auto-trigger on stuck-timer remains firmware-side (slice D_P6) — this
slice does not poll, only serves higher levels when asked.
Tests: 35 / 35 green (26 P1+P2+P3 unchanged + 9 new). Backward
compatible by construction: when group_profile is omitted MIXED is
used and at t=0 the floor is 0, so the existing P3 decision stands.
Phase P1 of the playtest harness design spec:
* tools/playtest/run_playtest.py — replays a playtest YAML
against the Runtime 3 IR and compares to (or updates) a
snapshot JSON
* game/scenarios/playtests/zacus_v3_60min_tech.playtest.yaml
— first canonical playtest, resolves PUZZLE_LA_440 via the
UNLOCK_LA_440 unlock event
* game/scenarios/playtests/snapshots/
zacus_v3_60min_tech.snapshot.json — committed reference
* Makefile: new "playtest" target wiring the runner via uv
Critical-asserts evaluator and TS runner are out of P1 scope.
- npc_phrases.yaml: full phrase bank (hints, personality,
adaptation, bridges, false leads, ambiance) in French
- generate_npc_pool.py: batch TTS generator (Piper API)
- test_npc_engine.py: 21 unit tests for trigger logic
- test_npc_phrases_schema.py: YAML schema validation (12 tests)
- Fix FAST_PROGRESS guard: use absolute time limit to prevent
false positives after several minutes on a scene
Impact: Sprint 3 NPC data layer complete. 33 tests passing.
- Introduced SceneGyrophareConfig structure for configuration parameters.
- Implemented SceneGyrophare class with methods for creating, destroying, and updating the gyrophare effect.
- Added rendering functions for background, beams, and warning triangle.
- Integrated timer for animation updates based on frame rate.
- Created a log file for ESP32 audio kit boot information.
- Removed 9 unused screen JSON files: SCENE_BROKEN, SCENE_CAMERA_SCAN, SCENE_FIREWORKS, SCENE_LA_DETECT, SCENE_MEDIA_ARCHIVE, SCENE_SIGNAL_SPIKE, SCENE_WIN, SCENE_WINNER, SCENE_WIN_ETAPE.
- Updated AGENT_TODO.md to reflect the cleanup actions and results.
- Enhanced StorageManager to handle SD card access failures with a failure streak mechanism, switching to LittleFS after repeated failures.
- Added support for aliasing long action IDs to short filenames in the generator.
- Improved scenario manager to handle different key names for action IDs in YAML files.
- Updated multiple scene JSON files to improve visual themes, effects, and transitions.
- Changed effect speeds and added missing timeline objects for better scene management.
- Enhanced SCENE_LA_DETECTOR, SCENE_LEFOU_DETECTOR, SCENE_MEDIA_MANAGER, SCENE_QR_DETECTOR, SCENE_WARNING, SCENE_WIN_ETAPE1, and SCENE_WIN_ETAPE2 with refined titles, subtitles, and symbols.
- Introduced a new user live logger script to capture serial logs during real user playtests for better debugging and analysis.
- Added a workbench export/import tool to streamline scene editing and synchronization with JSON files.
- Improved FX verificator documentation to clarify usage modes and verification processes.
* docs: import zacus conversation bundle v3 and close ZIP intake TODO
* tools: add reproducible validator installer and document next gates
* docs: remove ZIP terminology and align intake docs to conversation bundle
* tools: add runtime bundle validator and update docs workflow
* feat: promote gameplay scenario and enforce G3 bundle checks in CI
* docs: add deep repo analysis and next-step TODOs
* Initial plan (#107)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
- Implemented QrUnlockApp class with methods for lifecycle management (begin, start, update, stop, handleEvent) and snapshot retrieval.
- Created header file for QrUnlockApp with necessary method declarations and private members.
- Added Yamale schema for scenario template to define prompt input and optional firmware snapshot.