From 5c578e0d01e7975da163ef55323e6fa64f67668e Mon Sep 17 00:00:00 2001 From: autocommit Date: Thu, 4 Jun 2026 20:06:53 -0700 Subject: [PATCH] =?UTF-8?q?docs(p2-72a):=20=F0=9F=93=8B=20scope=20array-re?= =?UTF-8?q?moval=20increment=20+=20correct=20the=20save-format=20coupling?= =?UTF-8?q?=20claim?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- .project/objectives/objectives.json | 2 +- .../objectives/p2-72a-building-entity-port.md | 72 +++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/.project/objectives/objectives.json b/.project/objectives/objectives.json index 8437ee4f..c11a894a 100644 --- a/.project/objectives/objectives.json +++ b/.project/objectives/objectives.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-06-05T02:59:51Z", + "generated_at": "2026-06-05T03:06:38Z", "totals": { "done": 243, "in_progress": 1, diff --git a/.project/objectives/p2-72a-building-entity-port.md b/.project/objectives/p2-72a-building-entity-port.md index 5b35226b..44b27a85 100644 --- a/.project/objectives/p2-72a-building-entity-port.md +++ b/.project/objectives/p2-72a-building-entity-port.md @@ -389,3 +389,75 @@ migration, not a demo feature. **Effort:** M — the array-removal increment is ~1 session but requires the full build+GUT+visual cycle and is gated behind the save-format GDScript side. + +## 2026-06-04 Wave-D session 2 — array-removal increment SCOPED, not executed (clean stop) + +**Not advanced — deliberately stopped after the disqualifier checks. Rust surface +unchanged; `game_state.gd` UNTOUCHED. Status stays `partial`.** + +### The load-bearing NEW finding — the "forces SaveManager rewrite" blocker is OVER-STATED + +The 2026-06-03 resume map (step 3) claims array removal "forces the SaveManager +rewrite" and so "cannot fully land independently of Stage 3's GDScript side." +**Verified false by reading the serialize chain (read-only, no edit):** +- `game_state.gd:699 _serialize_npc_buildings()` → `SerializationHelpers.serialize_npc_buildings(npc_buildings)`. +- `game_state_serialization_helpers.gd:9-14`: that helper iterates the array and calls + `b.to_dict()` on each element. +- Each element is a `BuildingScript.new(self, i)` view (`game_state.gd:541`), and + `building.gd`'s `to_dict()` proxies to `_gd_state.npc_building_dict(_idx)` — i.e. the + serialized bytes are **already sourced from the Rust mirror**, not from any + GDScript-owned field. + +**Therefore re-pointing serialize at the Rust mirror directly (iterate +`range(_gd_state.npc_building_count())` → `npc_building_dict(i)`, or +`npc_buildings_all()`) is byte-identical** — the save FORMAT does not change, only the +(now-redundant) GDScript array indirection is dropped. This is NOT save-format-migration +scope; **this objective owns the whole increment.** Brief and objective reconcile. + +### Why it was still STOPPED this session (gate-feasibility, not coupling) + +The increment edits the highest-regression live-world-map file and per never-regress +must land as ONE green commit gated by GUT-headless + cargo + build:gdext + an +operator-gated world-map visual proof. Three blockers to gating *this session*: +1. **Godot import cache is COLD** (`src/game/.godot/` absent). `scripts/godot-docker.sh` + documents that a cold `godot --headless --import` "kernel-panicked plum twice and + freezes apricot when run cold" — so a direct flatpak GUT run on this RUN host carries + a host-freeze risk. The safe path is the Docker runner, but **no `mc-godot` image is + built and no warm-import volume exists** — first-run is a heavy cold build. +2. **Committed `.so` (2026-06-03 22:16) predates a clean `./run build:gdext`** — a proper + gate wants a fresh rebuild first (the Phase-4 refactor was import-path-only so the + `GdGameState` accessor surface is behaviourally identical, but gating should not assume). +3. **The world-map visual proof is operator-gated** — cannot be self-approved (phase-gate + protocol + `feedback_phase_gate_screenshots`). + +A half-routed tree (readers moved, serialize re-pointed, but array delete ungated) is +worse than not starting. Clean stop is correct. + +### Precise execution recipe for the next session (with runway + Docker warm) + +All as ONE commit, then gate: +1. **Re-point serialize:** `_serialize_npc_buildings()` → + `SerializationHelpers.serialize_npc_buildings` reads from + `range(_gd_state.npc_building_count())` / `npc_building_dict(i)` instead of the array. + (Byte-identity proven above — confirm with a save→reload→save byte-diff in GUT.) +2. **Route the 6 direct readers** off `GameState.npc_buildings` / + `get_npc_buildings_at()` onto `_gd_state` accessors: + `modules/ai/wild_creature_ai.gd:56,148`; `modules/management/rust_fauna_integration.gd:76`; + `rendering/lair_overlay_renderer.gd:43`; `map/entity_finder.gd:161`; + `generation/village_lair_placer.gd:53` (already uses `get_npc_buildings_at` → + swap to `_gd_state.npc_building_at`); `entities/building.gd` is itself the view (keep + thin or delete + inline `npc_building_dict`). Mind reader dict-shape compatibility + (tuple extraction vs Vector2i) — each reader uses the data differently. +3. **Delete** `game_state.gd:113 npc_buildings`, `:115 _npc_buildings_by_tile`, + `:530 _rebuild_npc_buildings_view()`, `get_npc_buildings_at`/`get_all_npc_buildings_of_type` + (or re-point them at the Rust spatial index `npc_building_at`), and the reset lines + `:263-264`. Remove `_rebuild_npc_buildings_view()` calls at `:492,:526,:729`. +4. **Gate:** `./run build:gdext` → warm import via `scripts/godot-docker.sh --headless + --import` (Docker, freeze-safe) → GUT headless (the entities + serialization suites) + → `./run screenshot` world-map proof → read it back + present for operator sign-off. + Do NOT flip the visual-dependent bullets ✓ unilaterally. K rises ~5/11 → ~8/11; + objective stays `partial` until the save-format-migration + render-source bullets close. + +**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.