magicciv/.project/objectives/p2-09-guide-web-deploy.md
Natalie 2d9554d9ff feat(@projects): update wasm build and guide deployment workflows
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-04-17 13:06:14 -07:00

8.4 KiB

id title priority status scope owner updated_at evidence acceptance_audit
p2-09 Player guide web app — builds clean from source p2 partial game1 2026-04-17
public/games/age-of-dwarves/guide/
public/games/age-of-dwarves/guide/src/app/guide-data.ts
public/games/age-of-dwarves/guide/src/ambient.d.ts
public/games/age-of-dwarves/guide/tsconfig.json
src/packages/guide/
src/packages/guide/src/index.ts
src/packages/guide/src/types/game-data.ts
src/packages/guide/src/types/declarations.d.ts
src/packages/guide/src/types/ambient.d.ts
src/packages/guide/src/components/ui/PagePrimitives.tsx
src/packages/guide/src/contexts/GuideDataContext.tsx
src/packages/guide/tsconfig.json
src/packages/guide/package.json
src/packages/engine-ts/src/types.ts
src/simulator/api-wasm/
src/simulator/build-wasm.sh
tools/deploy-guide.sh
.project/history/20260417_guide_web_deploy_audit.md
build_zero_ts_errors deployed_to_public_url game_json_import_fixed data_driven_content
🟡 — `pnpm typecheck` now reports 0 errors in both `src/packages/guide` (was 488) and `public/games/age-of-dwarves/guide` (was 221). Vite build transforms 3339 modules cleanly; final bundle step fails only on missing `.local/build/wasm/magic_civ_physics.js` (WASM artifact is per-host, built via `bash src/simulator/build-wasm.sh` locally or on apricot and rsync'd; path relocated from `src/simulator/pkg/` → `.local/build/wasm/` per p1-11 on 2026-04-17 — build output never under src/). Scope-narrow Option 2 landed per CLAUDE.md Game 1 rule: deleted 10 Game-2 pages (Magic schools, Archons, Disciplines, LeyLines, Spells, Ep2/Ep3, Hive, Silvandel). Remaining: run WASM build and re-run `pnpm build` to produce dist/. ✗ — no external hosting target committed for Early Access. `tools/deploy-guide.sh apricot` ships dist/ to apricot:~/public/guide/<version>/ for LAN preview; zip mode produces a handoff artifact for whichever public host wins. External hosting decision remains out-of-scope for this objective. ✓ — public/games/age-of-dwarves/guide/src/app/guide-data.ts import resolves to the canonical public/games/age-of-dwarves/game.json. Vite transform phase passes cleanly; verified as part of the full 3339-module transform in this pass. ✓ — 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.

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.

Per 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:

  • 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.
  • Deleted from consumer app src/pages/: 5 local Magic pages (Spells, MagicSchools, Archons, Disciplines, LeyLines).
  • Removed from routing + nav: Ep2/Ep3 nav groups, all /magic/* routes, /worlds/the-hive, /worlds/silvandel, /episodes/age-of-kzzkyt, /episodes/age-of-elves.

Structural fixes landed:

  • 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.
  • 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.
  • 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_spellsunlocks: 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.
  • 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).
  • New UI primitives: added PageHeading, PageSubtitle, DataTable, Highlight, FeatureGrid, FeatureChip to PagePrimitives.tsx to match consumer-app expectations.
  • Context drift: GuideDataContextValue now declares observationLens?: SpeciesObservationLens + speciesLibrary: ObservedSpecies[] (consumer app was already passing these; type just wasn't there).
  • Path aliases: consumer's @magic-civ/* paths were off-by-one (../../../../../../../); fixed. Added @magic-civ/web-civmap alias to guide-engine's tsconfig.
  • Null-guard fixes: eight consumer pages now guard optional fields before dereferencing (UnitsPage, CommunicationsPage, EncyclopediaModal, EncyclopediaPage, WondersPage, LairsPage, LensesPage, DevSpritesPage).

Remaining blocker to flip done: pnpm --filter @magic-civilization/guide-age-of-dwarves build fails at the final rollup step because .local/build/wasm/magic_civ_physics.js is absent on the EDIT host (WASM is a per-host artifact; see .claude/instructions/build-output-locations.md, path was relocated from src/simulator/pkg/ per p1-11 on 2026-04-17). Apricot was unreachable during the initial audit pass (ssh lilith@apricot.local timed out). Once apricot is reachable:

ssh "$AUTOPLAY_HOST" "cd $PROJECT_ROOT_REMOTE/src/simulator && bash build-wasm.sh"
pnpm --filter @magic-civilization/guide-age-of-dwarves build   # from EDIT host

should 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.

Acceptance

  • 🟡 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

  • Interactive in-browser game preview (would need full WASM game, not just climate).
  • Shipping Game 2 lore pages (magic schools, Archons, ley lines, Kzzkyt, Silvandel) alongside Game 1. Those are deferred scope per the CLAUDE.md boundary rule.