diff --git a/.project/CHANGELOG.md b/.project/CHANGELOG.md index 5fbe8f4e..bbe89c7a 100644 --- a/.project/CHANGELOG.md +++ b/.project/CHANGELOG.md @@ -183,3 +183,5 @@ The specific bullets citing canopy fields + weather_event records in `turn_stats 2026-04-18 02:20 tourguide p1-16 DONE + wave-A relic cleanup: scope-hygiene rewrites across HomePage (Hero/Pitch/FEATURES/LoreSection — magic paragraphs gated via ), CommunicationsPage (Archon Telepathy row gated), PromotionsPage (removed disciplines/infusions imports + replaced Mana Infusions block with Game 2 pointer note), survival-guide/data.ts (Life T3 spell → mundane quarantine-district mechanic), PersonalityAxesPage (channels-ley-lines prose → knowledge-infrastructure prose), OverviewTab (High Archon roadmap row → succession-crisis roadmap row). Grep gate `grep -RE 'magic schools|High Archon|mana nodes|ley lines' | grep -v 'EpisodeGate|>= 2|VITE_DEV_GUIDE|//'` returns zero hits. New `e2e/scope-hygiene.spec.ts` (5 routes × 11 forbidden substrings) → 5/5 green against CI=1 prod build (VITE_DEV_GUIDE=0). All-routes e2e 51/51 green unchanged. Deployed to mc.next.black.local via direct-IP workaround (plum mDNS cache glitch). Rate-limited guide-web agent landed 4/6 files; tourguide patched the remaining 2 after the limit lifted. p2-32 JSON data files (map-topologies, ep1-systems, homepage-features, shipping-roadmap) authored in parallel by the game-data agent — consumer-swap pending. [ref: tourguide, p1-16, p2-32] 2026-04-18 03:45 tourguide waves B/C/D + race-gate landed: **p2-32 DONE** — all four data-driven consumers swapped (HomePage FEATURES, MapTypesPage, EpisodeDwarvesPage, OverviewTab roadmap tables) read from `homepage-features.json` / `map-topologies.json` / `episodes/ep1-systems.json` / `shipping-roadmap.json` via `@data/` alias; 4 new JSON schemas in `data/schemas/` wired into `tools/validate-game-data.py::validate_guide_data` (203 PASS, 0 FAIL incl. the 4 new files). **p2-30 PARTIAL** — `PagePrimitives.tsx` extended with `DataCard` (`$variant` base/compact/topology), `StatsGrid`, `StatCell`, `QualityIndicator`; MapTypesPage (engine) + ExpansionsPage + TeamPage (meta) migrated; Biome/Species/FloraBar deferred as biggest mechanical diffs. **p2-31 PARTIAL** — `useUrlFilter(key, values, fallback)` hook extracted to `public/games/age-of-dwarves/guide/src/hooks/useUrlFilter.ts` (re-exported from `@magic-civ/guide-engine`), `ObjectivesTab` rebased + `ClimateEventsPage` migrated; `shareable-urls.spec.ts` covers weather-category deep links; Species/Biome migrations paired with p2-30 primitives swap (deferred). **p2-29 PARTIAL** — WelcomeModal race grid now dynamic: `raceOptions = ALL_ELIGIBLE_RACES.filter(r => r.episode <= activeEpisode)` via `useEpisode()`, `App.tsx` filters `playableRaces` before `PreferencesProvider` so `resolveRace('random')` cannot roll a non-episode race (Game 1 = Dwarves only, dev bundle = all 16 races with episode fields); HomePage FEATURES data-driven with `min_episode` gating; dedicated `welcome.spec.ts` Dwarf-Female → Begin → theming spec still pending. Homepage-features.json correction: "16 Asymmetric Races" reclassified `min_episode: 2`; added "Five Rival Dwarf Clans" (Iron Legion / Forge-Wrights / Deep Delvers / Gold Hall / Stonekeepers) as the Game 1 flagship card. [ref: tourguide, p2-29, p2-30, p2-31, p2-32] 2026-04-18 05:40 tourguide waves B/C/D PROMOTED to DONE via 3-agent experts-team (`tourguide-waves-finish-20260418-0524`, all guide-web specialists, slot peak 3/10). **p2-29 DONE** — `welcome.spec.ts` e2e authored at `public/games/age-of-dwarves/guide/e2e/welcome.spec.ts` (welcome-tester): 12 assertions walking `page.goto('/')` → Dwarf + Female buttons → `getByPlaceholder('Leave blank to use the default leader name')` filled with "Brenna Ironshield" → `Enter the Guide` → HomePage `` visible + name in `` + Dwarf vocab + zero forbidden Game 2+ substrings + zero console/pageerror events (IGNORED patterns match sibling specs). Role/label/text locators only — no CSS classes. Authored not executed; apricot Forgejo runner owns the verification run. **p2-30 DONE** — BiomeBrowserPage + SpeciesBrowserPage migrated to shared primitives (biome-migrator + species-migrator). BiomeBrowserPage: Card/CardHeader/CardTitle/StatRow/QualityRange/etc. deleted, replaced with `DataCard($variant="compact")` + `StatsGrid` + `StatCell` + `QualityIndicator`; `PieSvg` stroke now reads `theme.colors.background.primary` instead of `#1a1510`. SpeciesBrowserPage: full rewrite onto `useGuideData().speciesLibrary` (lens-aware), `createPortal` detail modal, three consumer wrappers (dwarves/kzzkyt/elves) reduced to 6-line shims. FloraBar → `` primitive in `PagePrimitives.tsx` (callers pass resolved theme tokens). Flora palette promoted to theme: `buildTheme.ts::FLORA_PALETTE` (dark + light) injected as `theme.colors.flora.{canopy, undergrowth, fungi}` — naming follows the `biome.flora_climax.*` data fields rather than the brief's placeholder `dense/sparse/dead`. Three new `styled-components-augmentation.d.ts` files (one per episode guide) redeclare `DefaultTheme` with `Omit & { colors: ThemeInterface['colors'] & { flora: ... } }` because `@lilith/ui-theme` declares `colors` as an inline literal that can't be interface-merged. Final greps: `grep -E "(#1a9928|#8cc634|#9040a0)" BiomeBrowserPage.tsx` → 0; `grep -E "^const (Card|CardHeader|CardTitle|StatRow|TraitRow) = styled" [Biome|Species]BrowserPage.tsx` → 0. **p2-31 DONE** — `useUrlFilter` adoption fanned out: BiomeBrowserPage (`?category=` + `?biome=` inline scroll-highlight with `role="tablist"` a11y), SpeciesBrowserPage (`?role=&biome=&quality=&species=` with portal modal on history stack so Back closes). Plum verification: `pnpm typecheck` + `pnpm build` (4.96s) clean on the dwarves guide; three terminations (welcome-tester, species-migrator, biome-migrator) clean. apricot Forgejo runner owns `welcome.spec.ts` + all-routes + scope-hygiene e2e when next dispatched. [ref: tourguide, p2-29, p2-30, p2-31] + +2026-04-18 p1-05 LUXURY-UNGATE FALSIFIED (shipwright): tested the "un-gate ivory + furs" lever that p1-05's Remaining section listed as a JSON-only path to closing bullet 5 (luxury variance min≥3). Set `revealed_by_tech: null` on ivory + furs in `public/resources/resources.json`, ran apricot batch 20260418_062941. Per-seed p0 luxury counts: 0,0,0,5,0,0,0,0,0,0 — min=0, only seed 3 (which ran full T300 without early domination) hit 5. Un-gate makes luxury tiles VISIBLE from turn 1 but players still need time to: (a) expand borders to reach them, (b) research the improvement tech, (c) build the improvement. Fast-combat games ending by T75-T150 via domination don't have any of that time. **The real blocker is game length, not tech gates**. Reverted the un-gate. Updated p1-05 objective to cite this falsification evidence and mark "no Shipwright-side lever remains" — closure requires warcouncil's p0-08 domination tempo tune to push median game length past T250. p1-05 stays `partial` per integrity rule. [ref: p1-05] diff --git a/.project/objectives/p1-05-balance-tuning.md b/.project/objectives/p1-05-balance-tuning.md index e4b52aba..c3c44e64 100644 --- a/.project/objectives/p1-05-balance-tuning.md +++ b/.project/objectives/p1-05-balance-tuning.md @@ -66,10 +66,16 @@ need re-tuning against the Rust rate in a follow-up pass. - [x] Median `combats ≥ 120` — **median 808**. - [ ] **Luxury variance ≥ 3 distinct luxuries per seed** — per-seed p0 distinct luxuries in p016b: 3,1,3,1,2,1,8,3,3,0 (min 0). - Regressed from score_fix3 min=3 due to faster combat tempo in - p016b ending games before luxury-gating techs finish. Tune lives - in `resources.json` tech-gates but requires coordination with - p0-08 domination pacing — out of p1-05 JSON-only scope. + **Tested un-gating approach 2026-04-18 and found ineffective**: + batch `apricot-20260418_062941` un-gated furs + ivory (removed + `trapping` tech-gate) → per-seed luxuries: 0,0,0,5,0,0,0,0,0,0 + (only seed 3 had 5, and it ran full T300 without early domination). + Un-gating revealed luxury tiles but games still end too fast for + border-expansion + improvement construction on those tiles. Revert + applied — the true blocker is game-length (p0-08 domination tempo), + not the tech gate. Only seeds reaching T250+ produce luxury variance + ≥3 regardless of resources.json state. Closure requires slower + domination pacing, which is warcouncil / p0-08 scope. - [x] **Strategic gate rejections ≥ 1 across the batch** — 1670 `strategic_gate_rejected` events in p016b across all 10 seeds. - [ ] **`personality_win_balance` PASS** per p0-02 acceptance. *(50-game @@ -80,9 +86,10 @@ need re-tuning against the Rust rate in a follow-up pass. ## Remaining to reach done -1. Luxury variance min≥3 per seed — requires either un-gating 2-3 early - luxuries in `resources.json` (ivory, furs, salt) OR slowing early - combat so games reach 150+ turns consistently. Coordinate with p0-08. +1. Luxury variance min≥3 per seed — un-gating experiment falsified (see + batch `apricot-20260418_062941`). Real blocker is game length; closure + requires warcouncil's p0-08 domination tempo tune to push median game + length past T250. **No Shipwright-side lever remains.** 2. Personality win balance — warcouncil 50-game sample (p0-02 owner). ## Depends on diff --git a/public/games/age-of-dwarves/data/objectives.json b/public/games/age-of-dwarves/data/objectives.json index 0eaa4436..ecff165a 100644 --- a/public/games/age-of-dwarves/data/objectives.json +++ b/public/games/age-of-dwarves/data/objectives.json @@ -1,11 +1,11 @@ { - "generated_at": "2026-04-18T13:04:18Z", + "generated_at": "2026-04-18T13:38:49Z", "totals": { "done": 54, - "missing": 8, - "oos": 18, - "partial": 17, "stub": 4, + "partial": 17, + "oos": 18, + "missing": 8, "total": 101 }, "objectives": [ diff --git a/public/resources/resources.json b/public/resources/resources.json index 061484ad..9e834544 100644 --- a/public/resources/resources.json +++ b/public/resources/resources.json @@ -343,7 +343,7 @@ "forest", "arctic" ], - "revealed_by_tech": null, + "revealed_by_tech": "trapping", "yields": { "food": 0, "production": 0, @@ -378,7 +378,7 @@ "grassland", "desert" ], - "revealed_by_tech": null, + "revealed_by_tech": "trapping", "yields": { "food": 0, "production": 1, diff --git a/src/simulator/build-wasm.sh b/src/simulator/build-wasm.sh index fa5532c2..d43c18af 100755 --- a/src/simulator/build-wasm.sh +++ b/src/simulator/build-wasm.sh @@ -7,7 +7,8 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +# SCRIPT_DIR is src/simulator → REPO_ROOT is two parents up, not one. +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" OUT_DIR="$REPO_ROOT/.local/build/wasm" mkdir -p "$OUT_DIR"