From 9f19fed8a11386ca4a36f926663893719b488c3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=27=C3=A9lectron=20rare?= <108685187+electron-rare@users.noreply.github.com> Date: Sun, 3 May 2026 16:29:47 +0200 Subject: [PATCH] chore: bump ESP32_ZACUS + nested CLAUDE.md refresh Submodule bump: 6129375 -> 1a984b0 Pulls in the firmware build fixes pushed to github.com/electron-rare/ESP32_ZACUS branch fix/build-arduino-esp32-3.20014 (PR pending review). The firmware now compiles cleanly and survives boot on the Freenove ESP32-S3 dev board (verified flash + 30 s monitor: SD mounted, LittleFS ready, no panic, 90 k UI frames). Once the upstream PR is merged to main, the parent pointer can be re-bumped to ESP32_ZACUS@main without changes. CLAUDE.md refresh (init-deep follow-up): - frontend-v3/apps/atelier/CLAUDE.md (new, 61 lines): layout map, store responsibilities, lazy-chunk pattern, dev-only window hooks, build with --base, anti-patterns. - desktop/CLAUDE.md (+8 lines): Tests section + npm test command + --ignore-scripts install hint. - tests/CLAUDE.md (+1 line): list test_firmware_bundle.py alongside test_runtime3_routes.py. All nested CLAUDE.md remain within the 30-80 line target (longest is atelier at 61). --- ESP32_ZACUS | 2 +- desktop/CLAUDE.md | 8 ++++ frontend-v3/apps/atelier/CLAUDE.md | 61 ++++++++++++++++++++++++++++++ tests/CLAUDE.md | 3 +- 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 frontend-v3/apps/atelier/CLAUDE.md diff --git a/ESP32_ZACUS b/ESP32_ZACUS index 6129375..1a984b0 160000 --- a/ESP32_ZACUS +++ b/ESP32_ZACUS @@ -1 +1 @@ -Subproject commit 6129375916537423ba68637b5236de1c51369487 +Subproject commit 1a984b006d1c97043d3adf14d3f6377a596be451 diff --git a/desktop/CLAUDE.md b/desktop/CLAUDE.md index 977bdf2..29e073c 100644 --- a/desktop/CLAUDE.md +++ b/desktop/CLAUDE.md @@ -19,13 +19,21 @@ resources/ # Bundled frontend artefacts + assets ```bash npm install # Triggers electron-builder install-app-deps + electron-rebuild +npm install --ignore-scripts # Skip native rebuild (sufficient for unit tests) npm run dev # Concurrent main + renderer npm run build # tsc main + vite renderer npm run build:mac # Universal (x64 + arm64) installer npm run build:mac-arm64 # Apple Silicon only npm run rebuild-native # zacus-native addon for current Electron ABI +npm test # Vitest unit tests (mocks electron + serialport) ``` +## Tests + +Unit tests live in `src/**/__tests__/**/*.test.ts` and run via Vitest in node env. `electron`, `fs`, `os`, and `http` are mocked via `vi.mock` so tests need neither a real ESP32 nor the native serialport rebuild. + +Out of scope here: Playwright Electron mode (would launch the packaged app), HTTP-flow OTA tests (need server fixture), BLE/USB delegation paths. + ## Patterns - Three tsconfigs (`tsconfig.main.json`, `tsconfig.renderer.json`, root) — never share between processes; main and renderer have different module systems. diff --git a/frontend-v3/apps/atelier/CLAUDE.md b/frontend-v3/apps/atelier/CLAUDE.md new file mode 100644 index 0000000..7ce8b6a --- /dev/null +++ b/frontend-v3/apps/atelier/CLAUDE.md @@ -0,0 +1,61 @@ +# Atelier + +Scratch-like authoring studio: Blockly editor (left/center) + R3F 3D simulation stage (right) + validation console (bottom). Live-diff: edit a block → 500 ms debounce → stale badge → click Run → simulation reloads via `simStore.loadScenario(yaml)`. + +Design doc: `docs/superpowers/specs/2026-05-01-v3-fusion-atelier-design.md`. + +## Layout + +``` +src/ + main.tsx # ReactDOM root, StrictMode + App.tsx # useLiveDiff() + ; dev hooks on window + main.css # Shell + pane styles + vite-env.d.ts # Vite client types + components/ + Layout.tsx # PanelGroup tree, ⌘B stage toggle + EditorPane.tsx # Lazy(BlocklyWorkspace) + register blocks + validate on change + StagePane.tsx # Lazy(RoomScene + mode HUDs) + Run button + ConsolePane.tsx # Mode tabs + validation entries list + BlocklyWorkspace.tsx # forwardRef wrapper around Blockly.inject + toolbox.ts # XML toolbox config + YamlPreview.tsx # Syntax-highlighted YAML rendering + blocks/ + {puzzle,npc,flow}-blocks.ts # Block definitions + YAML generators + index.ts # registerAllBlocks (idempotent) + scene/ # R3F 3D scene (RoomScene, RtcPhone, PuzzleStations, NpcBubble) + puzzles/ # P1Sound, P5Morse, P6Symbols, P7Coffre (3D widgets) + modes/ # SandboxMode, DemoMode, TestMode HUDs + stores/ # editor / runtime / sim / validation (zustand) + lib/ + yaml-export.ts # workspace -> YAML + yaml-import.ts # YAML -> workspace + validator.ts # 6-rule schema check (ScenarioYaml -> ValidationResult) + useLiveDiff.ts # debounce 500 ms then setPendingIr +``` + +## Patterns + +- **Lazy chunks** via `React.lazy` + Suspense for both Blockly (~700 kB gzip) and R3F+three (~1 MB gzip). Initial shell stays under 80 kB. Vite `manualChunks` in `vite.config.ts` enforces the split. +- **Stores stay focused**: `editorStore` = blocklyJson string ; `runtimeStore` = pending/current IR + isStale ; `simStore` = mode + engine instance + npcMood ; `validationStore` = entries with `severity` + `source` (schema|compile|runtime|test). +- **Mode is sim concern**, not editor↔stage sync — lives in `simStore`. ConsolePane reads from there. +- **Run button** in `StagePane` is the only commit point: it calls `simStore.loadScenario(pendingIr)` then `runtimeStore.commitPendingIr()`. +- **Tailwind classes are not configured** — use inline styles or `main.css` classes (`atelier-pane`, `atelier-mode-tab`, `atelier-resizer--*`). Tailwind in legacy simulation HUDs was rewritten as inline styles during P4. +- **Dev-only window hooks**: `App.tsx` exposes stores on `window.__atelierStores`, `Layout.tsx` exposes `window.__atelierToggleStage`, `EditorPane.tsx` exposes `window.__atelierBlockly.getWorkspace()`. All gated by `import.meta.env.DEV`. E2E specs drive workflow through them instead of relying on real DnD. + +## Build + +```bash +pnpm exec vite build --base=/atelier/ # for prod deployment with prefix +pnpm exec vite build # for dev / desktop bundle (root path) +``` + +`pnpm --filter @zacus/atelier build -- --base=...` does NOT pass `--base` correctly through the script chain — call vite directly via `cd apps/atelier && pnpm exec vite ...`. + +## Anti-patterns + +- Putting `mode` back into `runtimeStore` — it belongs to `simStore`. +- Calling `voiceWsConnect()` or any lwip-touching code at boot without a network-ready guard (matches the ESP32_ZACUS bug fix from this session). +- Hardcoding `/atelier/` as base path — the dev server uses root, only the deployed prod build uses the prefix. +- Adding deps to root `frontend-v3/package.json` — atelier deps live here. +- Bypassing the Run button to mutate `simStore.engine` directly — breaks the live-diff contract. diff --git a/tests/CLAUDE.md b/tests/CLAUDE.md index 309ae2e..5ab823e 100644 --- a/tests/CLAUDE.md +++ b/tests/CLAUDE.md @@ -9,7 +9,8 @@ Python unittest suite covering Runtime 3 IR, NPC engine integration, and scenari | `test_npc_engine.py` | NPC state machine (triggers, mood, rule firing) | | `test_npc_integration.py` | NPC ↔ TTS ↔ phrase bank wiring | | `test_npc_phrases_schema.py` | `npc_phrases.yaml` schema invariants | -| `runtime3/` | Runtime 3 compiler/IR/pivot tests | +| `runtime3/test_runtime3_routes.py` | Runtime 3 compiler/IR/pivot tests | +| `runtime3/test_firmware_bundle.py` | E2E pipeline: scenario YAML → IR → firmware bundle JSON (subprocess) | ## Running