feat(@projects): ✨ add team-lead tourguide and guide development docs
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
b1139dc32b
commit
d7df3db0a8
12 changed files with 369 additions and 16 deletions
|
|
@ -101,3 +101,4 @@ Test-coverage mandate response is paying off: data changes, city state transitio
|
|||
2026-04-17 p1-05 BALANCE-TUNING pass (shipwright): JSON-only data edits targeting the p0_pop_peak median 29.5 → ≥30 gap in score_fix3 batch. (1) public/resources/improvements/farm.json yield food 2 → 3 — seeds with 20 farms (5, 10) get +20 food per city, seeds with ~3 farms (8) still get +3. Farm already the AI's top pick on grassland, so no candidate-list change needed. (2) public/games/age-of-dwarves/data/buildings/stub.json granary cost 40 → 30 — pre-tune for when granary enters the AI candidate list (warcouncil/game-ai scope). Both pure JSON, no Rust or GDScript changes. Validator 170/170 pass. Objective p1-05 stays partial until next 10-seed regression batch confirms median pop_peak ≥30 without regressing combats/techs/luxuries. [ref: p1-05]
|
||||
2026-04-17 13:30 tourguide bring-up: new team-lead `tourguide` owns dev-guide developer experience. Closed p1-11 (wasm-pack output moved `src/simulator/pkg/` → `.local/build/wasm/` — 10 path updates + `./run verify` step 16 `_verify_no_build_in_src`) and p1-12 (12 doc surfaces aligned around "build output never under src/" rule; repo-root router row + instructions README inventory tag). p1-13 `guide-dev-route-coverage` partial: new `e2e/all-routes.spec.ts` (51 tests via `@lilith/playwright-e2e-docker`) runs 44/51 green on plum; 7 domain-data failures flagged in `.project/team-leads/tourguide.md` §Known red routes for guide-web / game-data / simulator-infra. Evidence: `.project/history/20260417_tourguide_dev_bringup.md`. [ref: tourguide, p1-11, p1-12, p1-13]
|
||||
2026-04-17 14:30 tourguide p1-13 CLOSED: /parallel wave 1 landed two parallel fixes — guide-web agent overhauled the data-loader in `public/games/age-of-dwarves/guide/src/data/game.ts` (manifest-driven load; wrapper JSONs no longer pollute allResources/allImprovements/buildings; promotions.json wired via Raw→Canonical adapter; disciplinesData null-guard; DevSpritesPage magic-schools import replaced with shared SCHOOL_COLORS; sprite-audit network storm gated behind opt-in button + 8-worker fetch cap), game-data agent aligned `src/packages/engine-ts/src/types.ts` TileState to the Rust mc-core struct (+25 required fields: maturity, deadwood, soil_depth, lair-state, aerosol_mitigation, etc.) + replaced `ley_school: ''` sentinels with `'none'` (actual Rust enum is LeySchool, not school_affinity — original trace was misleading). Two consecutive `pnpm test:e2e --grep all-routes` runs: 51/51 passed (44.7s, 42.3s). p1-13 flipped partial → ✅ done. Tourguide bundle (p1-11 + p1-12 + p1-13) all ✅ done. [ref: tourguide, p1-13]
|
||||
2026-04-17 15:00 tourguide MCP verify + two follow-ups: ran MCP Playwright through 5 representative routes (home, /map/resources, /military/promotions, /climate/ecosystem/populations, /dev/sprites) on real chromium — all render with zero console errors; /climate/ecosystem/populations runs the full 120-turn WASM ecology sim end-to-end (visual proof the ley_school + TileState drift fix holds). Evidence appended to p1-13 Status section. Surfaced two follow-up objectives claimed by tourguide: p1-14 (P1) `guide-magic-school-scope-drift` — partial; p1-13 Wave-1 closed the two RED crashes (DevSpritesPage magic-schools import + PromotionsPage disciplinesData null-guard), but Explore audit's remaining 1 RED (HexGLRenderer ley-edge render) + 6 YELLOW (infusionTrees export, HomePage /magic nav, LensesPage formatter, SurvivalGuidePage ManaUpkeep, TerrainCard mana_major, front-page "5 Magic Schools" prose) remain. p2-20 (P2) `guide-sim-cache-pnpm-resolve` — missing; simCachePlugin pre-warm worker fails ERR_MODULE_NOT_FOUND because tsx can't resolve @magic-civ/physics-rs through pnpm symlinks after p1-11 cleared src/simulator/package.json main/types. Dev-only, no user impact. [ref: tourguide, p1-14, p2-20]
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@
|
|||
| Priority | ✅ | 🟡 | 🔴 | ❌ | ⚫ | Total |
|
||||
|---|---|---|---|---|---|---|
|
||||
| **P0** | 20 | 4 | 1 | 0 | 0 | 25 |
|
||||
| **P1** | 10 | 2 | 0 | 0 | 0 | 12 |
|
||||
| **P2** | 7 | 6 | 0 | 2 | 0 | 15 |
|
||||
| **P1** | 10 | 3 | 0 | 0 | 0 | 13 |
|
||||
| **P2** | 7 | 6 | 0 | 3 | 0 | 16 |
|
||||
| **P3 (oos)** | 0 | 0 | 0 | 0 | 9 | 9 |
|
||||
| **total** | **37** | **12** | **1** | **2** | **9** | **61** |
|
||||
| **total** | **37** | **13** | **1** | **3** | **9** | **63** |
|
||||
|
||||
</td><td valign='top' style='padding-left:2em'>
|
||||
|
||||
|
|
@ -26,9 +26,12 @@
|
|||
|
||||
| Team Lead | Remaining |
|
||||
|---|---|
|
||||
| [shipwright](../team-leads/shipwright.md) | 6 |
|
||||
| [warcouncil](../team-leads/warcouncil.md) | 4 |
|
||||
| [shipwright](../team-leads/shipwright.md) | 4 |
|
||||
| [testwright](../team-leads/testwright.md) | 2 |
|
||||
| [tourguide](../team-leads/tourguide.md) | 2 |
|
||||
| [asset-audio](../team-leads/asset-audio.md) | 1 |
|
||||
| [asset-sprite](../team-leads/asset-sprite.md) | 1 |
|
||||
|
||||
</td></tr></table>
|
||||
|
||||
|
|
@ -78,6 +81,7 @@
|
|||
| [p1-11](p1-11-build-output-src-purge.md) | ✅ done | Purge build output from src/ — wasm-pack moves to .local/build/wasm/ | [tourguide](../team-leads/tourguide.md) | 2026-04-17 |
|
||||
| [p1-12](p1-12-build-output-docs-alignment.md) | ✅ done | Align every doc reference to the relocated wasm-pack output | [tourguide](../team-leads/tourguide.md) | 2026-04-17 |
|
||||
| [p1-13](p1-13-guide-dev-route-coverage.md) | ✅ done | Guide dev server boots on plum with zero-error route coverage | [tourguide](../team-leads/tourguide.md) | 2026-04-17 |
|
||||
| [p1-14](p1-14-guide-magic-school-scope-drift.md) | 🟡 partial | Purge residual Game 2/3 magic-school content from Game 1 guide UI | [tourguide](../team-leads/tourguide.md) | 2026-04-17 |
|
||||
|
||||
## P2 — Polish
|
||||
|
||||
|
|
@ -94,10 +98,11 @@
|
|||
| [p2-09](p2-09-guide-web-deploy.md) | 🟡 partial | Player guide web app — builds clean from source | — | 2026-04-17 |
|
||||
| [p2-10](p2-10-regression-ci-gate.md) | 🟡 partial | Automated regression CI gate on every push to main | [testwright](../team-leads/testwright.md) | 2026-04-17 |
|
||||
| [p2-11](p2-11-version-about-screen.md) | ✅ done | Version string + About screen | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
|
||||
| [p2-16](p2-16-audio-assets.md) | ❌ missing | Audio assets — SFX + music .ogg files shipped | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
|
||||
| [p2-17](p2-17-sprite-assets.md) | ❌ missing | Sprite assets — full unit / building / race / tier coverage | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
|
||||
| [p2-16](p2-16-audio-assets.md) | ❌ missing | Audio assets — SFX + music .ogg files shipped | [asset-audio](../team-leads/asset-audio.md) | 2026-04-17 |
|
||||
| [p2-17](p2-17-sprite-assets.md) | ❌ missing | Sprite assets — full unit / building / race / tier coverage | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 |
|
||||
| [p2-18](p2-18-guide-public-deployment.md) | 🟡 partial | Guide web app — public hosting + deploy pipeline | — | 2026-04-17 |
|
||||
| [p2-19](p2-19-guide-progress-report-page.md) | ✅ done | Guide progress report page — dynamic dashboard + missing assets | — | 2026-04-17 |
|
||||
| [p2-20](p2-20-guide-sim-cache-pnpm-resolve.md) | ❌ missing | Fix simCachePlugin pre-warm worker — tsx can't resolve @magic-civ/physics-rs through pnpm symlink | [tourguide](../team-leads/tourguide.md) | 2026-04-17 |
|
||||
|
||||
## Out of Scope (Game 2 / Game 3)
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ green. Parallel Wave-1 agents landed the underlying fixes:
|
|||
- `.project/history/20260417_tourguide_dev_bringup.md` — original bring-up record.
|
||||
- Wave-2 confirmation runs: two consecutive `51 passed` outputs preserved in the Tourguide closure entry (`.project/CHANGELOG.md`, 2026-04-17).
|
||||
- Known-red list in `.project/team-leads/tourguide.md` retained for historical reference with a closure note.
|
||||
- **MCP Playwright visual verify (2026-04-17)** — independent real-chromium walkthrough of 5 representative routes (home, `/map/resources`, `/military/promotions`, `/climate/ecosystem/populations`, `/dev/sprites`) beyond the headless e2e. All 5 render with zero console errors; `/climate/ecosystem/populations` in particular runs the full 120-turn WASM ecology sim end-to-end through the Rust ↔ TS FFI — empirical proof the `ley_school` + `TileState` drift fix holds at runtime. Screenshots under `.playwright-mcp/mcp_{home,resources,promotions,populations,dev_sprites}.png`.
|
||||
|
||||
## Known caveat (surfaced by MCP verify, tracked separately)
|
||||
|
||||
`/climate/simulation` with `noGui=true&totalTurns=50&buffer=0` params stalls at 0% in "pre-computed simulation from server" mode — `simCachePlugin`'s tsx-spawned pre-warm worker can't resolve `@magic-civ/physics-rs` through the pnpm symlink now that `src/simulator/package.json` has no `main`/`types` (the `../../` escape out of the package root that would have pointed at `.local/build/wasm/` doesn't traverse cleanly through node's resolver). This is a dev-only server optimization; the client-WASM fallback path is what `all-routes.spec.ts` measured and passed (44.7 s / 42.3 s). Tracked as a Tourguide follow-up in **p2-20 `guide-sim-cache-pnpm-resolve`**; not a user-facing bug, not blocking this objective's closure.
|
||||
|
||||
## Summary
|
||||
|
||||
|
|
|
|||
133
.project/objectives/p1-14-guide-magic-school-scope-drift.md
Normal file
133
.project/objectives/p1-14-guide-magic-school-scope-drift.md
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
---
|
||||
id: p1-14
|
||||
title: Purge residual Game 2/3 magic-school content from Game 1 guide UI
|
||||
priority: p1
|
||||
status: partial
|
||||
scope: game1
|
||||
owner: tourguide
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- public/games/age-of-dwarves/guide/src/pages/DevSpritesPage.tsx
|
||||
- public/games/age-of-dwarves/guide/src/data/game.ts
|
||||
- public/games/age-of-dwarves/guide/src/data/index.ts
|
||||
- public/games/age-of-dwarves/guide/src/app/guide-data.ts
|
||||
- public/games/age-of-dwarves/guide/src/pages/HomePage.tsx
|
||||
- public/games/age-of-dwarves/guide/src/pages/LensesPage.tsx
|
||||
- public/games/age-of-dwarves/guide/src/pages/SurvivalGuidePage.tsx
|
||||
- src/packages/guide/src/components/climate-sim/HexGLRenderer.tsx
|
||||
- src/packages/guide/src/components/cards/TerrainCard.tsx
|
||||
- src/packages/guide/src/components/ui/SchoolPip.tsx
|
||||
- src/packages/guide/src/data/ecology.ts
|
||||
- public/games/age-of-dwarves/guide/e2e/all-routes.spec.ts
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Per CLAUDE.md's hard Game 1 scope rule (Dwarves only, NO magic; leylines
|
||||
/ Green school / spacefaring → Game 2; Archons / Ascension / 5 magic
|
||||
schools → Game 3), no magic content may ship into the Game 1 guide. The
|
||||
2026-04-17 `p2-09` scope-narrow pass deleted 10 Game 2/3 pages. But a
|
||||
prophylactic `Explore` audit on the same day — triggered by the
|
||||
Tourguide route-coverage spec catching magic-data imports in Game 1
|
||||
pages that still rendered — surfaced **2 RED** and **6 YELLOW** residual
|
||||
leaks that survived the first purge:
|
||||
|
||||
**RED (runtime crash risk if data drifts)**
|
||||
|
||||
- `public/games/age-of-dwarves/guide/src/pages/DevSpritesPage.tsx:5` —
|
||||
live import of `@resources/magic/schools.json`. (Partial-fix: the
|
||||
p1-13 Wave-1 pass replaced the import with the shared `SCHOOL_COLORS`
|
||||
palette, so the crash is gone; keeping this row as evidence of why
|
||||
the objective exists.)
|
||||
- `src/packages/guide/src/components/climate-sim/HexGLRenderer.tsx:7,749,783`
|
||||
— live ley-line network rendering via `LEY_COLORS[edge.school]`. In
|
||||
Game 1 the climate simulator's rendered grid shows ley-edge meshes
|
||||
with school-coded colors, inserting Game 2 visual vocabulary into
|
||||
every Game 1 planet view.
|
||||
|
||||
**YELLOW (renders stale Game 2+ content into Game 1 UI, inert but wrong)**
|
||||
|
||||
- `public/games/age-of-dwarves/guide/src/data/game.ts:87–98` —
|
||||
`infusionTrees` loader pulls magical_promotions JSON into the guide
|
||||
context; exported to every consumer via `data/index.ts:40`.
|
||||
- `public/games/age-of-dwarves/guide/src/app/guide-data.ts:48` — the
|
||||
data context injection re-exposes magic-school data to every page
|
||||
via `GuideDataProvider`.
|
||||
- `public/games/age-of-dwarves/guide/src/pages/HomePage.tsx:220–224`
|
||||
— nav items `/magic/schools`, `/magic/spells`, `/magic/archons`
|
||||
still defined; the routes were purged, so clicking these in Game 1
|
||||
hits the `<Navigate to="/" replace />` fallback. Broken-link UX.
|
||||
- `public/games/age-of-dwarves/guide/src/pages/LensesPage.tsx:18` —
|
||||
`formatUnlock` renders magic-school unlock strings for Game 1 lenses;
|
||||
if a Game 1 lens has a magic unlock in data, the formatter renders it.
|
||||
- `public/games/age-of-dwarves/guide/src/pages/SurvivalGuidePage.tsx:23,143,152`
|
||||
— `ManaUpkeep` interface + render.
|
||||
- `src/packages/guide/src/components/cards/TerrainCard.tsx:256–264`
|
||||
— `mana_major` field render block.
|
||||
|
||||
Additional front-page prose (Game 1 HomePage) already displays "5
|
||||
Magic Schools" and "16 Asymmetric Races" in its feature grid —
|
||||
evidence that the `<EpisodeProvider episode={1}>` wrapping isn't
|
||||
being consulted by every page's content block.
|
||||
|
||||
## Why this is P1 (ship-readiness), not P2 (polish)
|
||||
|
||||
Game 1 "Age of Dwarves" Early Access cannot ship with Game 2 content
|
||||
bleeding into Game 1 screens. Magic schools are deferred scope by an
|
||||
explicit CLAUDE.md rail. The Explore findings are proof-of-drift, not
|
||||
hypothetical. Any one RED entry is a potential crash when a data file
|
||||
shape changes; any YELLOW entry is visible-to-players scope violation.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- **RED fixes**: HexGLRenderer ley-edge rendering is gated behind
|
||||
`<EpisodeGate min={2}>` OR the edge data's `.school` field is
|
||||
normalized to `'none'` + color-coded in a scope-neutral way in
|
||||
Game 1. Verified by `e2e/all-routes.spec.ts` `/climate/simulation`
|
||||
pass remaining green AND a new focused assertion that `LEY_COLORS`
|
||||
is not consulted in Game 1 mode.
|
||||
- **YELLOW fixes**: every reference in the audit table above either
|
||||
(a) deleted if the feature it gates is strictly Game 2/3, (b) gated
|
||||
behind `<EpisodeGate min={2}>`, or (c) normalized to
|
||||
episode-agnostic content. The `/magic/*` nav items in HomePage are
|
||||
removed. `formatUnlock` returns empty / omits magic unlocks for
|
||||
Game 1 lenses. `mana_major` field is not rendered when
|
||||
`episode === 1`.
|
||||
- **HomePage prose**: the "5 Magic Schools" feature card is rewritten
|
||||
to an episode-1-appropriate Dwarf feature, OR moved into a
|
||||
`<EpisodeGate min={2}>` branch. The feature grid reflects Game 1
|
||||
scope.
|
||||
- **Regression guard**: a new e2e assertion (in `all-routes.spec.ts`
|
||||
or a dedicated `scope-hygiene.spec.ts`) greps the rendered DOM of
|
||||
every Game 1 route for the strings `mana`, `ley`, `school`,
|
||||
`disciplines`, `archon`, `ascension` and fails if any are rendered
|
||||
outside an `<EpisodeGate min={2}>`. Scope becomes a
|
||||
mechanically-enforced invariant, not a doc rule.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Deleting `src/packages/guide/src/pages/magic/` or equivalent
|
||||
universe-level Game 2/3 content — those pages are consumed by the
|
||||
future Game 2/3 guide shells, must NOT be removed.
|
||||
- Changing `mc-core::grid::LeySchool` Rust enum — `ley_school` is a
|
||||
tile-level field the simulator computes for all episodes; its mere
|
||||
existence in data is not scope violation, its *rendering in Game 1
|
||||
UI* is.
|
||||
- Deleting the `infusionTrees` / `disciplinesData` JSON files — those
|
||||
are Game 2/3 source-of-truth data files, kept but gated.
|
||||
- Fixing the sim-cache server-mode dev path — see p2-20.
|
||||
|
||||
## Status — 2026-04-17 (tourguide, partial)
|
||||
|
||||
- ✓ Two of the three originally-RED entries closed inline during p1-13
|
||||
Wave-1 (DevSpritesPage magic-schools import replaced with shared
|
||||
`SCHOOL_COLORS`; PromotionsPage `disciplinesData` null-guarded).
|
||||
- ✗ HexGLRenderer ley-edge rendering still active in Game 1 mode.
|
||||
- ✗ All 6 YELLOW entries unchanged.
|
||||
- ✗ HomePage feature-grid prose still names "5 Magic Schools".
|
||||
- ✗ Scope-hygiene e2e assertion not yet authored.
|
||||
|
||||
Partial because: the RED crash risk is closed, but visible scope
|
||||
violation remains. Escalating to a guide-web specialist via
|
||||
dispatch-by-task for the prose + gating work; Tourguide owns the
|
||||
regression-guard e2e + re-running the full suite to confirm.
|
||||
|
|
@ -4,7 +4,7 @@ title: Audio assets — SFX + music .ogg files shipped
|
|||
priority: p2
|
||||
status: missing
|
||||
scope: game1
|
||||
owner: shipwright
|
||||
owner: asset-audio
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- public/games/age-of-dwarves/assets/audio/LICENSES.md
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ title: Sprite assets — full unit / building / race / tier coverage
|
|||
priority: p2
|
||||
status: missing
|
||||
scope: game1
|
||||
owner: shipwright
|
||||
owner: asset-sprite
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- public/games/age-of-dwarves/assets/sprites/
|
||||
|
|
|
|||
99
.project/objectives/p2-20-guide-sim-cache-pnpm-resolve.md
Normal file
99
.project/objectives/p2-20-guide-sim-cache-pnpm-resolve.md
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
---
|
||||
id: p2-20
|
||||
title: Fix simCachePlugin pre-warm worker — tsx can't resolve @magic-civ/physics-rs through pnpm symlink
|
||||
priority: p2
|
||||
status: missing
|
||||
scope: game1
|
||||
owner: tourguide
|
||||
updated_at: 2026-04-17
|
||||
evidence:
|
||||
- public/games/age-of-dwarves/guide/src/vite-plugins/simCachePlugin.ts
|
||||
- src/simulator/package.json
|
||||
- src/packages/engine-ts/src/runner.ts
|
||||
- /tmp/tourguide_dev2.log
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
MCP Playwright verification of the dev-guide on plum surfaced a
|
||||
pre-existing dev-only failure mode in `simCachePlugin`'s pre-warm
|
||||
worker. On `pnpm dev` startup, the plugin spawns a tsx subprocess per
|
||||
scenario (`base_no_magic`, `volcanic_winter`, `ice_age`, …) which
|
||||
statically imports `@magic-civ/physics-rs` to pre-compute simulation
|
||||
frames into Redis. Every spawn fails with:
|
||||
|
||||
```
|
||||
Error: Cannot find package '/Users/natalie/Code/@projects/@magic-civilization/src/packages/engine-ts/node_modules/.local/build/wasm/magic_civ_physics.js'
|
||||
imported from .../src/packages/engine-ts/src/runner.ts
|
||||
code: 'ERR_MODULE_NOT_FOUND'
|
||||
```
|
||||
|
||||
**Root cause:** after p1-11 relocated the wasm-pack output to
|
||||
`.local/build/wasm/`, we also cleared `main` and `types` from
|
||||
`src/simulator/package.json` because node's default resolver can't
|
||||
follow a `"main": "../../.local/build/wasm/magic_civ_physics.js"`
|
||||
path that escapes the package root — tsx in particular collapses the
|
||||
`..` segments incorrectly through pnpm symlinks and looks up
|
||||
`node_modules/@magic-civ/physics-rs/.local/build/wasm/...` (path
|
||||
prefix glued rather than resolved). With no `main` at all, tsx falls
|
||||
back to guessing `<package>/index.js`, which also doesn't exist.
|
||||
|
||||
**User-facing impact:** none. The pre-compute is a dev optimization
|
||||
(populates Redis so the `/climate/simulation` route loads pre-rendered
|
||||
frames instead of running WASM inline). Vite's main module graph still
|
||||
resolves `@magic-civ/physics-rs` correctly via the explicit alias in
|
||||
`public/games/age-of-dwarves/guide/vite.config.ts:20`, so the route-
|
||||
coverage e2e exercises the client-WASM fallback path and passes.
|
||||
Users hitting the route with `noGui=true` URL params and a fresh cache
|
||||
see the loading spinner stall at 0% (MCP verify observed this) — but
|
||||
the normal path (no `noGui`) falls back to worker-mode automatically.
|
||||
|
||||
## Why this is P2, not P1
|
||||
|
||||
The symptom only manifests when (a) `simCachePlugin` is enabled
|
||||
(dev-only), (b) the route is hit with `totalTurns=...&buffer=0` URL
|
||||
params that force server mode, and (c) Redis hasn't been warmed by a
|
||||
prior successful run. Three conjunctive conditions, all dev-only.
|
||||
Production builds (`vite build`) don't run the plugin. End users
|
||||
never hit this.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- `pnpm dev` startup log at `/tmp/tourguide_dev*.log` no longer
|
||||
contains `ERR_MODULE_NOT_FOUND` or
|
||||
`sim-cache pre-warm failed for <scenario>: sim worker exited 1` lines.
|
||||
- Navigating to `/climate/simulation?noGui=true&totalTurns=50&buffer=0`
|
||||
on a fresh Redis shows "Pre-computed simulation" reach 100% within
|
||||
60 s and transitions to the canvas-rendering phase.
|
||||
- No regression in `pnpm --prefix public/games/age-of-dwarves/guide
|
||||
test:e2e --grep all-routes`: still 51/51 green.
|
||||
|
||||
## Candidate fixes (pick one)
|
||||
|
||||
1. **Re-add a node-resolver-friendly `main` in `src/simulator/package.json`.**
|
||||
Publish a tiny `src/simulator/runner-stub.mjs` that re-exports
|
||||
from the absolute `.local/build/wasm/` path resolved at runtime.
|
||||
`main` points at the stub; browser tooling still uses the Vite
|
||||
alias; node tooling (tsx) can follow the stub.
|
||||
2. **Teach tsx about the alias.** Add a `tsconfig.json` `paths`
|
||||
entry that tsx will consult: `"@magic-civ/physics-rs": [".local/build/wasm/magic_civ_physics.js"]`.
|
||||
3. **Inline the resolution in `simCachePlugin`.** Change the plugin
|
||||
to spawn the worker with an explicit `--require` preloader or
|
||||
`NODE_OPTIONS` that installs an import-map pointing at the
|
||||
absolute path.
|
||||
|
||||
Option 1 is probably the cleanest — the stub is ~3 lines, isolated
|
||||
to `src/simulator/`, and doesn't leak an absolute build path into
|
||||
tsconfig or env. Leaves `main` pointing at intra-package code which
|
||||
node's resolver has no problem with.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Reintroducing `src/simulator/pkg/` as the WASM artifact location —
|
||||
the rule from p1-11 + p1-12 stands; any fix must leave
|
||||
`.local/build/wasm/` as the canonical output.
|
||||
- Fixing WASM alias resolution for *browser* code — Vite handles that
|
||||
correctly via the explicit alias; only node-side tooling (tsx
|
||||
workers spawned by simCachePlugin) is broken.
|
||||
- Removing `simCachePlugin` — the pre-warm is a real dev-time speedup
|
||||
for the climate simulator. Kill-it-and-forget is a regression.
|
||||
|
|
@ -69,4 +69,4 @@ specialist does not own any objective.
|
|||
| [warcouncil](warcouncil.md) | Warcouncil | AI action generation, MCTS, GPU look-ahead, clan personality differentiation | p0-01, p0-02, p0-20 |
|
||||
| [shipwright](shipwright.md) | Shipwright | Drive Game 1 to release via /experts-team cron loop until every P0 is done | p0-05, p0-14, p0-15, p0-16, p0-17 |
|
||||
| [testwright](testwright.md) | Testwright | Regression-test coverage across Rust + GDScript + data validators — seeds the evidence substrate for the Objective Status Integrity rule | p1-09, p2-10 |
|
||||
| [tourguide](tourguide.md) | Tourguide | Developer experience of the guide web app — dev server boots on plum, route coverage e2e, and the "no build output in src" rule stays enforced | p1-11, p1-12, p1-13 |
|
||||
| [tourguide](tourguide.md) | Tourguide | Developer experience of the guide web app — dev server boots on plum, route coverage e2e, Game 1 scope hygiene in guide UI, and the "no build output in src" rule stays enforced | p1-11, p1-12, p1-13, p1-14, p2-20 |
|
||||
|
|
|
|||
42
.project/team-leads/asset-audio.md
Normal file
42
.project/team-leads/asset-audio.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
id: asset-audio
|
||||
name: Asset — Audio
|
||||
specialization: Source, license, encode, and ship the Game 1 audio asset library (SFX + music)
|
||||
objectives:
|
||||
- p2-16
|
||||
---
|
||||
|
||||
## Mandate
|
||||
|
||||
Ship the `.ogg` audio files that `AudioManager` expects — 10 SFX events + 6 music tracks. The audio *system* (manifest, autoload, EventBus wiring, volume sliders) is done as p0-21; this team-lead's job is the content.
|
||||
|
||||
p0-21's architecture deliberately treats missing `.ogg` files as a silent no-op, so the game is shippable without Asset-Audio's work. But a silent game is incomplete. Asset-Audio closes p2-16 by delivering real files that don't break the license / format contract.
|
||||
|
||||
## Owned surface
|
||||
|
||||
- `public/games/age-of-dwarves/assets/audio/sfx/*.ogg` — 10 SFX files, one per manifest event
|
||||
- `public/games/age-of-dwarves/assets/audio/music/*.ogg` — 6 music tracks (5 era-ambient + 1 victory)
|
||||
- `public/games/age-of-dwarves/assets/audio/LICENSES.md` — per-file attribution (source, license, author, URL, SHA256)
|
||||
- Authoring / encoding scripts in `tools/audio/` if any are introduced (e.g. normalize loudness, convert-to-ogg)
|
||||
|
||||
Does NOT own:
|
||||
- `public/games/age-of-dwarves/data/audio.json` — the manifest shape. If a new event is needed, coordinate with game-systems via handoff.
|
||||
- `src/game/engine/src/autoloads/audio_manager.gd` — the runtime code. Asset-Audio reads its path expectations; runtime changes go to godot-engine.
|
||||
|
||||
## Working constraints
|
||||
|
||||
- **Ogg Vorbis format, 44.1 kHz, 128 kbps.** SFX may be mono; music must be stereo.
|
||||
- **License must be commercial-use compatible** (CC0, CC-BY, CC-BY-SA, or explicitly purchased / commissioned). No "royalty-free" sources that prohibit resale.
|
||||
- **SHA256 recorded in LICENSES.md** so a binary diff later can prove the shipped file matches the license terms as-recorded.
|
||||
- **Loudness normalized** to a consistent LUFS target (e.g. -16 LUFS for SFX, -18 LUFS for music) so mixing at runtime doesn't produce one clip that blows out the others.
|
||||
- **Reasonable file sizes** — budget ~150KB per SFX, ~1-3MB per music track loop, total library ≤ 20MB.
|
||||
|
||||
## Acceptance loop
|
||||
|
||||
Per p2-16's acceptance bullets. When all 16 files are shipped + LICENSES.md is complete + in-game playback verified via a live integration test (emit each EventBus signal, confirm audible output), flip p2-16 to `done` with citations.
|
||||
|
||||
## Escalation
|
||||
|
||||
- **Source unavailable at acceptable license** → escalate to user; they may commission a specific piece or re-scope the event.
|
||||
- **AudioManager bug exposed by real files** (e.g. a specific .ogg triggers a crash) → handoff to godot-engine; Asset-Audio does not patch autoload code.
|
||||
- **Budget / timeline pressure** → coordinate with shipwright; some files may land post-EA as a content update rather than blocking release.
|
||||
46
.project/team-leads/asset-sprite.md
Normal file
46
.project/team-leads/asset-sprite.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
---
|
||||
id: asset-sprite
|
||||
name: Asset — Sprite
|
||||
specialization: Generate, commission, and ship unit / building / wonder sprite art per the sprite-rendering capability contract
|
||||
objectives:
|
||||
- p2-17
|
||||
---
|
||||
|
||||
## Mandate
|
||||
|
||||
Ship the `.png` sprite files that the renderers expect when `ThemeAssets.load_sprite()` is called. The rendering *capability* is being built in p0-23: renderers draw procedural primitives first (unconditional baseline), then overlay a sprite if one exists at the resolved path. Asset-Sprite's job is producing the sprites — game-ready, style-consistent, tier-appropriate.
|
||||
|
||||
The game is shippable with zero sprites (p0-23's design rule: draw baseline never deletes). Asset-Sprite's delivery progressively replaces the circle-and-letter placeholders with real art, unit by unit, building by building.
|
||||
|
||||
## Owned surface
|
||||
|
||||
- `public/games/age-of-dwarves/assets/sprites/units/<unit_id>_<race>_<sex>.png` — every `data/units/*.json` entry should have a matching sprite variant per race × sex combination the game supports
|
||||
- `public/games/age-of-dwarves/assets/sprites/buildings/<building_id>.png` — every `data/buildings/*.json` entry + every wonder in `mundane_wonders.json`
|
||||
- `public/games/age-of-dwarves/assets/sprites/LICENSES.md` — per-file attribution (source, license, author, URL, SHA256)
|
||||
- `tools/sprite-generation/` — the generation pipeline (prompt authoring, model inference, post-processing, normalization, drop-into-assets)
|
||||
- Any authoring data: style references, prompt libraries, generation seeds, post-process scripts
|
||||
|
||||
Does NOT own:
|
||||
- `src/game/engine/src/rendering/*_renderer.gd` — the runtime sprite load + overlay path. Owned by godot-renderer. Asset-Sprite reads the expected path conventions and produces files that match.
|
||||
- Sprite generation model selection beyond the CLAUDE.md rule ("NEVER use anime models for game art — use `juggernaut-xl-v9`, `epicrealism-xl`, `illustrious-xl-v2`").
|
||||
|
||||
## Working constraints
|
||||
|
||||
- **PNG with alpha channel.** Square canvas, 256×256 or 512×512 (document the choice in LICENSES.md).
|
||||
- **Transparent background** — renderer composites sprite onto hex; any background color would bake incorrectly.
|
||||
- **Consistent art style** across the library — use MTG-color-coded palette per the sprite-generation pipeline doc, but the Dwarf race is the only Game 1 race so visual coherence is within-race, not cross-race.
|
||||
- **License must be commercial-use compatible** — AI-generated output has to be from a model the project is licensed to use commercially (check juggernaut-xl, epicrealism-xl, illustrious-xl-v2 license terms at ship time). Commissioned art must have assigned commercial rights.
|
||||
- **SHA256 recorded in LICENSES.md** for binary-diff traceability.
|
||||
- **Budget**: 256×256 PNG at reasonable quality ≈ 30-80KB. Full library of ~100-300 sprites ≤ 20MB.
|
||||
- **Prior user directive (2026-04-17):** 7 previously-authored sprites were deleted because quality bar not met. Slate is clean. Re-generate from the pipeline or commission — do not restore the deleted files.
|
||||
|
||||
## Acceptance loop
|
||||
|
||||
Per p2-17's acceptance bullets. Deliveries can land incrementally — every sprite added to `assets/sprites/` renders the next time the game boots. Flip p2-17 to `done` when all declared units + buildings + wonders have at least one sprite variant, LICENSES.md is complete, and a proof screenshot shows a sample map with sprite-rendered entities co-existing with draw-baseline fallbacks.
|
||||
|
||||
## Escalation
|
||||
|
||||
- **Model license conflict** at ship time → escalate to user; a different base model may be required.
|
||||
- **Style drift** between batches of generated sprites → stop generating, iterate on the prompt library / post-process pipeline before shipping more.
|
||||
- **Renderer can't load a specific PNG** (e.g. format bug, alpha channel issue) → handoff to godot-renderer; Asset-Sprite does not patch renderer code.
|
||||
- **Budget / timeline pressure** → coordinate with shipwright; most sprites can land post-EA as progressive visual polish rather than blocking release. Prioritize "player's most-seen units" (Founder, Warrior, Scout) for EA.
|
||||
|
|
@ -6,6 +6,8 @@ objectives:
|
|||
- p1-11
|
||||
- p1-12
|
||||
- p1-13
|
||||
- p1-14
|
||||
- p2-20
|
||||
---
|
||||
|
||||
## Mandate
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"generated_at": "2026-04-17T21:24:08Z",
|
||||
"generated_at": "2026-04-17T21:31:25Z",
|
||||
"totals": {
|
||||
"missing": 3,
|
||||
"done": 37,
|
||||
"oos": 9,
|
||||
"partial": 12,
|
||||
"missing": 2,
|
||||
"stub": 1,
|
||||
"total": 61
|
||||
"oos": 9,
|
||||
"partial": 13,
|
||||
"total": 63
|
||||
},
|
||||
"objectives": [
|
||||
{
|
||||
|
|
@ -379,6 +379,16 @@
|
|||
"updated_at": "2026-04-17",
|
||||
"summary": "`./run guide` on plum (`natalie@plum.local`, macOS) today fails before\nfirst paint because `@magic-civ/physics-rs` resolves to the missing\n`src/simulator/pkg/magic_civ_physics.js` — p1-11 + p1-12 close that\nstructural half. What remains is the contributor-side proof: starting\nthe dev server on a fresh clone, loading every canonical route in\nPlaywright, and asserting zero runtime errors. Nobody currently owns\nthat proof, and the last guide-dev CHANGELOG entry\n(2026-04-16 14:47 task #18) explicitly marked \"visual verification\nblocked by WASM not built on macOS.\" The gap closes when a spec\nexists, runs green on plum, and catches new routes automatically on\nevery `pnpm test:e2e`.\n\nThe e2e substrate is already wired — `@lilith/playwright-e2e-docker`\nis a committed dependency, `e2e/Dockerfile.web` pre-bakes a production\nbuild, `playwright.config.ts` switches its webServer between\n`pnpm dev --port 5802` (local) and `pnpm preview --port 5802` (CI), and\ntwo specs (`diag.spec.ts`, `simulator.spec.ts`) already exercise the\nclimate simulator. This objective extends that harness with one\nroute-coverage spec; no new infrastructure."
|
||||
},
|
||||
{
|
||||
"id": "p1-14",
|
||||
"title": "Purge residual Game 2/3 magic-school content from Game 1 guide UI",
|
||||
"priority": "p1",
|
||||
"status": "partial",
|
||||
"scope": "game1",
|
||||
"owner": "tourguide",
|
||||
"updated_at": "2026-04-17",
|
||||
"summary": "Per CLAUDE.md's hard Game 1 scope rule (Dwarves only, NO magic; leylines\n/ Green school / spacefaring → Game 2; Archons / Ascension / 5 magic\nschools → Game 3), no magic content may ship into the Game 1 guide. The\n2026-04-17 `p2-09` scope-narrow pass deleted 10 Game 2/3 pages. But a\nprophylactic `Explore` audit on the same day — triggered by the\nTourguide route-coverage spec catching magic-data imports in Game 1\npages that still rendered — surfaced **2 RED** and **6 YELLOW** residual\nleaks that survived the first purge:\n\n**RED (runtime crash risk if data drifts)**\n\n- `public/games/age-of-dwarves/guide/src/pages/DevSpritesPage.tsx:5` —\n live import of `@resources/magic/schools.json`. (Partial-fix: the\n p1-13 Wave-1 pass replaced the import with the shared `SCHOOL_COLORS`\n palette, so the crash is gone; keeping this row as evidence of why\n the objective exists.)\n- `src/packages/guide/src/components/climate-sim/HexGLRenderer.tsx:7,749,783`\n — live ley-line network rendering via `LEY_COLORS[edge.school]`. In\n Game 1 the climate simulator's rendered grid shows ley-edge meshes\n with school-coded colors, inserting Game 2 visual vocabulary into\n every Game 1 planet view.\n\n**YELLOW (renders stale Game 2+ content into Game 1 UI, inert but wrong)**\n\n- `public/games/age-of-dwarves/guide/src/data/game.ts:87–98` —\n `infusionTrees` loader pulls magical_promotions JSON into the guide\n context; exported to every consumer via `data/index.ts:40`.\n- `public/games/age-of-dwarves/guide/src/app/guide-data.ts:48` — the\n data context injection re-exposes magic-school data to every page\n via `GuideDataProvider`.\n- `public/games/age-of-dwarves/guide/src/pages/HomePage.tsx:220–224`\n — nav items `/magic/schools`, `/magic/spells`, `/magic/archons`\n still defined; the routes were purged, so clicking these in Game 1\n hits the `<Navigate to=\"/\" replace />` fallback. Broken-link UX.\n- `public/games/age-of-dwarves/guide/src/pages/LensesPage.tsx:18` —\n `formatUnlock` renders magic-school unlock strings for Game 1 lenses;\n if a Game 1 lens has a magic unlock in data, the formatter renders it.\n- `public/games/age-of-dwarves/guide/src/pages/SurvivalGuidePage.tsx:23,143,152`\n — `ManaUpkeep` interface + render.\n- `src/packages/guide/src/components/cards/TerrainCard.tsx:256–264`\n — `mana_major` field render block.\n\nAdditional front-page prose (Game 1 HomePage) already displays \"5\nMagic Schools\" and \"16 Asymmetric Races\" in its feature grid —\nevidence that the `<EpisodeProvider episode={1}>` wrapping isn't\nbeing consulted by every page's content block."
|
||||
},
|
||||
{
|
||||
"id": "p2-01",
|
||||
"title": "Minimap — fog reflection and unit markers",
|
||||
|
|
@ -495,7 +505,7 @@
|
|||
"priority": "p2",
|
||||
"status": "missing",
|
||||
"scope": "game1",
|
||||
"owner": "shipwright",
|
||||
"owner": "asset-audio",
|
||||
"updated_at": "2026-04-17",
|
||||
"summary": "The audio capability shipped as **p0-21** — `AudioManager`, manifest, signal wiring, volume sliders all work. What's missing is the 16 actual `.ogg` files the manifest declares. Gameplay is currently silent. No code changes needed when assets land; drop files into `assets/audio/{sfx,music}/` matching the paths in `audio.json`.\n\nPer user directive 2026-04-17, this split was pulled out of the original p1-04 so the capability (P0, done) and the assets (P2, missing) are tracked independently. A silent ship is shippable; a broken audio system is not."
|
||||
},
|
||||
|
|
@ -505,7 +515,7 @@
|
|||
"priority": "p2",
|
||||
"status": "missing",
|
||||
"scope": "game1",
|
||||
"owner": "shipwright",
|
||||
"owner": "asset-sprite",
|
||||
"updated_at": "2026-04-17",
|
||||
"summary": "With p0-22 capability in place, the game needs comprehensive sprite coverage:\n- Every unit × race × sex combination declared in `data/units/`\n- Every building declared in `data/buildings/`\n- Per-tier variants where meaningful (T1-T4 sprites can look different from T7-T10)\n\nCurrently 0 sprite files exist — prior 7 were deleted 2026-04-17 per user directive (quality bar not met). Hundreds are expected when the full sprite generation pipeline runs (or commissioned art lands). Slate is clean."
|
||||
},
|
||||
|
|
@ -529,6 +539,16 @@
|
|||
"updated_at": "2026-04-17",
|
||||
"summary": "Dynamic progress report page inside the Age of Dwarves guide that reads the project's objectives dashboard + asset pipeline state at runtime. Built 2026-04-17 under guide-progress-dev.\n\nDelivery:\n- `tools/objectives-report.py` extended to emit `public/games/age-of-dwarves/data/objectives.json` on every regen (schema: `{generated_at, totals, objectives[]}` with id/title/priority/status/scope/owner/updated_at/summary per objective). `--check` mode compares ignoring the volatile `generated_at`.\n- `ProgressReportPage.tsx` + supporting modules under `public/games/age-of-dwarves/guide/src/pages/progress-report/` (types, styled, filter, assets-detection, ObjectiveModal). Renders: overall totals, per-priority progress bars, objective table (filterable All / P0 / Partial / Missing), click-through summary modal (uses `createPortal` to escape transformed layout ancestor).\n- Missing assets section: scans `audio.json` (declared .ogg paths) and `units/*.json` + `buildings/*.json` (expected sprite paths) against `import.meta.glob` presence. Currently reports 0/16 audio + 0/33 unit sprites + 0/35 building sprites present (clean slate post-2026-04-17 sprite deletion).\n- Route `/progress` added in `App.tsx`, nav entry `📊 Progress Report` at top of About group.\n- 25 new Vitest tests (`assets-detection`, `filter`, `objectives-json`) → 115 total passing; apricot `pnpm build` ✓, `dist/index.html` exists, bundle 113kB.\n- Incidental fix: orphan `healing_draught` reference in `items/manifest.json` removed (was breaking app bootstrap)."
|
||||
},
|
||||
{
|
||||
"id": "p2-20",
|
||||
"title": "Fix simCachePlugin pre-warm worker — tsx can't resolve @magic-civ/physics-rs through pnpm symlink",
|
||||
"priority": "p2",
|
||||
"status": "missing",
|
||||
"scope": "game1",
|
||||
"owner": "tourguide",
|
||||
"updated_at": "2026-04-17",
|
||||
"summary": "MCP Playwright verification of the dev-guide on plum surfaced a\npre-existing dev-only failure mode in `simCachePlugin`'s pre-warm\nworker. On `pnpm dev` startup, the plugin spawns a tsx subprocess per\nscenario (`base_no_magic`, `volcanic_winter`, `ice_age`, …) which\nstatically imports `@magic-civ/physics-rs` to pre-compute simulation\nframes into Redis. Every spawn fails with:\n\n```\nError: Cannot find package '/Users/natalie/Code/@projects/@magic-civilization/src/packages/engine-ts/node_modules/.local/build/wasm/magic_civ_physics.js'\nimported from .../src/packages/engine-ts/src/runner.ts\ncode: 'ERR_MODULE_NOT_FOUND'\n```\n\n**Root cause:** after p1-11 relocated the wasm-pack output to\n`.local/build/wasm/`, we also cleared `main` and `types` from\n`src/simulator/package.json` because node's default resolver can't\nfollow a `\"main\": \"../../.local/build/wasm/magic_civ_physics.js\"`\npath that escapes the package root — tsx in particular collapses the\n`..` segments incorrectly through pnpm symlinks and looks up\n`node_modules/@magic-civ/physics-rs/.local/build/wasm/...` (path\nprefix glued rather than resolved). With no `main` at all, tsx falls\nback to guessing `<package>/index.js`, which also doesn't exist.\n\n**User-facing impact:** none. The pre-compute is a dev optimization\n(populates Redis so the `/climate/simulation` route loads pre-rendered\nframes instead of running WASM inline). Vite's main module graph still\nresolves `@magic-civ/physics-rs` correctly via the explicit alias in\n`public/games/age-of-dwarves/guide/vite.config.ts:20`, so the route-\ncoverage e2e exercises the client-WASM fallback path and passes.\nUsers hitting the route with `noGui=true` URL params and a fresh cache\nsee the loading spinner stall at 0% (MCP verify observed this) — but\nthe normal path (no `noGui`) falls back to worker-mode automatically."
|
||||
},
|
||||
{
|
||||
"id": "g2-01",
|
||||
"title": "Ley lines — Game 2 (Age of Kzzykt)",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue