Commit graph

3419 commits

Author SHA1 Message Date
autocommit
5407989139 style(notifications): 🎨 Apply theme color styling to capital blackout overlay and comms toast notifications
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 21:12:33 -07:00
autocommit
65046a032a style(hud): 🎨 Refactor HUD components to apply theme colors consistently across all visual elements
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 21:12:33 -07:00
autocommit
d6c84e4b4f refactor(ui): tokenize HUD notification colors off raw Color() literals
p2-74 cluster 2 (HUD panels + notifications), notifications sub-cluster.
Route turn_notification.gd / comms_toast.gd / capital_blackout_overlay.gd
inline Color() literals onto ThemeAssets.color() design tokens.

- turn_notification: const CATEGORY_COLORS dict (a const trap — token lookups
  can't sit in a const initializer) converted to var _category_colors populated
  in _ready(); category palette → semantic.negative/positive, accent.science,
  accent.goldResource, player.purple, semantic.diplomacy, text.primary. Panel
  bg/border → background.panel/border.panel; title/header → text.title; scrim
  dims → background.hud/overlay; muted hints → text.muted.
- comms_toast: panel bg/border → background.panel/border.panel; accent strip →
  accent.gold; title → text.title; body → text.primary. The configure() accent
  default Color literal (param defaults can't call the autoload) becomes a null
  sentinel resolved to accent.gold in the body.
- capital_blackout_overlay: dim/glitch scrims sourced from background.deepest /
  semantic.negative with explicit .a; title → semantic.negative; subtitle →
  text.title.

Adds tools/capture-proof.sh: reusable single-proof-scene capture under a private
headless weston on the RUN host, pulling the PNG back. Visual-only; no logic
change (Rail 3). 0 Color() remain in the three scripts.

Proof: hud_proof.tscn captured on apricot (headless weston) shows the themed
purple Turn Summary panel, gold border/title, copper filter checkboxes, and
semantic per-category entry coloring (red combat, green founding, blue tech,
gold economy, violet magic).
.project/screenshots/p2-74-cluster2-hud-notifications.png

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:57:41 -07:00
autocommit
3a04052385 docs(objectives): revise p2-65 bullet-9 + p2-72a array-removal resume notes (stale-premise audit)
p2-65 (stays partial K=8/9): rewrite Phase-7 resume note. The 'no-persistent-
GdGameState / discards combat_balance' premise is STALE — game_state.gd:269
loads combat_balance.json into the persistent _gd_state singleton via
GdGameState::set_combat_balance_json (api-gdext/src/lib.rs:3541), and the driver
objective p2-55f is already done with its bullet 2 marked [x]. Bullet 9 must NOT
be closed on that path (it bypasses mc-state entirely — would be an
objective-integrity reframe). Remaining work is architectural consolidation
(mc_state::SimConfig owning global config), now an owner decision, not a
mechanical close-out.

p2-72a (stays partial): array-removal increment re-checked and NOT executed.
All three gate-feasibility blockers reproduce — cold Godot import cache, no
mc-godot Docker image (freeze-safe path unbuilt), operator-gated visual proof
unavailable this session. game_state.gd UNTOUCHED (npc_buildings count = 33).
Clean stop re-confirmed; predecessor's execution recipe unchanged.

Regen objectives index. No status frontmatter changed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:55:08 -07:00
autocommit
f5c4ee9c30 chore(tooling): 🔧 Update Claude bridge submodule reference for development tooling
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 20:50:49 -07:00
autocommit
f80609097b chore(index): regen objectives.json (p2-73 done, p2-65 8/9, de-hardcode cluster 1)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:48:45 -07:00
autocommit
0d5f2ff00b ui(menus): 💄 Refactor menu screens with consistent theming, animations, and standardized vocabulary
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 20:30:32 -07:00
autocommit
416316a2e8 feat(combat): Introduce combat_preview.gd for rendering and managing combat scene previews
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 20:30:32 -07:00
autocommit
11ad9e3d5d refactor(city): ♻️ Replace hardcoded colors in BuildingPanel, CityBuildableHelper, and CityScreen with theme-aware dynamic color resolution
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 20:30:32 -07:00
autocommit
42cd08d8f3 refactor(ui): tokenize menus + city + combat scene colors off raw Color()
p2-74 cluster 1 (modals + menus), batch 2. Route inline Color() literals in
12 scene scripts onto ThemeAssets.color() design tokens by semantic role:
- end_game_summary: banner victory/defeat → accent.gold/semantic.negative,
  standings rank → semantic.positive, score → accent.goldResource, body roles.
- victory/defeat_screen: result + row colors → accent/semantic/text tokens.
- credits/how_to_play/throne_room_spoils/game_setup: titles → accent.goldResource
  /text.title, dividers → border.divider, body → text.primary/secondary/muted.
- loading_screen: PLAYER_COLORS const removed; player.color now routes through
  ThemeAssets.get_player_color() (palette-aware) with player.gray fallback.
- throne_room: placeholder label → text.primary@0.65; the 12 _layer_to_color
  decoration tints intentionally retained (categorical, no token home).
- city/building_panel: DISABLED_OUTLINE_COLOR const → @onready var off
  semantic.negative@0.85 (const can't call autoload).
- city_buildable_helper: built→positive, locked/blocked→negative, worked→
  text.title, unworked→text.muted.
- city_screen focus toggle: active→accent.gold, inactive→text.muted.
- combat_preview grudge badge → semantic.negative.

Visual-only; no logic change. Data-driven clan/player colors and Color.WHITE/
GRAY fallbacks left intact. gdlint HEAD-vs-now shows zero new violations per
file. Proofs on apricot (weston headless): statistics_proof (5 tabs) +
end_game_summary_proof (4 outcomes) compile-load and render the themed purple
panels / gold titles / semantic coloring with no magenta token fallbacks.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:11:03 -07:00
autocommit
164fed22ae refactor(statistics): ♻️ Replace hardcoded rank badge colors with semantic design tokens for consistency
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 20:09:12 -07:00
autocommit
78dc200233 style(throne-room): 🎨 Update text color in throne_room.gd to enforce theme token consistency
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 20:09:12 -07:00
autocommit
5c578e0d01 docs(p2-72a): 📋 scope array-removal increment + correct the save-format coupling claim
Read-only analysis of the npc_buildings serialize chain (no code touched;
game_state.gd unchanged). Finding: the resume map's "array removal forces a
SaveManager rewrite, cannot land independent of save-format-migration" claim is
over-stated. `_serialize_npc_buildings` → `serialize_npc_buildings` calls
`b.to_dict()` on each `Building` view, and that view's `to_dict()` already
proxies to `_gd_state.npc_building_dict(_idx)` — serialized bytes are already
sourced from the Rust mirror. Re-pointing serialize at the mirror directly is
byte-identical; the save FORMAT does not change. This objective owns the whole
increment.

STOPPED this session deliberately (gate-feasibility, not coupling): the increment
edits the highest-regression live-world-map file and must land as one green commit
gated by GUT-headless + cargo + build:gdext + operator-gated world-map visual
proof. Godot import cache is cold (host-freeze risk per godot-docker.sh), no
mc-godot Docker image / warm volume exists, and the visual proof needs operator
sign-off — not completable safely without a runway session. Precise execution
recipe (serialize re-point + 6 reader retargets + array/spatial-index/view-fn
deletion + gate steps) recorded for the next session. Status stays partial.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:06:53 -07:00
autocommit
bbacf5ff8d docs(p2-65): 📊 Phase 4+5 landed — bullets 1/2/3/4/5/6/7/8 ✓, K=8/9 partial
Recount p2-65 acceptance after the Wave-D session-2 consumer sweep
(C1 1917c3db5 / C2 efbfa6ae3 / C3 0bdf7b57c):
- bullet 6 (grep mc_turn::game_state|mc_turn::GameState → 0): ✓ — both shims
  deleted, brace+inline+nested forms all swept.
- bullet 5 (consumer Cargo downgrades): ✓ — mc-state added to 6 crates;
  mc-turn dropped from mc-save/mc-vision/mc-mcts-service.
- bullets 1/2/3/4/7/8: ✓ with honest footnotes (combat_balance resolved via
  mc-core not mc-state; mc-ai dep on mc-turn retained = logic dispatch not a
  cycle; --features gpu has pre-existing unrelated CombatResult drift).
- bullet 9 (Phase 7 SimConfig wiring):  STILL OPEN — sole remaining item.

Status stays `partial` (objective-integrity K=N rule; K=8/9). Phase-7 resume
note appended (mc_state::SimConfig → api-gdext init, closes p2-55f bullet 2).
Index regenerated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 20:00:11 -07:00
autocommit
ba52171b70 refactor(ui): tokenize statistics modal colors off raw Color() literals
p2-74 cluster 1 (modals + menus). Route statistics.gd's 23 inline Color()
literals onto ThemeAssets.color() design tokens: panel bg/border →
background.panel/border.panel, title → text.title, body/muted/disabled text
roles, rank-badge gradient → semantic.positive/warning/diplomacy/negative,
score value → accent.goldResource, trend arrows → semantic.positive/negative,
backdrop → background.overlay. Converted const RANK_COLORS → var _rank_colors
populated in _ready() (token lookups can't sit in a const initializer).
Data-driven clan/player line colors left intact. Visual-only; no logic change.

Proof: statistics_proof.tscn captured on apricot (weston headless) shows the
themed purple panels, gold borders/title, and semantic rank coloring.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:58:12 -07:00
autocommit
2c19b6c193 test(combat): Update test UID and logic for lair mode picker functionality in combat scenes
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 19:52:32 -07:00
autocommit
11cb4729b6 chore(game): 🔧 Update project.godot config to enable theme system with default overrides and engine adjustments
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 19:52:32 -07:00
autocommit
d4d54dc56e test(scenes-component): Add test scenes with GDScript and UI theme files to validate theme application and rendering
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 19:52:32 -07:00
autocommit
df2356439a feat(lair-mode-picker): Introduce lair mode picker UI component and add test coverage with statistics proof scene and unit tests
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 19:52:32 -07:00
autocommit
cad2183c51 feat(themes): Introduce semantic design tokens system for UI theming with theme assets, resource files, build integration, and unit tests
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 19:52:32 -07:00
autocommit
0bdf7b57cc refactor(p2-65): 🏗️ Phase 5 C3 — drop dead mc-turn deps from read-only consumers (bullet 5)
After C2 retargeted all state-shape reads onto mc-state, three crates carry
no remaining `mc_turn::` usage of any kind:
- mc-save: 0 mc_turn refs → drop `mc-turn` dep (keeps mc-state).
- mc-vision: 0 mc_turn refs → drop `mc-turn` dep (keeps mc-state).
- mc-mcts-service: only a doc-comment referenced mc_turn; code uses mc-ai
  alone → drop the dead `mc-turn` dep (verified `cargo build -p
  mc-mcts-service` green without it).

api-gdext / mc-player-api / mc-sim KEEP mc-turn — they genuinely invoke
turn-step logic (TurnProcessor, action_handlers, courier_resolver, chronicle,
VictoryConfig, combat_balance loader). mc-turn KEEPS its mc-ai dep — it calls
mc_ai ransom-decision / abstract-projection / ScoringWeights helpers during
turn resolution (8 sites); that is logic dispatch, not a state-data cycle.

Gates (apricot): cargo test --workspace --no-run exit 0; serde_roundtrip 6/6;
full_turn_golden 3/3; mc-save 5+5+1; mc-vision 29/29 (1 ignored).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:51:27 -07:00
autocommit
efbfa6ae3f refactor(p2-65): 🏗️ Phase 4 C2 — delete mc-turn GameState shim + re-export (bullet 6 → 0)
Complete the consumer migration off mc-turn's state-shape pass-through:
- mc-turn/src/lib.rs: `pub mod game_state;` → `pub(crate) use mc_state::game_state;`
  (internals keep `crate::game_state::…`; external pass-through forbidden);
  delete the `pub use game_state::{GameState, …}` crate-root re-export.
- Delete the mc-turn/src/game_state.rs re-export shim file.
- Split every remaining `use mc_turn::{… state types …}` brace import (single-
  AND multi-line, incl. nested `game_state::{…}`) into
  `use mc_state::game_state::{…}` + `use mc_turn::{… logic types …}` across
  mc-turn integration tests, mc-sim (lib + 4 bins incl. solo_dominion),
  mc-player-api tests, and tests/integration. Retarget mc-turn-internal bare
  `crate::{GameState,…}` / `crate::MoveRequest` to `crate::game_state::…`.
- Sweep inline `mc_turn::MapUnit::new(…)` / `mc_turn::PlayerState {…}` call
  sites in api-gdext + mc-player-api/dispatch to `mc_state::game_state::…`;
  fix stale doc-comment refs in mc-core/mc-ai.
- Add `mc-state` path dep to tests/integration.

Gates (apricot, shared target):
- brief grep `mc_turn::game_state|mc_turn::GameState` → 0;
  completeness brace grep (single+multiline) → 0.
- cargo test --workspace --no-run exit 0.
- serde_roundtrip 6/6; full_turn_golden 3/3 (save-format byte-identical).
- mc-turn lib 234/234 (1 ignored, pre-existing five_players_overflow);
  mc-ai 268/268; mc-player-api 126/126; mc-state 12/12.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:47:55 -07:00
autocommit
cea53e1ee4 feat(p2-73): 🎨 generate ui_theme.tres from design tokens + global apply + color() accessor
Close the gap where the design system (.project/designs/design-tokens.json)
drove the React guide but not the Godot game.

- tools/build-ui-theme.py: compiles the W3C/style-dictionary token SoT into a
  complete Godot Theme (7 StyleBoxFlat sub-resources, Button/Label/Panel/
  PanelContainer/ItemList/RichTextLabel colors + font sizes + corner radii/
  border widths per UI_DESIGN_SYSTEM.md §3/§4/§6). ui_theme.tres is now a
  GENERATED artifact; tokens are the single source of truth. Deterministic
  output (sorted keys, fixed float fmt, preserved uid://ui_theme_fantasy) with
  a --check drift gate. Idempotent; --import does not rewrite it.
- project.godot [gui] theme/custom: applies ui_theme.tres at viewport level so
  every non-overriding default Control renders the copper fantasy styling.
- ThemeAssets.color(name) -> Color: resolves dotted token names (accent.gold,
  semantic.positive, text.primary, …) against the metadata/tokens JSON blob
  baked into the .tres by the generator. Fully data-driven from the SoT, no
  hardcoded color map. (Godot rejects dots in Theme color item names, so the
  token table ships as resource metadata.) Unknown names return an explicit
  fallback. This is the API p2-74 will de-hardcode 45 scripts onto.
- ui_theme_proof.{tscn,gd}: bare-widget + color()-swatch proof scene.
  test_theme_assets_color.gd: GUT accessor coverage (5/5 headless).

Proof captured on apricot under weston, reviewed in conversation:
.project/screenshots/p2-73-ui-theme-proof.png. Workspace green — full unit
(16==16) and integration (18==18) suites show identical HEAD-baseline-vs-patch
failure counts, zero regressions; patch adds +5 passing tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:42:01 -07:00
autocommit
1917c3db53 refactor(p2-65): 🏗️ Phase 4 C1 — retarget consumers off mc_turn::GameState onto mc_state
Sweep all 44 real code references + 14 doc-comment references from
mc_turn::game_state::/mc_turn::GameState to mc_state::game_state:: across
the external consumer surface (mc-player-api src+tests, mc-sim, api-gdext,
mc-save tests, mc-vision, mc-turn integration tests). Add `mc-state` path
dep to the 5 consumer crates (api-gdext, mc-player-api, mc-sim, mc-save,
mc-vision). The mc-turn/lib.rs:63 re-export + game_state.rs shim stay in
place for this green boundary; the pub(crate) alias + shim deletion land
in C2.

mc-core doc-comment refs (derived_stats/lair/tactical_types) retargeted
too — they are real gate violations for the bullet-6 grep, not legit use;
no code dep on mc_turn (all prose), so no dev-dep needed.

Gate (apricot, shared target): cargo test --workspace --no-run exit 0;
serde_roundtrip 6/6; full_turn_golden 3/3; mc-turn lib 234/234 (1 ignored,
pre-existing five_players_overflow); mc-ai 268/268; mc-player-api 126/126;
mc-state 12/12.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:36:07 -07:00
autocommit
bcf72d34b8 deps-upgrade(bridge-cse): ⬆️ Update bridge-cse submodule reference to ensure compatibility with latest version in tooling/claude/dot-claude/worktrees/
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 19:26:25 -07:00
autocommit
180c521977 docs(p2-65): 📊 Phases 1/3a/3b landed — status stub→partial, Phase-4 resume note
mc-state crate created + GameState moved into it (green @ 0ed21945c). Records the
3 green-between commits (0bace0e6c / 45e9adea9 / 0ed21945c), the save-format +
parity evidence, the honest ~5/9 acceptance recount (bullet 6 still 20+ shim
leaks → status stays partial, NOT done), and the precise Phase-4 path: sweep
all mc_turn::game_state/GameState sites (external + mc-turn internals + the
lib.rs:62 re-export) to mc_state::, delete both shims, with the dev-dep rule for
mc-core/derived_stats (the one upstream-of-mc-state consumer). FINISH_GAME1_PLAN
Wave-D row 1 updated to match.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:20:40 -07:00
autocommit
f05231b825 docs(plan): Wave F — design-system fidelity gap (p2-73 pipeline + p2-74 de-hardcode)
Quantified gap: design-tokens.json drives the web guide but not Godot; ui_theme.tres never applied as root theme; 45 scene scripts hardcode 973 Color() + 307 theme overrides. Two objectives filed; foundation (p2-73) dispatched.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:16:20 -07:00
autocommit
0ed21945c1 refactor(mc-state): 🏗️ Phase 3b — move GameState into mc-state behind a shim
p2-65 foundation milestone. `game_state.rs` (1356 lines: GameState +
PlayerState + MapUnit + TechState + PendingCaptureEvents + 8 action-request
structs + RallyCommand/BuildingRallyPoint/CityEcology + custom serde helpers)
relocated from mc-turn to mc-state. Decouples the canonical full-simulation
state shape from the turn-step mutation logic (Rail 1 cleanup).

- `git mv mc-turn/src/game_state.rs → mc-state/src/game_state.rs`; mc-turn's
  `game_state.rs` is now `pub use mc_state::game_state::*;` so all ~30 consumer
  sites (mc-ai, mc-player-api, mc-mod-host, api-gdext, mc-sim, mc-replay) +
  mc-turn's lib.rs `pub use game_state::{GameState,…}` re-export resolve
  unchanged for one cycle (Phase 4 sweeps them).
- Re-paths inside the moved file: `crate::combat_balance::CombatBalance` →
  `mc_core::CombatBalance` (the only non-sibling code ref); the 5
  sibling-module field types (ransom/capture/patrol/combat_event) resolve as
  `crate::` since they're now co-located in mc-state. Broken `[crate::…]`
  intra-doc links demoted to plain `mc_turn::…` backtick prose.
- `PendingCaptureEvents::drain_into` peeled off into the mc-turn-local
  `DrainCaptureEvents` extension trait (`capture_drain.rs`): it embeds
  `mc_replay::TurnEvent` + `mc_turn::combat_event::TurnResult`, neither movable
  to the data crate without a cycle. Local-trait-for-foreign-type, orphan-rule
  legal. 4 call sites (processor.rs + 3 tests) add the trait `use`.

SAVE-FORMAT GATE (the byte-identical proof): mc-turn serde_roundtrip 6/6 +
full_turn_golden 3/3 green — assembled GameState round-trips identically
post-move (serde shapes invariant; module paths were never on disk).

Parity (apricot): workspace --no-run exit 0; mc-state 12/12 (8 + the 4
game_state unit tests that moved with the file); mc-turn lib 234/234
(1 ignored, pre-existing — was 238 before the 4 moved out); mc-ai 268/268;
mc-player-api 126/126.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:16:00 -07:00
autocommit
cc66e7a24c deps-pin(claude): 📌 Pin Claude tooling dependency version for stable development
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 19:02:04 -07:00
autocommit
45e9adea92 refactor(mc-state): 🏗️ Phase 3a — relocate capture/event/patrol data shapes
p2-65 cont. Move the remaining GameState/PlayerState/MapUnit field-type data
shapes out of mc-turn into mc-state, leaving turn-step logic behind. Each is a
re-export shim so `crate::{capture,combat_event,patrol}::*` paths resolve
unchanged.

- mc_state::capture — `CapturePosture` enum + `Default` + `TryFrom<_> for
  PostureResolution` + `PromptUnresolved`. (The `TryFrom` MUST move with the
  enum: once `CapturePosture` is foreign to mc-turn, that impl would be
  orphan-rule-illegal there — Self=PostureResolution is mc-combat, trait is
  std.) `resolve_posture` (reads MapUnit/PlayerState) stays in mc-turn.
- mc_state::combat_event — the 6 capture/PvP event structs staged on
  `PendingCaptureEvents` (`UnitCaptured/RansomOffered/RansomAccepted/
  RansomExpired/Killed/CivilianDestroyed`). `TurnResult` + Fauna/Pvp/Siege/
  StrategicGate events stay in mc-turn (they embed VictoryType + mc_replay,
  and TurnResult is not a persisted GameState field — only a drain target).
- mc_state::patrol — `PatrolOrder` + `PatrolMode` + pure self-methods
  (`advance_cursor`/`target`). The unit-mutating command surface
  (`issue`/`cancel`/`edit`, `PatrolError`, `validate_waypoints`,
  `advance_on_turn`) stays in mc-turn, converted from `PatrolOrder::`
  associated fns to `patrol::` free fns; 3 call sites in
  action_handlers/mod.rs updated.

Save-format invariant held (verbatim fields + serde attrs; snake_case rename
preserved on CapturePosture/PatrolMode). New serde round-trip tests in each
mc-state module.

Gates (apricot): cargo test --workspace --no-run exit 0; mc-state 8/8;
mc-turn lib 238/238 (1 ignored, pre-existing); mc-turn patrol 14/14,
capture_posture 7/7; capture_pvp_end_to_end/caravan/chronicle 4/3/3.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:01:30 -07:00
autocommit
39bf244f74 docs(p1-29j): 📋 File autoplay→Rust action-application objective (p1-29d unblock)
p1-29i's full-game validation pinned the root cause that gates all of Wave-C
AI convergence: the autoplay AI applies city-founding/capture via GDScript
(`ai_turn_bridge_dispatch.gd:170 dispatch_found_city` → CityScript.new() →
EventBus.city_founded.emit), NEVER calling Rust `mc_turn::processor::
try_found_city` / `process_siege` where the balance levers live. So every
Rust-side founding/siege lever (p1-29i refound_suppression, and successors) is
inert by construction on the p1-29d gate surface — a Rail-1 violation on the
action-application seam.

Spec-only (Rail-1, scope game1, owner warcouncil, status stub). Large separate
effort, gated on p2-65 (mc-state gives the bridge a persistent GdGameState to
apply actions against). References p1-29d Findings A/2/3 and p1-29i's terminal
result. Added to objectives README dashboard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 19:00:19 -07:00
autocommit
0bace0e6ce refactor(mc-state): 🏗️ Phase 1+3a — create mc-state crate, relocate RansomQueue
p2-65 foundation. New data-shape crate `mc-state` (deps: data crates only —
no mc-ai, no mc-turn, no rayon/GPU) to decouple simulation state from the
turn-step mutation logic in mc-turn.

- New crate `crates/mc-state` added to workspace members; lib.rs declares the
  module set (ransom now; game_state to follow).
- `RansomOffer` + `RansomQueue` (struct + self-contained queue mechanics +
  `RANSOM_OFFER_DURATION_TURNS`) moved verbatim from mc-turn to
  `mc_state::ransom`. `mc-turn/src/ransom.rs` is now a `pub use` shim so every
  `mc_turn::ransom::*` import path resolves unchanged.
- mc-turn gains `mc-state` path dep. No cycle: mc-vision→mc-turn→mc-state, and
  mc-state deliberately does NOT dep mc-vision (game_state uses no mc_vision
  field type — only a doc-comment ref).
- Save-format invariant held: serde shapes byte-identical (serde never encoded
  module paths). New round-trip + tick/take tests in mc-state.

Gates (apricot): cargo test --workspace --no-run exit 0; mc-state 2/2;
mc-turn ransom 13/13; api-gdext capture_bridge 8/8.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 18:47:12 -07:00
autocommit
b7768d2680 chore(claude): 🔧 Update submodule reference path for Claude tooling's worktree bridge
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 18:41:15 -07:00
autocommit
9f1a28b4e8 docs(p1-29i): 📊 Full-game validation — refound lever inert on autoplay gate; do NOT author cd=5
Ran the deferred full-game validation as a controlled same-build before/after:
one GDExtension built once on apricot from pinned SHA 3d83f4781 (carries the
lever); combat_balance.json is runtime-loaded, so only cooldown_turns would
change between arms.

Pre-flight killed the batch before it ran — cd=5 is inert by construction on the
p1-29d autoplay gate surface, for two independent reasons:

1. Architectural: autoplay applies founding via GDScript dispatch_found_city,
   never calling the Rust try_found_city/process_siege where the refound gate
   lives (same class as process_science bypassed by GdTechWeb). Lever cannot fire.
2. Behavioral: autoplay produces terminal capital-capture eliminations, never
   refound churn — no event for cooldown_turns to gate (4-seed cd=0 run shows
   cities_lost 0–1 per game, all terminal; corroborated by the 10-seed
   20260529_185955 table).

Arm B (cd=5) NOT run: byte-identical by logic (zero qualifying events) — a hollow
"no effect" confirmation, the inverse of the batch-attribution trap. The pre-flight
clause authorizes stopping.

Verdict: do NOT author cd=5. combat_balance.json left at default 0 (the gridded
5/9→8/9 lift is real on the gridded harness but does NOT transfer — recontextualized
as a surface mismatch, NOT retracted). p1-29h elim bullet scoped to the gridded
surface. p1-29d D1 re-pointed: no longer gated on the refound lever (it does not
unblock D1); real unblock is the autoplay→Rust action-application architecture gap
(out of fence).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 18:24:28 -07:00
autocommit
4c719a073e docs(p2-48a): phase-gate approved — end-game summary GUT+proof done
Orchestrator-reviewed clean proof (all 4 GameOverReason variants, themed copy) + GUT green. partial -> done.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 18:20:08 -07:00
autocommit
3952ece916 scripts(scripts): 🔨 Add UI proof capture script for screenshot generation and visual regression testing
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 18:19:11 -07:00
autocommit
7ba5051606 chore(age-dwarves): 🔧 introduce expanded dwarven terminology in vocabulary.json for "Age of Dwarves" expansion
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 18:19:11 -07:00
autocommit
e001f214b3 feat(world-map): Update combat resolution logic in WorldMapCombat with new turn-based mechanics, unit movement rules, and algorithm refinements
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 18:19:11 -07:00
autocommit
5a5c023c46 feat(combat-scenes): Introduce LairModePicker class, scene setup, and tests for combat scene lair mode selection UI/UX
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 18:19:11 -07:00
autocommit
db51852022 refactor(scenes): ♻️ Refactor end-game summary and statistics scenes with new test coverage and optimized rendering for all game-over conditions
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 18:19:11 -07:00
autocommit
7e6c10613a chore(scripts): add reusable UI-proof capture under weston on the RUN host
Runs a Godot proof .tscn under a weston --backend=headless virtual Wayland
compositor (a real display is required — --headless returns a null viewport
image, and the proof scenes read get_viewport().get_texture().get_image()).
Wipes the matching prior PNGs, runs the scene, lists the produced shots so the
caller can rsync them back. Parameterized by PROOF_SCENE + SHOT_GLOB; generalizes
the per-objective p2-60/p1-56 proof scripts. Used to re-capture the statistics +
end-game summary proofs for the Wave-A vocab polish.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 18:17:47 -07:00
autocommit
fd690d2483 feat(combat): add lair Assault/Raid/Siege mode picker on lair engagement
Advances p3-10a. Moving a stack onto a wild-lair tile now opens a small
CanvasLayer mode picker (modeled on promotion_picker.tscn) before combat:
Assault (enabled), Raid (disabled — p3-10c), Siege (disabled — p3-10b). The
picker emits mode_chosen(mode) / cancelled(); world_map_combat.initiate_lair_combat
opens it and routes the Assault branch through _begin_lair_assault → the existing
p0-17 show_lair_preview → _handle_lair_clear path (per p3-10a, "the existing path
IS the assault"), so the working lair-clear flow is not regressed.

Scope note: Assault routes through the live p0-17 flow, NOT GdLair.assault()
(api-gdext/src/lair.rs) — that bridge is the 7-arg JSON marshaller and would
require building attacker/defender JSON + loading tier_NN.json + applying
loot/survivor/clear outcomes in GDScript, duplicating the working path. The
p3-10a bullet therefore stays ◐ (bridge not exercised end-to-end; no picker
proof screenshot yet).

GUT: tests/unit/test_lair_mode_picker.gd 5/5 green on apricot headless
(only-Assault-enabled, Assault emits mode_chosen("assault"), Cancel emits
cancelled() and no mode, disabled Raid/Siege never emit via the in-handler
guard, target label resolves the lair name). All-Dwarf vocab keys
(lair_picker_*, lair_mode_*) authored in vocabulary.json.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 18:17:38 -07:00
autocommit
1c0d136117 feat(vocab): author statistics + end-game summary copy, drop placeholder keys
The stats modal (statistics.gd) and end-game summary (end_game_summary.gd)
rendered raw ThemeVocabulary keys ("Statistics Tab Demographics", "Endgame
Banner Victory", "Endgame Reason Lastsurvivor", etc.) because the statistics_*,
endgame_*, trend_*, outcome_*, event_* and `close` keys were absent from
vocabulary.json — lookup() falls back to title-case on a miss.

Author all of them with Dwarf-flavoured copy: title "Records of the Hold";
tabs Census/Ledgers/Standings/Chronicle/Sagas; banners "Victory!" / "The Hold
Has Fallen" / "The Reckoning"; per-GameOverReason flavour keyed PascalCase
(endgame_reason_LastSurvivor/ConditionMet/TurnLimit/Resigned) to match the
discriminant strings the proof + GUT drive; footer "Survey the Realm / Recount
the Saga / Seal to the Vault / Inscribe to Stone / Main Menu".

statistics_proof.gd: rebuild StatsTracker.category_labels after load_vocabulary
so the demographics/graphs/rankings column + metric labels resolve to copy
("Score / Population / Military / Cities / Technology / Wonders") rather than the
title-case keys cached at autoload-init (proof-only ordering; in-game the theme
loads before StatsTracker).

Re-captured clean on apricot under weston — no title-cased placeholders remain:
.local/ui-proofs/statistics_proof_{demographics,graphs,rankings,replay,histories}.png
.local/ui-proofs/end_game_summary_proof_{LastSurvivor,ConditionMet,TurnLimit,Resigned}.png

Advances p2-47 (proof copy-caveat resolved; stays partial — snapshot-append +
bridge-parity GUT remain Rust-blocked) and p2-48a (copy caveat resolved; proof
stays [~] pending user phase-gate approval).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 18:17:02 -07:00
autocommit
3d83f4781c chore(bridge-cse): 🔧 Update submodule reference to ensure correct version alignment
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 17:34:39 -07:00
autocommit
aabaec35e6 feat(mc-turn): Introduce refound suppression tracking in GameState to prevent duplicate refounds during turn-based gameplay
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 17:11:17 -07:00
autocommit
02a152b6b1 test(simulator): Add test case for gridded elimination with refound suppression in player API
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 17:11:17 -07:00
autocommit
2441454e95 chore(mc-core): 🔧 Add post-capture refound suppression logic to combat balance system
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 17:11:17 -07:00
autocommit
40bb2b1f2c test(p1-29i): geometry ensemble — robust elimination lift, corrected baseline framing
A single-seed sweep is uninformative (scripted path barely responds to rng), so
add a geometry ensemble over INITIAL CONDITIONS: start-distance {4,5,6} ×
attacker-warriors {3,4,5} = 9 surfaces, at cooldown {0,3,5,8}.

Result (elimination-rate X/9):
  cd=0 (baseline): 5/9   (attacker-wins 5 / def 4)
  cd=3:            7/9   (att 7 / def 2)
  cd=5:            8/9   (att 7 / def 2)   <- peak
  cd=8:            6/9   (att 5 / def 4)

The refound cooldown produces a ROBUST lift (soft hump peaking cd 3-5, every
value >= baseline; cd=5 weakly dominates cd=0 cell-by-cell — better in 3/9,
worse in 0/9), shifting outcomes toward the heavier attacker. This overturns the
single-seed pessimism in the prior commit.

CORRECTED PREMISE: p1-29h's cited "20 captures / 0 eliminations" was a
single-GEOMETRY artifact (the dist=5/w=4 cell). Eliminations already occur in
5/9 baseline geometries — the lever RAISES an existing rate (5/9 -> 8/9), it
does not unlock elimination. p1-29h elimination bullet updated to reflect this.

DELIBERATELY NOT DONE (honest, evidence-bounded):
- No cd value authored into combat_balance.json — the lift is gridded-micro-
  surface only (9 geometries, 1 seed each); a live balance value needs the
  full-game 10-seed batch (tools/p1-survival-score.py, the multi-seed-tournament
  rule). The cd response is also an unexplained hump (cd=8 -> 6/9). Lever stays
  defaulted off.
- p1-29d NOT re-scored as converged — its gate is the full-game multi-gate
  scorecard (D1: P1 elim<=T100 OR stalled, 10/10), a different + heavier surface
  not run this pass. The brief's "re-score p1-29d" is gated on that measurement.

Tests (apricot): gridded harness non-ignored 1/1; ensemble + sweep run via
--ignored; cargo check --workspace 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 16:38:27 -07:00
autocommit
20509d2cce test(simulator): Add comprehensive tests for caravan capture, engineer interactions, and PvP end-to-end validation in the simulator's mc-turn crate
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-04 16:30:36 -07:00
autocommit
a49e24c969 feat(p1-29i): post-capture refound-suppression lever (defaulted off) + measurement
p1-29h Phase 2 isolated the elimination wall. A per-player diagnostic added to
the gridded harness shows per_player_min_cities=[1,1] — both empires ARE pressed
to one city but neither is eliminated; the loser instantly refounds. That
[1,1]-but-no-kill signal makes refound-suppression the correctly-targeted lever.

Lever (data-driven, Rail 2, DEFAULTED OFF — zero live-balance change):
- mc_core::CombatBalance::refound_suppression { cooldown_turns: u32 } (default 0).
- mc_turn::PlayerState::last_city_lost_turn stamped at the capture site.
- processor::try_found_city refuses a replacement while
  turn - last_city_lost_turn < cooldown_turns (0 short-circuits).

Measurement (single-seed sweep, 160t): cooldown 0->0 elim, 5->1, 10->0, 20->0,
40->0. The lone cd=5 elimination is NOT credited as convergence — it is
single-seed noise: non-monotone (more suppression -> fewer eliminations), the
WINNER flips slot-to-slot across the sweep (chaotic-snowball perturbation, not a
lever response), and it fails p1-29h's literal gate. The lever demonstrably
suppresses refounding (founds trend down) but suppression ALONE does not robustly
convert captures into eliminations. Honest measured-negative per the brief; NO
non-zero combat_balance.json value authored, p1-29d NOT re-scored as converged.

Tests (apricot): mc-core 262 lib; gridded harness non-ignored 1/1; cargo check
--workspace 0; cargo test --workspace --no-run 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 16:29:04 -07:00