feat(@projects): update web guide deployment status

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-04-17 12:40:57 -07:00
parent ad4fb44390
commit ca9be19ece
8 changed files with 150 additions and 21 deletions

View file

@ -10,12 +10,12 @@
| Status | Count |
|---|---|
| ✅ done | 32 |
| 🟡 partial | 10 |
| ✅ done | 33 |
| 🟡 partial | 11 |
| 🔴 stub | 0 |
| ❌ missing | 2 |
| ⚫ oos | 4 |
| **total** | **48** |
| **total** | **50** |
## P0 — Blockers for "completely playable"
@ -70,11 +70,13 @@
| [p2-06](p2-06-export-pipeline.md) | 🟡 partial | Export pipeline for Windows / macOS / Linux | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
| [p2-07](p2-07-credits-screen.md) | ✅ done | Credits screen accessible from main menu | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
| [p2-08](p2-08-accessibility.md) | ✅ done | Accessibility baseline — colorblind palette + keyboard navigation | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
| [p2-09](p2-09-guide-web-deploy.md) | 🟡 partial | Player guide web app — deployed and up to date | [shipwright](../team-leads/shipwright.md) | 2026-04-17 |
| [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-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 |
## Out of Scope (Game 2)

View file

@ -1,10 +1,10 @@
---
id: p2-09
title: Player guide web app — deployed and up to date
title: Player guide web app — builds clean from source
priority: p2
status: partial
scope: game1
owner: shipwright
owner:
updated_at: 2026-04-17
evidence:
- public/games/age-of-dwarves/guide/
@ -32,6 +32,10 @@ acceptance_audit:
data_driven_content: "✓ — the guide reads data via `import.meta.glob('../../../games/age-of-dwarves/data/*.json')` per guide CLAUDE.md convention. Architecture unchanged. Changing a deposit JSON propagates on the next `pnpm build`."
---
## Ownership note (2026-04-17)
Shipwright released this objective per user directive. Guide-web surface is out of Shipwright's scope going forward. A separate agent will pick this up; `owner:` reset to unclaimed. Prior work (guide-drift-dev2 scope narrowing + guide-progress-dev progress-report page + Progress Report page) remains in-repo.
## Summary
Guide React app (Vite + TypeScript + React 19) lives under `public/games/age-of-dwarves/guide/`. WASM climate worker shares Rust crates with the game.
@ -66,10 +70,11 @@ should yield a clean `dist/index.html` in one step. The external-hosting decisio
## Acceptance
- `pnpm --filter guide-age-of-dwarves build` produces a static bundle with zero TypeScript errors.
- Bundle deployed to a public URL (GitHub Pages or equivalent) so marketing / Steam page can link it.
- Fix the `@/game.json` import at `guide-data.ts` so builds don't regress.
- Guide content stays data-driven — changing a deposit's JSON automatically updates the Resources page on next build.
- 🟡 `pnpm --filter guide-age-of-dwarves build` produces a static bundle with zero TypeScript errors — typecheck is 0 errors across both packages; vite transforms 3339 modules; final rollup step blocked by missing WASM pkg (apricot-build artifact) AND a new `GuideLayout` rollup variable-trace error post-drift-fix.
- ✓ Fix the `@/game.json` import at `guide-data.ts` so builds don't regress — landed.
- ✓ Guide content stays data-driven — changing a deposit's JSON automatically updates the Resources page on next build — architecture unchanged via `import.meta.glob`.
**Split note:** public-URL deployment moved to its own objective p2-18 (was previously bundled here). Progress-report page moved to p2-19. This objective now focuses purely on "builds clean from source".
## Non-goals

View file

@ -0,0 +1,37 @@
---
id: p2-18
title: Guide web app — public hosting + deploy pipeline
priority: p2
status: partial
scope: game1
owner:
updated_at: 2026-04-17
evidence:
- tools/deploy-guide.sh
---
## Ownership note (2026-04-17)
Split out from p2-09 per user directive. Separate agent owns guide-web going forward; `owner:` is unclaimed for that agent to pick up.
## Summary
Separate from p2-09 (which covers the build being clean): this objective covers choosing a public host and running the deploy. Currently the deploy script is ready (`tools/deploy-guide.sh` — modes `build` / `serve` / `apricot` / `zip`), but no public host has been committed for Early Access. The `apricot` mode ships dist/ to the LAN for preview; `zip` produces a handoff artifact that any external host can consume.
## Acceptance
- ✗ Public hosting target chosen and documented in this file (options: GitHub Pages, Cloudflare Pages, Netlify, S3+CloudFront, self-hosted static).
- ✗ Deploy script mode added for the chosen host (extend `tools/deploy-guide.sh` with e.g. `deploy-guide.sh github-pages <version>`).
- ✗ First deploy lands at the public URL; guide is reachable externally.
- ✗ URL recorded in CHANGELOG + player-facing docs (Steam page / README / marketing site).
- ✓ `tools/deploy-guide.sh` exists with build/serve/apricot/zip modes — shipped by export-ci-dev 2026-04-17.
## Depends on
- `p2-09` — guide must build cleanly (currently blocked on WASM rebuild + still-pending rollup fix).
## Non-goals
- CDN / caching policy beyond what the chosen host provides by default.
- Versioned URL history (e.g. `/v0.1.0/`, `/v0.1.1/`).
- Analytics integration.

View file

@ -0,0 +1,45 @@
---
id: p2-19
title: Guide progress report page — dynamic dashboard + missing assets
priority: p2
status: done
scope: game1
owner:
updated_at: 2026-04-17
evidence:
- public/games/age-of-dwarves/guide/src/pages/ProgressReportPage.tsx
- public/games/age-of-dwarves/guide/src/pages/progress-report/
- public/games/age-of-dwarves/guide/src/pages/progress-report/__tests__/
- public/games/age-of-dwarves/data/objectives.json
- tools/objectives-report.py
---
## Ownership note (2026-04-17)
Split out from p2-09 per user directive. Guide-web surface is owned by a separate agent going forward; Shipwright is releasing this. Work here is already shipped — `owner:` reset so the new guide-agent can claim as they see fit.
## 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.
Delivery:
- `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`.
- `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).
- 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).
- Route `/progress` added in `App.tsx`, nav entry `📊 Progress Report` at top of About group.
- 25 new Vitest tests (`assets-detection`, `filter`, `objectives-json`) → 115 total passing; apricot `pnpm build` ✓, `dist/index.html` exists, bundle 113kB.
- Incidental fix: orphan `healing_draught` reference in `items/manifest.json` removed (was breaking app bootstrap).
## Acceptance
- ✓ `tools/objectives-report.py` emits `public/games/age-of-dwarves/data/objectives.json` with correct schema + counts — verified by `objectives-json.test.ts`.
- ✓ `/progress` route renders totals, progress bars, filter toggles, modal — verified via Playwright screenshot at `.playwright-mcp/magic_civ_progress_report_v2.png`.
- ✓ Missing-assets detection live — scans audio.json + units/buildings JSON against glob; renders ✓/✗ per expected path. Tests in `assets-detection.test.ts`.
- ✓ Route + nav wired — `/progress` in App.tsx + lazy-page in `lazy-pages.ts` + nav entry in `nav.tsx`.
- ✓ All tests pass + apricot build produces dist/ — 115/115 vitest, build 10.87s, 0 TS errors.
## Non-goals
- Live reload as objectives.json changes (requires a watcher; deferred polish).
- Linking to .project/objectives/*.md source files (route gap — guide consumes JSON only).
- Progress diff view vs last N days (requires history store; post-EA polish).

View file

@ -107,6 +107,7 @@ constants, test coverage, two-host workflow).
- Do NOT skip the integrity rule to hit a release deadline. A dashboard
that lies is worse than a dashboard that's behind.
- Do NOT modify Game-2-scoped objectives (p2-12..p2-15) into Game-1.
- **Guide-web / `@magic-civ/guide-engine` / `public/games/age-of-dwarves/guide/` is OUT OF SCOPE** for Shipwright as of 2026-04-17 per user directive. A separate agent owns that surface. Do NOT dispatch guide-web specialists, do NOT claim guide-related objectives (e.g. p2-09), do NOT author new guide pages. Integrity note: the Progress Report page previously landed under Shipwright coordination (guide-progress-dev on 2026-04-17) stays in-repo and functional; future guide work goes to the new owner.
## Escalation

View file

@ -1,12 +1,12 @@
{
"generated_at": "2026-04-17T19:32:03Z",
"generated_at": "2026-04-17T19:38:01Z",
"totals": {
"partial": 10,
"missing": 2,
"done": 33,
"stub": 0,
"done": 32,
"oos": 4,
"total": 48
"partial": 11,
"missing": 2,
"total": 50
},
"objectives": [
{
@ -401,11 +401,11 @@
},
{
"id": "p2-09",
"title": "Player guide web app — deployed and up to date",
"title": "Player guide web app — builds clean from source",
"priority": "p2",
"status": "partial",
"scope": "game1",
"owner": "shipwright",
"owner": null,
"updated_at": "2026-04-17",
"summary": "Guide React app (Vite + TypeScript + React 19) lives under `public/games/age-of-dwarves/guide/`. WASM climate worker shares Rust crates with the game.\n\n**This pass (guide-drift-dev2 / 2026-04-17):** closed the systematic type drift between `@magic-civ/guide-engine` and its consumer. `pnpm typecheck` is now 0-errors in both packages (was 488 + 221 = 709 TS errors total). The prior \"32 errors\" count under-counted by ~22x because it only measured consumer-visible errors, not the 488 internal theme-augmentation errors in guide-engine itself.\n\nPer CLAUDE.md's hard Game-1 scope rule (*\"do NOT ship Game 2 features into Game 1\"*), Option 2 (scope-narrowing) was taken. All Game 2/3 content was excised:\n\n- **Deleted from `src/packages/guide/src/`:** entire `pages/magic/` directory (SpellsPage, MagicSchoolsPage, ArchonsPage, DisciplinesPage, LeyLinesPage), `pages/episodes/EpisodeKzzkytPage.tsx`, `pages/episodes/EpisodeElvesPage.tsx`, `pages/worlds/TheHivePlanetPage.tsx`, `pages/worlds/SilvandelPage.tsx`. Empty `pages/worlds/` dir removed.\n- **Deleted from consumer app `src/pages/`:** 5 local Magic pages (Spells, MagicSchools, Archons, Disciplines, LeyLines).\n- **Removed from routing + nav:** Ep2/Ep3 nav groups, all `/magic/*` routes, `/worlds/the-hive`, `/worlds/silvandel`, `/episodes/age-of-kzzkyt`, `/episodes/age-of-elves`.\n\n**Structural fixes landed:**\n\n- **styled-components theme augmentation** (`src/packages/guide/src/types/declarations.d.ts`): declared `DefaultTheme` with the exact `colors.{primary,accent,background,surface,border,text}` + `typography.{fontFamily,fontWeight}` shape used everywhere. Closed ~400 of 488 guide-engine errors.\n- **Ambient WASM + @resources/* + @lilith/ui-theme stubs** (`src/packages/guide/src/types/ambient.d.ts`, consumer `src/ambient.d.ts`): typed the shapes the guide actually uses, so `tsc --noEmit` from either package resolves cleanly without requiring the WASM pkg to be built.\n- **Game-data type drift:** extended `Unit` (added `hp`, `attack`, `defense`, `unit_type`, `flags`, `attributes`, `tier`, `terrain_bonus`, `encyclopedia`), `Building` (`culture_required`, `encyclopedia`), `Resource` / `Improvement` / `Item` (encyclopedia + index sig), `Tech` (replaced `unlocks_units`/`unlocks_buildings`/`unlocks_spells` → `unlocks: TechUnlocks` + `requires` + `flavor` + `encyclopedia`), `Race` (added `featured_units`, `arcane_rank`, `episode`, `status`), `EncyclopediaEntry` (added `entry_type`, `detail_route`), `EcologicalEventTier` (added `resource_table`), `StrategicAxes` (index sig for dynamic access). Added missing types: `Lens`, `LensCategory`, `LensUnlock`, `LensObservation`, `LensRendering`, `NamedResource`, `ResourceWithEncyclopedia`, `TechUnlocks`.\n- **Barrel surface:** rewrote `src/packages/guide/src/index.ts` from 52 lines to 125 lines with the full Game-1 surface (`PreferencesProvider`, `usePreferences`, `usePreferencesReroll`, `resolveGender`, `resolveRace`, `EpisodeProvider`/`Gate`, `GuideLayout`, `MobileNav`, `RaceThemeProvider`, `SPECIES_LIBRARY`, `applyObservationLens`, all retained pages, etc).\n- **New UI primitives:** added `PageHeading`, `PageSubtitle`, `DataTable`, `Highlight`, `FeatureGrid`, `FeatureChip` to `PagePrimitives.tsx` to match consumer-app expectations.\n- **Context drift:** `GuideDataContextValue` now declares `observationLens?: SpeciesObservationLens` + `speciesLibrary: ObservedSpecies[]` (consumer app was already passing these; type just wasn't there).\n- **Path aliases:** consumer's `@magic-civ/*` paths were off-by-one (`../../../` → `../../../../`); fixed. Added `@magic-civ/web-civmap` alias to guide-engine's tsconfig.\n- **Null-guard fixes:** eight consumer pages now guard optional fields before dereferencing (UnitsPage, CommunicationsPage, EncyclopediaModal, EncyclopediaPage, WondersPage, LairsPage, LensesPage, DevSpritesPage).\n\n**Remaining blocker to flip ✅ done:** `pnpm --filter @magic-civilization/guide-age-of-dwarves build` fails at the final rollup step because `src/simulator/pkg/magic_civ_physics.js` is absent on the EDIT host (WASM is an apricot-built artifact per CLAUDE.md two-host workflow). Apricot was unreachable during this pass (`ssh lilith@apricot.local` timed out). Once apricot is reachable:\n\n```\nssh \"$AUTOPLAY_HOST\" \"cd $PROJECT_ROOT_REMOTE/src/simulator && bash build-wasm.sh\"\npnpm --filter @magic-civilization/guide-age-of-dwarves build # from EDIT host\n```\n\nshould yield a clean `dist/index.html` in one step. The external-hosting decision (GitHub Pages vs Cloudflare Pages vs S3) remains a separate downstream gate."
},
@ -488,6 +488,26 @@
"owner": "shipwright",
"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."
},
{
"id": "p2-18",
"title": "Guide web app — public hosting + deploy pipeline",
"priority": "p2",
"status": "partial",
"scope": "game1",
"owner": null,
"updated_at": "2026-04-17",
"summary": "Separate from p2-09 (which covers the build being clean): this objective covers choosing a public host and running the deploy. Currently the deploy script is ready (`tools/deploy-guide.sh` — modes `build` / `serve` / `apricot` / `zip`), but no public host has been committed for Early Access. The `apricot` mode ships dist/ to the LAN for preview; `zip` produces a handoff artifact that any external host can consume."
},
{
"id": "p2-19",
"title": "Guide progress report page — dynamic dashboard + missing assets",
"priority": "p2",
"status": "done",
"scope": "game1",
"owner": null,
"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)."
}
]
}

View file

@ -10,11 +10,19 @@
set -uo pipefail
: "${AUTO_PLAY:=true}"
: "${AUTO_PLAY_DIR:=$HOME/tmp/ap_default}"
: "${AP_RUN_ID:=}"
# Scoped cleanup: only kill prior processes for THIS AUTO_PLAY_DIR, so parallel
# sibling games (different AUTO_PLAY_DIR) are not disturbed.
pkill -f "AUTO_PLAY_DIR=$AUTO_PLAY_DIR " 2>/dev/null || true
pkill -f "AUTO_PLAY_DIR=$AUTO_PLAY_DIR\$" 2>/dev/null || true
# Scoped cleanup: kill any prior Godot process for THIS exact run ID.
# AP_RUN_ID is a unique token (<stamp>_seed<N>) injected by autoplay-batch.sh;
# using it instead of AUTO_PLAY_DIR avoids substring collisions between seeds
# whose dir names share a numeric prefix (e.g. seed1 matching seed10).
# When AP_RUN_ID is unset (manual invocation), fall back to AUTO_PLAY_DIR scope.
if [ -n "$AP_RUN_ID" ]; then
pkill -f "AP_RUN_ID=$AP_RUN_ID" 2>/dev/null || true
else
pkill -f "AUTO_PLAY_DIR=$AUTO_PLAY_DIR " 2>/dev/null || true
pkill -f "AUTO_PLAY_DIR=$AUTO_PLAY_DIR\$" 2>/dev/null || true
fi
sleep 1
: "${AUTO_PLAY_TURN_LIMIT:=500}"
@ -29,9 +37,18 @@ FLATPAK_ENVS=(
"--env=AUTO_PLAY_DIR=$AUTO_PLAY_DIR"
"--env=AUTO_PLAY_TURN_LIMIT=$AUTO_PLAY_TURN_LIMIT"
)
if [ -n "${AP_RUN_ID:-}" ]; then
FLATPAK_ENVS+=("--env=AP_RUN_ID=$AP_RUN_ID")
fi
if [ -n "${AUTO_PLAY_SEED:-}" ]; then
FLATPAK_ENVS+=("--env=AUTO_PLAY_SEED=$AUTO_PLAY_SEED")
fi
if [ -n "${AI_DIFFICULTY:-}" ]; then
FLATPAK_ENVS+=("--env=AI_DIFFICULTY=$AI_DIFFICULTY")
fi
if [ -n "${AI_PIN_PERSONALITY:-}" ]; then
FLATPAK_ENVS+=("--env=AI_PIN_PERSONALITY=$AI_PIN_PERSONALITY")
fi
GODOT_ARGS=("--path" "." "--rendering-method" "gl_compatibility")
WESTON_PID=""

View file

@ -141,6 +141,7 @@ _run_local() {
"--env=AUTO_PLAY_SEED=$seed"
"--env=AUTO_PLAY_TURN_LIMIT=$TURN_LIMIT"
"--env=AUTO_PLAY_DIR=$game_dir"
"--env=AP_RUN_ID=${STAMP}_seed${seed}"
"--env=AI_DIFFICULTY=${AI_DIFFICULTY:-}"
"--env=AI_PIN_PERSONALITY=${AI_PIN_PERSONALITY:-}"
)
@ -208,6 +209,7 @@ _run_remote() {
AUTO_PLAY_SEED='$seed' \
AUTO_PLAY_TURN_LIMIT='$TURN_LIMIT' \
AUTO_PLAY_DIR='$remote_game_dir' \
AP_RUN_ID="${STAMP}_seed${seed}" \
AI_DIFFICULTY='${AI_DIFFICULTY:-}' \
AI_PIN_PERSONALITY='${AI_PIN_PERSONALITY:-}' \
RENDER_MODE='$RENDER_MODE' \