From 3a04052385c7217fd58fd5e6ab7a7e66b0dc15dc Mon Sep 17 00:00:00 2001 From: autocommit Date: Thu, 4 Jun 2026 20:55:08 -0700 Subject: [PATCH] docs(objectives): revise p2-65 bullet-9 + p2-72a array-removal resume notes (stale-premise audit) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- .project/objectives/objectives.json | 4 +- .../p2-65-extract-mc-state-crate.md | 83 ++++++++++++++----- .../objectives/p2-72a-building-entity-port.md | 28 ++++++- 3 files changed, 89 insertions(+), 26 deletions(-) diff --git a/.project/objectives/objectives.json b/.project/objectives/objectives.json index e0ab51be..a9a0c6e8 100644 --- a/.project/objectives/objectives.json +++ b/.project/objectives/objectives.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-06-05T03:47:56Z", + "generated_at": "2026-06-05T03:54:45Z", "totals": { "done": 243, "in_progress": 1, @@ -3105,7 +3105,7 @@ "status": "partial", "scope": "game1", "owner": "simulator-infra", - "updated_at": "2026-05-12", + "updated_at": "2026-06-04", "blocked_by": [], "summary": "The bridge-cse lane did **not** execute the npc_buildings-array-removal increment. Reason: it is the highest-regression file in the lane (`game_state.gd`, touching the live world map which `project_standin_blockers_worldmap.md` already flags as fragile) and the increment requires the full `build-gdext.sh` + GUT + visual-verification cycle (screenshot tail, operator-gated). It was correctly the first-to-cut item under budget. Precise resume map for the next lane (verified by grep 2026-06-03):" }, diff --git a/.project/objectives/p2-65-extract-mc-state-crate.md b/.project/objectives/p2-65-extract-mc-state-crate.md index d73b069e..9748ccfd 100644 --- a/.project/objectives/p2-65-extract-mc-state-crate.md +++ b/.project/objectives/p2-65-extract-mc-state-crate.md @@ -608,31 +608,68 @@ the objectives index. The concurrent design-system lane's files `scenes/tests/ui_theme_proof.*`) were left modified/untracked and were NEVER staged — verified at every commit. -## Phase 7 resume note (the ONLY remaining bullet — start here next session) +## Phase 7 resume note (the ONLY remaining bullet — OWNER DECISION; premise revised 2026-06-04 Wave-D-cont) -**Goal (bullet 9 / closes p2-55f bullet 2):** add `mc_state::SimConfig` carrying -`combat_balance` (8-field `mc_core::CombatBalance`) + room for future global -config. Wire it ONCE at api-gdext extension registration; have `GdGameState::init` -populate `self.inner.combat_balance` from it. Today every ephemeral `GdGameState` -instantiates a fresh default and discards `combat_balance` — this is the -no-persistent-`GdGameState` constraint that triggered the whole objective. +**Status of bullet 9: OPEN. K stays 8/9 → `partial`.** Do NOT close it by +pointing at the existing `set_combat_balance_json` path (see "stale premise" +below) — that path never touches mc-state and so cannot be cited as mc-state's +proof-of-value. Closing bullet 9 on it would be the objective-integrity §15 +reframe forbidden by the rail. Bullet 9 is genuinely larger than a mechanical +close-out, and its original justification has changed — so this session +deliberately leaves it `partial` (the brief pre-authorized exactly this: "if the +last bullet is genuinely larger than a close-out, leave honest partial with a +precise note"). -**Steps:** +**STALE PREMISE (the load-bearing 2026-06-04 finding — verified read-only):** +The earlier resume note claimed "every ephemeral `GdGameState` instantiates a +fresh default and discards `combat_balance` — the no-persistent-`GdGameState` +constraint that triggered the whole objective." **That constraint no longer +holds.** The persistent singleton EXISTS and the value IS delivered at boot: + +- `src/game/engine/src/autoloads/game_state.gd:269` → + `_load_combat_balance_into(_gd_state)` (the persistent `_gd_state` singleton, + not an ephemeral instance) → `:238 _gd_state.set_combat_balance_json(raw)`. +- `api-gdext/src/lib.rs:3541 fn set_combat_balance_json` parses via + `mc_turn::combat_balance::load_combat_balance` and writes + `self.inner.combat_balance = cb`. +- The DRIVER objective **p2-55f** is already `status: done`, and **its bullet 2 + ("DataLoader / GameState init reads `combat_balance.json` and populates the + field at game start") is marked `[x]`** with cited end-to-end evidence + (`p2-55f` line 23 + the passing test + `combat_balance_json_load_threads_nondefault_duration_into_game_state`). + +So the *outcome* p2-65 bullet 9 was meant to unblock is already delivered, by a +path that routes api-gdext → mc_turn → mc_core and **bypasses mc-state entirely.** + +**What bullet 9 actually still asks for (and why it's an owner decision):** +bullet 9 is p2-65's "proof-of-value that retroactively justifies the crate +split." Satisfying it on its own terms means making mc-state OWN the global +sim-config surface: introduce `mc_state::SimConfig { combat_balance: +mc_core::CombatBalance, … }`, route the boot load through it, and retire the +ad-hoc `set_combat_balance_json` setter in favour of the mc-state-owned config. +That is an **architectural consolidation of an already-working path**, not a +missing capability — a stale-premise refactor whose original urgency has +evaporated. It is the OWNER's call whether mc-state should own global config at +all now, or whether bullet 9 should be re-scoped/struck given the driver closed +independently. Do NOT unilaterally build `SimConfig` to satisfy a literal reading +of a resume note written under a premise that no longer holds; do NOT +unilaterally close the bullet either. Surface to the objective owner. + +**If the owner elects to build it** (the original `SimConfig` design, now purely +for architectural consolidation, not to unblock anything): 1. New `mc-state/src/config.rs`: `pub struct SimConfig { pub combat_balance: mc_core::CombatBalance, … }` + `Default`. Re-export `mc_state::SimConfig`. -2. api-gdext registration (`lib.rs` `#[gdextension]` init or a `GdSimConfig` - singleton): load `combat_balance.json` via DataLoader once, build `SimConfig`. -3. `GdGameState::init` (or the `GameState` constructor it calls) reads the - singleton and sets `self.inner.combat_balance`. -4. **Risk (from §Risk register):** if the singleton is a `OnceCell`, cargo-test - parallelism may fight it. Mitigate by giving `GameState` a - `with_combat_balance(cb)` constructor for tests and reserving the `OnceCell` - for the api-gdext path only. +2. api-gdext: load `combat_balance.json` once into `SimConfig`; have + `GdGameState` pull from it instead of the standalone setter. +3. Retire `set_combat_balance_json` (route through `SimConfig`) — full removal, + not a parallel path (Zero-Tech-Debt rail). +4. **Risk (§Risk register):** `OnceCell` vs cargo-test parallelism — give + `GameState` a `with_combat_balance(cb)` ctor for tests; reserve the + `OnceCell` for the api-gdext path only. +5. **Gate:** trio (`serde_roundtrip` + `full_turn_golden` + parity) + + `cargo build -p api-gdext` + an api-gdext test asserting a loaded + `combat_balance.json` reaches `state.combat_balance` THROUGH `SimConfig`. + Only then bullet 9 ✓ → flip `partial` → `done` and regen the index. -**Gate:** the same trio (`serde_roundtrip` + `full_turn_golden` + parity) + -`cargo build -p api-gdext` + a check that a loaded `combat_balance.json` actually -reaches `state.combat_balance` (assert in a new api-gdext test). When green and -bullet 9 ✓ → flip status `partial` → `done` and regen the index. - -**Effort:** S–M, ~half a session. Discrete design work — do NOT bundle with other -objectives. It is the proof-of-value that retroactively justifies the crate split. +**Effort:** S–M, ~half a session of discrete design work — do NOT bundle with +other objectives. Owner-gated by the premise change above. diff --git a/.project/objectives/p2-72a-building-entity-port.md b/.project/objectives/p2-72a-building-entity-port.md index 44b27a85..fea42ca8 100644 --- a/.project/objectives/p2-72a-building-entity-port.md +++ b/.project/objectives/p2-72a-building-entity-port.md @@ -7,7 +7,7 @@ scope: game1 category: architecture owner: simulator-infra created: 2026-05-11 -updated_at: 2026-05-12 +updated_at: 2026-06-04 blocks: [p2-72a-save-format-migration, p2-72a, p2-72] --- @@ -461,3 +461,29 @@ All as ONE commit, then gate: **Blocker for next session:** none technical — needs a session with runway to build the Docker godot image + warm the import cache, and an operator present for the visual-proof sign-off. + +## 2026-06-04 Wave-D continuation — array-removal STILL not executed (gate unreachable; clean stop re-confirmed) + +**Not advanced. `game_state.gd` UNTOUCHED. `grep -c npc_buildings game_state.gd` = 33 +(unchanged). Status stays `partial`.** This lane owned the increment and re-checked +gate feasibility before touching the highest-regression live-world-map file. The three +2026-06-04-session-2 blockers all REPRODUCE this session (verified, not assumed): + +1. **Godot import cache COLD** — `src/game/.godot/` absent (verified `ls`). A direct + flatpak `godot --headless --import` on this RUN host carries the documented + host-freeze risk: `scripts/godot-docker.sh:4-7` states cold `--headless --import` + "kernel-panicked plum twice and freeze apricot when run cold." The safe path is the + Docker runner. +2. **No `mc-godot` Docker image built** — `docker images` shows only unrelated + e2e/mailpit images; the freeze-safe `scripts/godot-docker.sh` path needs a heavy + cold image build + warm-import volume first (no `mc-src` warm volume exists). +3. **World-map visual proof is operator-gated** — phase-gate-protocol + + `feedback_phase_gate_screenshots` forbid self-approving the screenshot. No `$SCREENSHOT_HOST` + set and no operator present this session to sign off. + +Per never-regress: a tree with readers re-routed + serialize re-pointed but the array +delete ungated (no GUT-green, no operator visual sign-off) is worse than not starting. +Clean stop re-confirmed — the predecessor's execution recipe (above, §"Precise execution +recipe for the next session") is still the correct, complete plan; it remains blocked +solely on (a) runway to build the Docker godot image + warm the import cache, and (b) an +operator present for the visual-proof sign-off. No code or recipe change needed.