Vertical slice completion (PROCEED), Art Bible, and Pre-Production propagation - #111
Open
CryNoxTheKid wants to merge 312 commits into
Open
Vertical slice completion (PROCEED), Art Bible, and Pre-Production propagation#111CryNoxTheKid wants to merge 312 commits into
CryNoxTheKid wants to merge 312 commits into
Conversation
… 'missing faces' cause User: 'nothing changed at all' after every mesh/look fix — because it was never the mesh. The orbit camera's target sat at a FIXED height (y=10) and nothing kept the EYE out of the terrain: panning/zooming toward any raised terrace put the camera INSIDE the hill, and a backface-culled voxel world viewed from inside reads exactly as reported — 'only outer faces render, see through to bedrock', while top-down views look perfect. None of the mesh audits could catch it (mesh and data were always correct). Fix: camera target now rides the terrain surface (height provider wired from GameWorld) and the eye is clamped >= 2 cells above the terrain at its own footprint. LOOP_TEST PASS. Task: Roadmap Step 2 — Vertical Slice (user-found defects) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…onts are CLOCKWISE
User diagnosis was correct all along ('you only render the inner faces'):
the mesher wound every face counter-clockwise-outward (OpenGL front-face
convention), but Godot treats CLOCKWISE as front — cull_back therefore hid
the OUTSIDE of everything. All prior symptoms were this one bug seen from
different angles: see-through cliffs, hollow trunks, inside-out canopies,
'floating' lip faces (inner surfaces of far walls), 'nothing ever changes'
(every fix polished the visible subset). All audits passed because they
validated winding against the mesh's own stored normals — self-consistently
wrong, never against the engine convention.
Fix: cull_mode = CULL_DISABLED on the world material (immediate, correct
from every angle; ~2x face cost absorbed by the 10x frame headroom).
Follow-up noted for REPORT/production: rewind faces to Godot's clockwise
convention and re-enable culling; audit rule = validate winding against
ENGINE convention, not self-stored normals. Also: 8-cell terrace steps
(4-cell steps were perceptually invisible from the colony camera).
LOOP_TEST PASS.
Task: Roadmap Step 2 — Vertical Slice (user-found root cause)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Characters are now 2 blocks tall (capsule 1.4+head; walk clearance stays 3, logic untouched) — blocks read smaller, world reads bigger. Landforms widened (continent freq 0.0022, core plateau r=60 blend to 150, tree clearing r=70), trees taller (trunks 4-6). Three villagers spawn (Hilda, Bruno, Mira) and breathers are rarer/shorter (8 jobs before break, 40 ticks) — 'they should work more': hut build time in the loop test dropped from ~3400 to 650 ticks. Camera default distance 24. Loop test expects 3 villagers. GDD propagation notes (production): character scale 2 blocks, bed footprint 2 cells (multi-cell furniture), 16k world. LOOP_TEST PASS. Task: Roadmap Step 2 — Vertical Slice (user direction: scale + industry) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
User request for the testing phase: toggleable overlay (F3) showing performance (FPS, frame/physics ms, draw calls, triangles, RAM/VRAM, node count), simulation state (pause/warp, chunk count, camera position), building state (blueprints/claimed/furniture/tool), per-villager rows (state, cell, sleep, mood band, distress) and a timestamped event log (construction, furniture, invalid commits, rooms, warnings, state and distress changes). Wall-clock refresh, read-only taps on public APIs. First live numbers: 240 fps, 6.4 ms frame, 265 draws, 84k tris — well inside every budget. LOOP_TEST PASS. Task: Roadmap Step 2 — Vertical Slice (test tooling) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ats line User request for better simulation testing: TimeTickSystem gains warps 10 and 20 (HUD speed radio picks them up automatically; +/- keys step through the warp list), a lifetime tick counter drives a sim clock, and the time-controls panel shows a live stats line (sim time, villager count, beds, open build jobs). Note: at 20x (80 ticks/s) the 10-ticks-per-frame cap engages below ~120 fps — excess sim time is discarded by design (GDD tick-cap rule), fine for testing. LOOP_TEST PASS. Task: Roadmap Step 2 — Vertical Slice (test tooling) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ed inline literals User crash on Block tool after building: _render_tool_preview demanded Array[Vector3i] but call sites pass '[cell] if valid else []' inline literals (plain Array). Param untyped with rationale comment. LOOP_TEST PASS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t, flush floors User direction: (1) BUILD/EDITOR MODE — 'Bauen' master toggle in the HUD; tools arm only inside build mode (arming auto-enters), Esc chain exits the mode last; outside it clicks stay with villager selection. (2) DRAFT-FIRST — blueprints are drafts (alpha 0.30) villagers ignore; 'Bau starten (N)' releases them (alpha 0.45) to the job queue. (3) FLUSH FLOORS — floor drags starting on terrain replace the picked surface plane (dips fill), undo restores captured pre-values (restore_value) instead of assuming AIR. Loop test releases drafts explicitly + asserts the release count. CONTRACTS.md updated with the new APIs. LOOP_TEST PASS. GDD propagation notes: building-ui Rule 1 (mode), building-system Rules 4/5 (excavation, draft phase), voxel-world terrain-removal exception. Task: Roadmap Step 2 — Vertical Slice (user direction: build workflow) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ndow
Stonehearth-style building entities (user decisions 2026-07-22):
contiguous draft cells (26-neighborhood, batch-merge) group into
projects with states DRAFT/BUILDING/PAUSED/DONE. Per-project release
('Bau starten'), pause/resume, cancel/demolish (un-builds via
restore_value). claim_job gated on BUILDING + tracks claiming
villager; projects expose worker_ids. HUD: projects panel
(bottom-left cards: status, progress bar, workers, state buttons)
replaces the global release button. release_drafts() kept as compat
wrapper. Loop test asserts 1 merged DRAFT project for the hut,
BUILDING on release, DONE with full built count; bed is its own
project. Resource costs deferred to Production (user decision).
LOOP_TEST PASS.
Task: Roadmap Step 2 — Vertical Slice (user direction: build projects)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ixes
User direction (2026-07-22): (1) DRAFT ERASER — removal tool in build
mode erases DRAFT-project blueprint cells instantly (carve a door gap
out of a drawn wall); (2) TERRAIN DIG ORDERS — removal tool over
terrain (1..5) creates dig projects ('Abbau N', red ghosts); villagers
excavate after release through the same claim/write pipeline,
restore_value undo/cancel; (3) GHOST SNAPPING — raycast_cells gained
an extra_solid predicate so picking anchors on blueprint ghosts (roof
on drafted walls). Fixes: water no longer solid for picking; removing
a floor-replace block restores terrain (restore_value) instead of
carving a hole — the reported 'invisible floor' cause (chunk-boundary
remesh was already correct; chunks are full-height XZ columns);
dig jobs exclude the stand-on-target onsite offset (villager dug the
block under its own feet and got trapped). LOOP_TEST PASS with new
eraser/dig/regression assertions.
Task: Roadmap Step 2 — Vertical Slice (user direction: editor feedback)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…house tools User-prioritized UX package (brainstorm 2026-07-22): (1) HOVER HIGHLIGHT + BUILD GRID — wireframe box + face quad on the cell a click would affect (reuses the pick raycast), 9x9 terrain grid overlay around the cursor in build mode. (2) SLICE VIEW (Timberborn-style) — chunk material converted to ShaderMaterial (chunk_terrain.gdshader: atlas + vertex-AO + y_cut fragment discard, no remesh needed); PageUp/PageDown/Home + HUD 'Ebene' controls; ghosts/highlight filtered, villagers hidden above the cut. (3) ROOM TOOL (Raum, key 6) — ground rect drag -> perimeter walls at wall height with auto door gap on the camera-facing edge. (4) AUTO-ROOF (Dach, key 7) — one click roofs the clicked project's bbox at top height (thatch), joins the same project. (5) HOUSE TEMPLATE (Haus, key 8) — 7x7 starter house stamp (flush floor, walls + door gap, roof) as one draft project; known limitation: redo after undo rebuilds only single-material batches. hud.setup gained voxel_world param; CONTRACTS.md updated. LOOP_TEST PASS incl. new room/roof/house/slice assertions. Task: Roadmap Step 2 — Vertical Slice (user direction: build UX) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n check _uniform_cell_values (new in the UX package) required Array[Vector3i], but _render_tool_preview deliberately passes plain Arrays (same class as the c05e4a1 crash). Untyped the param and added a loop-test regression call that drives the preview path with plain Arrays so the headless gate catches any retyping (runtime type errors surface as SCRIPT ERROR in the gate grep). Task: Roadmap Step 2 — Vertical Slice (user crash report) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n + ghost visuals User decisions 2026-07-23: (1) grid lines ~30% alpha; ghosts full texture at 0.50 draft / 0.70 released (ghost-face audit: no culling bug — low alpha was the culprit; DEPTH_DRAW_ALWAYS added for sort stability); inflated overlay markers on affected terrain (orange = floor-replace, red = dig/demolition). (2) Projects persist after DONE; clicking any project cell (any mode, no tool armed) selects it — panel card gold-highlighted + scroll-into-view, cyan wireframe outline in world, Esc deselects before exiting build mode. (3) Change orders: new drafts adjacent to BUILDING/PAUSED/DONE projects ATTACH to them (reverses the old no-absorb rule); 'Änderungen geplant' status + per-project release. (4) Rückbau nur über Aufträge: removal tool on built project cells creates demolition orders (released -> villagers tear down block by block, restore_value honored); cancel/Abriss converts built cells to released demolition orders, project vanishes only when empty; undo/redo touch PLAN entries only — never built cells. Loop test: persistence, change-order, demolition, undo-safety, selection assertions. LOOP_TEST PASS. Task: Roadmap Step 2 — Vertical Slice (user direction: persistent projects) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
User scope decision 2026-07-23 (safety net, not build-order planning): (1) WATCHDOG: villagers with no legal step (or non-standable cell) while TRAVELING/WORKING for 12 ticks (~3s) are teleported to the nearest standable unoccupied cell; claimed job released back to the queue; villager_unstuck signal + total/per-villager telemetry in the F3 console event log (data collection for the Production fix). (2) SEAL PREVENTION: report_on_site refuses a build write that would leave the builder with zero legal steps — claim released for an outside villager; livelock guard allows the write after 3 abandons by the same villager (watchdog rescues). Digs/demolitions exempt. Loop test: burial-rescue + mock-corridor seal-refusal assertions; a real watchdog rescue fired during the E2E build itself. LOOP_TEST PASS. Production follow-ups (GDD list): build-order planning, scaffolding, stuck telemetry requirement. Task: Roadmap Step 2 — Vertical Slice (user direction: anti-stuck) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Slice concluded 2026-07-23 after user debrief: full build->furnish-> live loop validated (headless gate green every commit), feasibility ~1 feature package/day over 5 active build days. Experience gaps for Production: loop payoff under-communicated, atmosphere/mood weakest axis (primary Art Bible input). Tester-prioritized frictions: worker intelligence, build comfort, world content, performance/16k world. README status Concluded + findings; prototypes/index.md gains the Vertical Slices table. CD-PLAYTEST skipped (lean review mode). Task: Roadmap Step 2 — Vertical Slice (Phase 5-6 wrap-up) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
S5 Characters (2-block chibi, personal accent colors, Corruption enemy hue, personality via motion), S6 Environment (northern homestead vernacular, no-PBR rule, Ambient Life & Motion table with confirmed first wave: smoke/foliage-sway/idle-behaviors/clutter/torch-flicker — direct answer to the slice debrief's 'mood lacking'), S7 UI/HUD (ux-designer conflict pass resolved: Hearth Gold dual-channel, red->State Orange with mandatory shapes, Dusk Test QA gate, typography + panel anatomy, open handoffs incl. projects-panel UX spec), S8 Asset Standards (16px texel tier + 16 voxels/cell user decisions, naming, palette bands, review checklist + technical constraints: measured draw-call ledger ~1293/2000, 16k world flagged as a STORAGE problem for the ADR-0014-successor spike, reject-if gate), S9 Style Prohibitions (16 rules, each traced to a locked rule or a lived incident). Seven user taste decisions recorded inline. AD-ART-BIBLE gate skipped (lean mode) — required before the Production gate. Task: Pre-Production — Art Bible completion (post-slice, REPORT.md input) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 1 of the slice propagation batch (source: REPORT.md + user playtest decisions 2026-07-12…23). All changes tagged '(Slice revision 2026-07-23)', existing requirement IDs untouched. - game-concept: 16,000x16,000x32 production target (gated on the storage/streaming spike — ~11 GB naive, 3x over the 4 GB ceiling; a storage problem, not rendering), 2-block character scale. - voxel-world (TR-050..053): floor terrain-replace with restore_value, villager-executed terrain dig orders, CW-winding+culling hard requirement (CULL_DISABLED documented as temporary), 16k scope note. - building-system (TR-102..126, AC52..77): build/editor mode, draft-first blueprints grouped into persistent BUILD PROJECTS (26-neighborhood merge, per-project release/pause/cancel, worker attribution, change orders, click-selection), job-gated demolition + Abriss, plan-only undo/redo, floor excavation, dig/mining projects, draft eraser, multi-cell furniture, higher-level tools contract, door/window items + worker-safety/telemetry forward requirements. Flagged judgment call: furniture removal stays instant (carve-out). - building-ui (TR-075..088): build-mode toggle + Esc chain, click routing, ghost-anchored picking, hover highlight + grid, ghost alpha-as-commitment, replace/dig markers, room/roof/house tools, slice view, projects panel (layout provisional pending design/ux/projects-panel.md), door-gap affordance, undo scope. - villager-ai-behavior (TR-097..109): claim attribution, 2-cell body column naming, unstuck watchdog + rescue BFS, seal prevention + livelock escape, dig on-site exclusion, telemetry as sizing input for production build-order planning/scaffolding. Flagged: GDD tick-rate (2.0) vs slice tick-rate (4.0) discrepancy. - resource-item-database (TR-052..054): furniture footprint field (bed 1x2) + boot validation; cost field anticipated, not designed. - design/registry/entities.yaml: bed footprint, watchdog/seal constants. Task: Pre-Production — slice propagation Phase 1 (GDDs) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dates, ADR-0015/0016 Change-impact report (change-impact-2026-07-23-slice-batch.md) with per-ADR assessment: 9 ADRs unaffected, 5 updated in place — ADR-0009 (body-column occupancy, watchdog teleport as second sanctioned discrete mutation, seal-prevention consumer), ADR-0010 (Build-Mode- gated click routing + villager/project selection arbitration), ADR-0014 (CW winding + culling-enabled hard requirement, extra_solid picking predicate ownership, boot-allocation clause under ADR-0015 review), ADR-0012/0013 (impact notes gated on ADR-0015). NEW ADR-0015 Large-World Storage & Residency — PROPOSED pending the storage spike (user decision: paged region-file residency as the load-bearing mechanism, sparse far-terrain regen as fast-follow within it, compression-only rejected). Five measurable spike pass criteria encode the Accept gate (page-in latency, flat memory over a 16k traverse, write-to-unloaded correctness, eviction under budget, region-file save round-trip). NEW ADR-0016 Build Project Entity Lifecycle — ACCEPTED (prototype- validated; cites slice commits + REPORT.md): draft/release/pause/ done + job-based demolition incl. furniture, 26-neighborhood merge, change orders, worker attribution, plan-only undo, reverse-index selection, persistence-until-empty. User resolutions applied: ticks_per_second 2.0 -> 4.0 authoritative (time-tick-system.md + registry; re-tuning pass tracked as Open Question — per-tick rates now ~2x real-time), furniture removal job-gated (building-system.md TR-127, atomic multi-cell demolition). requirements-traceability.md + tr-registry.yaml (528 entries) updated; technical-preferences ADR log extended. Task: Pre-Production — slice propagation Phase 2 (architecture) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New design/ux/projects-panel.md (Draft, pending /ux-review): claims HUD zone Z7 (bottom-left, villager-panel baseline lifted above it), tier-first sort (BUILDING > PAUSED > DRAFT > DONE+changes > settled), bounded visible cards (6) with issues-anchor-style overflow row, selected card always pinned, no-modal Abriss policy (job-gated delay substitutes for friction, revisit with economy), state shape proposals for the Art Bible §7.3 shape-budget table, 9 tracked open questions (incl. required hud.md Z7/visual-budget follow-up edit). Task: Pre-Production — projects-panel UX spec (Art Bible §7.6 / TR-building-ui-086) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
/ux-review first pass: NEEDS REVISION (0 blocking, 4 advisory). Applied: States & Variants section with explicit no-loading-state rationale; Abriss/Abbrechen irreversibility note (no undo entry for Built cells, TR-building-ui-088/TR-building-system-119) in Confirmation Policy, Interaction Map and Events Fired; priority- tiered bounded list + Selection Pin flagged as candidate interaction-patterns.md entry; Z4/Z7 baseline claims separated. Re-review verdict: APPROVED (0/0). Ready for /team-ui Phase 2. Task: Pre-Production — projects-panel UX spec (review cycle) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paged region-file residency prototype for the 16k world (synthetic 16,000x16,000x32, real slice terrain-gen cost). Round 1 (fixed 2-items/frame budget, 120 c/s): C3/C5 PASS (byte-identical write and save round-trips; save 4.76MB vs 7.63GB naive — ~1600x; 99.5% of page-ins regen from seed), C1/C2/C4 FAIL (backlog under 12x demand). Round 2 (time-based 4ms budget + capped async prefetch, measured at the REAL max camera speed 144 c/s derived from camera_input.gd, and 120 c/s): C2 now PASS and flat (39-44MB peak), C1/C4 remain FAIL narrowly — single indivisible work items (15-17ms chunk regen, 48.6ms disk op) exceed a frame alone; 2.3ms over at 120 c/s. Found and fixed an unbounded async-dispatch defect (10.1s hitch) via MAX_CONCURRENT_ASYNC_TASKS=16. Spike verdict: architecture validated (residency, region files, load-before-write, sparse regen, save format); remaining C1/C4 is a tuning problem (async cap, bounded per-chunk gen cost), not an architecture problem. Full data in results/storage_residency_spike.csv; findings in README.md. Task: Pre-Production — ADR-0015 acceptance gate spike Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Decisive lever: NO synchronous fallback anywhere — a chunk the async pool cannot take stays queued instead of running on the main thread. Worst frame drops to a uniform 12.0-14.5ms across all four speed(144/120 c/s) x cap(32/64) combos; io_worst/regen_worst 0.00ms by construction. Async eviction writes with a read-through in-flight cache close the disk tail (48.6ms -> 0) and a real race (chunk re-needed mid-flush must be served from memory). Cap size stopped mattering once the fallback was gone (32 vs 64: ~0.3ms). C2 flat 44-84MB; C3 20/20; C5 40/40 (0.77MB vs 7.63GB naive). All five ADR-0015 validation criteria PASS at the game's real max camera speed (144 c/s, derived from camera_input.gd) — Accept recommended with time-based budget clause, no-sync-in-frame-path rule, read-through-cache edge case, and one-time region-header I/O noted. Task: Pre-Production — ADR-0015 acceptance gate spike (round 3) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Spike evidence (afb609c, 799ddbc): all five validation criteria PASS at the real max camera speed (144 cells/s, derived from camera_input.gd) and 120 c/s, async caps 32 and 64. Four validated clause updates applied: time-based page/evict budget (4.0ms), NO synchronous disk I/O or terrain-gen in the per-frame path (the sync fallback was the failure mode), read-through in-flight-write cache as a load-before-write edge case, one-time region-header I/O noted as the accepted sync exception + completion-driven drain loop for production. ADR-0014's full-world-at-boot clause formally superseded. ADR-0012 resolved: save format = region files (Alt-C escape hatch exercised via 0015). ADR-0013 resolved: offset stays 100_000 — absolute gap 84,000 units vs the 16k span; increasing it trades imperceptible for perceptible float32 ULP jitter. ADR log updated. Task: Pre-Production — ADR-0015 acceptance (spike-gated) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… AD sign-off APPROVED Full gate run (lean mode, all four directors): CD/TD/PR/AD all CONCERNS, none NOT READY. Validation artifacts all pass (slice PROCEED, 16 ADRs Accepted, art bible signed off — AD-ART-BIBLE APPROVED recorded retroactively in the bible header during the AD panel). FAIL is the missing planning layer only: control-manifest refresh (stale, pre-0015/0016), Production milestone + estimate re-baseline with slice velocity, epics+stories, main-menu/pause-menu UX specs, first sprint plan. Non-blocking: external playtests before scope lock, /asset-spec inventory, ambient-life wave 1 + loop-payoff as early stories. Producer panel's stale ADR-0015 claim corrected in the report (Accepted, spike-validated). Chain-of-verification: 5 questions, 3 tool actions, verdict unchanged. Task: Pre-Production — gate check (Pre-Production -> Production) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…, epics, menu specs Pre-Production->Production blocker path items 1-4 (gate report 2026-07-23): (1) control-manifest.md refreshed to 2026-07-23 — ~39 new/expanded rules from ADR-0015/0016 + slice-propagation amendments (never sync I/O in frame path, built cells job-only, CW winding, body-column occupancy, engine facts). (2) Milestone 01 Foundation+Core (~22 expected days, 13 exit criteria, CD-protected items + all three tech debts in scope; loop-payoff mechanic deferred to M02 with rationale) + estimate re-baseline: 32 expected days (26-42) vs the uncalibrated 38d, slice-velocity-derived. (3) Epics: 6 Foundation (incl. cross-cutting foundation-spine) + 2 Core, each with governing ADRs, engine risk, M01/M02 tags; ambient-life + loop-payoff deliberately NOT force-fitted (tracked in index for a Presentation pass). (4) main-menu.md and pause-menu.md authored and APPROVED via /ux-review fix cycles (notable: overwrite-modal default focus safety rule, E11 dim supersession, Esc-chain 5th-step proposal flagged for propagation, three-spec confirmation-policy set flagged for one pattern-library entry). Remaining for the gate: stories per epic, sprint plan. Task: Pre-Production — gate blocker path (items 1-4) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…stories /create-stories passes across the M01 epic set (manifest 2026-07-23 embedded, slice code declared reference-only, GdUnit4 evidence paths, dependency-ordered): foundation-spine 5, scene-world-management 3 (boot-vs-menu conflict carried as NEEDS-DECISION, not a block), time-tick-system 7 (re-tune story with cross-epic coordination flag), resource-item-database 9 (footprint TR-052..054), voxel-world 17 (CW-rewrite, fresh ADR-0015 residency in 5 stages, C1/C4 tuning, TR-050/051 write paths), camera-input 9 (extra_solid contract, pause-halt note), building-system 33 (Block A pre-slice foundation 019-033 build-first + Block B slice block 001-018 with explicit depends-on graph; TR-102..127 fully covered), villager-ai-behavior 25 (all determinism ACs as same-seed tests; watchdog telemetry). Cross-epic sequencing flags recorded (camera before residency, 16k config-gated until measured, save/load VS-tier). tr-registry TR-123 stale instant-removal clause corrected (superseded by TR-127). Task: Pre-Production — gate blocker path item: stories Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sprint 1 (production/sprints/sprint-01.md + sprint-status.yaml): goal = Foundation spine boots behind the RID gate + three track- starters; 8 stories (5 Must: spine-001/002/003, rid-001/002; 3 Should as cut lever: tick-001, cam-001, vox-001), 10 days with an explicit 20% buffer absorbing the measured wiring overhead; risks carried in-doc (single-specialist throughput, quality-bar delta, NEEDS-DECISION on scene-world 001 deferred to S2, re-tune halves deferred to the integrated build). Gate report addendum: all five blockers resolved same-day -> Final Verdict PASS. Forward recommendations: /qa-plan sprint before /dev-story, external playtests before scope lock, /asset-spec inventory. Task: Pre-Production — gate blocker path complete Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gate 2026-07-23 re-check PASS (all five blockers resolved same-day, AD-ART-BIBLE APPROVED, director panel 4x CONCERNS / none NOT READY). User-confirmed stage advance. Task: Production entry Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lete Story: foundation-spine story-001 (EPIC foundation-spine) GameWorld root scene + injected-tier DI scaffold per ADR-0001/0005: @export injected_tier_modules array, explicit setup() invocation from the orchestration root (never _ready() ordering), ReferenceInjectedModule as the canonical module shape (typed @export deps, setup() asserts, no _ready() override). Establishes neues-spiel/src/<module>/ layout. Tests: 7 new (3 integration DI-scaffold + 4 unit reference-module), full suite 10/10 green headless, parent-verified (exit 0). Guardrail greps clean (no Autoload @export injection, no _ready() dependency reads). One-time global class-cache rebuild documented as a CI note. Also: QA plan sprint 1 (production/qa/qa-plan-sprint-1-2026-07-23.md — 8/8 stories classified, all BLOCKING, smoke scope defined) and test-evidence paths normalized to neues-spiel/tests/ across story files (QA-plan finding). Story status Complete; sprint-status updated. Task: Sprint 1 — spine-001 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r-only view Story: resource-item-database story-001 (Sprint 1) ItemDefinitionResource (11 @export schema fields incl. footprint Vector2i) + ItemDefinition getter-only RefCounted wrapper per ADR-0006 (wraps, never copies; zero setters; Object.get()/set() reflection bypass documented as accepted residual risk). 3 unit tests at the QA-plan evidence path; setter check scoped to the class's own declared API via get_script_method_list() (inherited engine set_* methods excluded — documented test fix). Full suite 13/13 green headless, parent-verified. Task: Sprint 1 — rid-001 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The settlement and player-view captures re-taken after vox-022/vox-023, with the persisted regions cleared first so no stale single-colour chunk could page in and make the picture lie. These are the frames behind decision D12: four terrain colours genuinely render, and the composition is wrong — grey and pale peak dominate where a valley should be green, because D11's provisional band anchoring puts the boundaries at [2,4,5] in a world whose columns top out at y=7. The lever passed; the picture did not. Both are true and both are recorded. Task: Sprint 12 — evidence refresh Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Story: villager-ai story-024 — the blocking defect filed this morning A room drawn through the hosted WallTool now reaches FULL ENCLOSURE. Verified directly: wall_room_no_plateau_test PASSED, and an isolated column completes at the shipped height of 3 AND at 6, so the fix is structural rather than tuned to one height. THE RULE, confirmed empirically and not merely theorised: VillagerNavGraph can never connect two cells in the same column. A step is defined as inherently horizontal, and is_standable requires the cell below to be solid — so two stacked cells can never both be standable graph points at once. A wall's layer 2 is reachable from always-standable ground in one combined step. Layer 3 needs a second such extension, but its only same-column neighbour at the required height is layer 2's own cell, which goes solid and leaves the graph in the SAME patch_cells call that adds layer 3. Layer 3 enters as an ISOLATED point: has_point true, find_path from every occupied cell returns [] on every tick up to 5000. Job selection excludes it before any claim — which is exactly why the stuck cells read PLANNED, claimed_by -1, abandon_count 0. This also refutes Sprint 12's spike-plateau hypothesis, which assumed seal-prevention refusals. That path is never consulted at all. PLATEAU-CHECK cell=(2, 1, 3) state=2 claimed_by=1 abandon_count=0 PLATEAU-CHECK cell=(2, 2, 3) state=2 claimed_by=1 abandon_count=0 PLATEAU-CHECK cell=(2, 3, 3) state=0 claimed_by=-1 abandon_count=0 THE FIX IS SYMMETRIC: a builder standing where the graph cannot reach is moved discretely, at the two moments it happens — climbing ONTO the self-sealed cell, and stepping back DOWN when the column is done. The obvious alternative, widening stuck detection into WANDERING, was rejected: villager-ai-019 deliberately makes a walled-in wanderer STAY PUT, and a walled-in villager is indistinguishable from a stranded one by flood-fill alone. It reads as what a real builder does. ADR-0009's "two sanctioned mutation points" is amended, control-manifest follows. Seal prevention and the livelock escape are intact — 13/13 and 12/12, both suites unchanged. AND A DEFECT OF MY OWN, found here: payoff_loop_demo.gd has not PARSED since commit 6ddb153 — two while-true helpers with no trailing return, written by the scene-009 attempt and committed without the tool ever being load()-ed once. The tool that exists to catch "shipped but never run" was itself shipped and never run. Fixed, with the reason recorded at both sites. Its new roof stage is written but unexecuted, so AC5/AC6 ship as a named debt rather than a claim. Suite 1580/1580 green, parent-verified. Task: Sprint 12 — villager-ai-024 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
villager-ai-024's AC5/AC6 are RUN and NOT MET, recorded rather than
rounded up. The demo reached 27/30 wall cells and 9/12 roof cells, and
never reached the bed claim inside its 300s cap. 06-claimed.png and
07-sleeping.png do not exist, correctly — the tool refuses to photograph
a stage it did not reach.
The wall fix is real: 19/30 before it, 27/30 after, same cap, and the
unit test reaches 30/30 on a tick budget. The gap between 30/30 in test
and 27/30 live is not a second defect. It is D10, and the tool listed
every instance instead of smoothing them:
D10 check: 6 SLEEPING episode(s) observed this run
episode 1: GROUND sleep at (992, 9, 1003) (no bed owned yet)
... six of them, every one on the ground, none in a bed ...
The villager spends more of the run exhausted than building. It builds
its own house, gets tired, lies down in the dirt beside it, gets up,
builds a little more, and never gets far enough to claim the bed it
placed itself.
So D10 stops being a curiosity and becomes a blocker: scene-009 cannot
show a villager sleeping in a bed it built until the villager can stay
awake long enough to finish the room. The decision is the creative
director's and is logged with three options and a recommendation — NOT
taken, because unlike the lighting values it is not reversible by
editing one number without changing how the early game feels.
Task: Sprint 12 — villager-ai-024 AC5/AC6 outcome
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Story: presentation-experience story-005 (authored and implemented; the
story file did not exist, which is why Sprint 12's gate G2 never really
closed for this lane)
A placed bed existed in the registry, had a Mesh in the game data, and
had nobody to draw it. It now has a view, hosted in Valley and reported
through get_injected_tier_modules like every other module.
THE LEVER IS THE LIVE-TREE COUNT — the same technique that found the
missing camera — measured against the unchanged build first:
SCRATCH BASELINE: placed bed item_id=1, registry now holds 1 item(s)
SCRATCH BASELINE: furniture view nodes in live tree AFTER a real
placed bed = 0
SCRATCH BASELINE: Valley.get_child_count() = 29
After: exactly one view per footprint, confirmed by a real tree walk and
not by asking the presenter how many it thinks it made.
Deletion probe run and recorded, not asserted:
Assertion failed: Valley: FurniturePresenter.furniture_registry must be
wired to the SAME hosted FurnitureRegistry instance -- never left null,
never a second one
Restored byte-for-byte.
READ-ONLY BY CONSTRUCTION, grep-guarded: the view reads the registry's
signals and never writes. BV-1 forbids furniture from reaching the voxel
grid, and that prohibition is exactly what makes build-validation-002's
transparency guarantee true — so the guard protects a guarantee, not a
convention.
Per-entity view/presenter, mirroring presentation-003's landed pair. The
MultiMesh-versus-per-item ruling was named non-blocking and never
arrived; the MVP has one multi-cell furniture type, so the scaling
argument does not bite yet. Recorded so a later ruling can overturn it
knowingly.
ONE AC STAYS OPEN AND IS NOT ROUNDED UP: there is no fresh screenshot.
Two demo runs stalled at 27/30 walls and never reached the furniture
stage — villager-ai-024's plateau compounded by D10's pacing, not this
story's code. Rendering is proven headlessly against the real bed.tres
mesh. The picture is owed, and the stale 05-furnished.png on disk (14:13,
before the terrain recolour) must not be passed off as evidence for it.
23 new tests. Suite 1603/1603 green, parent-verified.
Task: Sprint 12 — presentation-005
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…pacing The user caught this and they are right. I reported the villager 'sleeping six times on the ground' and escalated D10 as blocking two stories. The coordinates say otherwise: y=9 and y=10, against a site at y=6 with walls to y=8 — every sleep ON TOP of its own structure, with state=5, WANDERING. The demo's 'GROUND sleep' label means 'no bed owned', not 'on the ground'. I read my own instrumentation literally and drew the wrong conclusion from it. What actually happened: the villager climbed up, could not get down, wandered the roof plane and slept there because nothing else was available. That is this story's own stranded-on-an-isolated-graph-point case, and it shows the symmetric descend fix does not cover this path — it fires when a column completes, not when a builder is left stranded on a finished structure. So D10 stays a legitimate design question but is NOT blocking. Stranding is. Recorded here and in the session state; the tool's misleading wording needs fixing so it cannot mislead again. Task: Sprint 12 — correction to villager-ai-024's AC5/AC6 note Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s ten gaps Story: building-system story-034 (032 and 033 were taken; noted in the file). The user proposed scaffolding as the real fix for the reachability gap and ruled on all four boundary conditions; this writes that down faithfully rather than redesigning it. THE KEY PROPERTY IS THAT IT IS NOT SOLID. Minecraft's scaffolding has no collision: you pass through it, stand on top, climb it from inside. Two risks vanish for free — a non-solid cell can never read as a wall or roof, so no phantom rooms; and nobody can seal themselves in behind something they can walk through, so seal prevention needs no scaffold-awareness at all. The nav amendment is deliberately bounded: a scaffold cell is standable without solid ground beneath it, and vertical edges are legal ONLY when BOTH endpoints are scaffold. Two ordinary stacked cells still never both stand. Proposed ADR-0007 wording is in the story, flagged for the TD rather than edited in. THE LEVER IS TWO REAL-BOOTED-GAME ASSERTIONS, and they fail differently: find_path to the top course is empty today (measured, every tick to 5000), and find_path from the finished roof back to the ground is ALSO empty — which is the stranding the correction found. Lever 1 can pass while lever 2 still fails, so both are needed. TEN GAPS THE FOUR RULINGS DO NOT ANSWER, all recorded as open decisions with options and a recommendation, none decided. The sharpest: a scaffold cell cannot live in the voxel grid at all, because any non-zero block id is solid to every reader; scaffold-as-project-member would stop the project ever reaching DONE, which is the very state that triggers dismantling; the game has no gravity, so a bottom-up collapse would strand the worker and reintroduce the bug; and AC1's automatic trigger has no implementation, because the pre-claim reachability skip is documented as silent by design. Also fixed here: the demo's misleading label. It said GROUND sleep, meaning only "no bed owned", and I read it literally as asleep on the ground — which sent a pacing question to the creative director that was never the cause. It now says BEDLESS and points at the cell height, with the reason recorded: a label that reads as a location must not describe an inventory fact. Task: Sprint 12 — scaffolding authoring Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ten open decisions ruled, two deliberately left to the user, and three
load-bearing corrections to the story's own proposed wording.
THE CRUX (D1): a scaffold cell cannot live in the voxel grid — any
non-zero block id is solid to every reader. It gets its own Building
System registry, and the shared walkability predicates take occupancy as
an explicit, defaulted parameter. Build Validation passes nothing and
therefore stays scaffold-blind STRUCTURALLY rather than by convention.
THREE CORRECTIONS THE TD MADE TO THE STORY, each of which would have
been a real defect:
1. The _after_write predicates MUST be scaffold-aware. A villager on
scaffolding has AIR beneath it, so a blind check would report
would_trap_builder for nearly every write. "Seal prevention needs no
scaffold-awareness" is true of the gate, not of its inputs.
2. is_step_legal must now EXPLICITLY refuse same-column steps. Today it
would already return true; the only thing preventing that edge was
that two stacked cells can never both be standable — and the new
self-supporting clause removes exactly that guard.
3. A scaffold write is not a voxel write, so cell_changed never fires
and the nav graph would silently never learn scaffolding exists.
New synchronous patch signal added.
Also caught: the story proposed reusing a 3D Chebyshev helper for the
6-cell cantilever. It is 3D, which would have silently converted the
user's OVERHANG cap into a HEIGHT cap. Ruled horizontal-only.
D3 resolved the self-contradiction: scaffolding is its own project kind
linked by owner id, so the owning project can actually reach DONE — the
state that triggers dismantling. And it IS persisted, because
non-persistence would strand a villager across a save/load, which is the
exact bug being fixed.
D4: cancel checks whether a worker is aboard — occupied means top-down
worker-ridden, unoccupied means the fast bottom-up collapse. No fifth
sanctioned mutation point.
LEFT TO THE USER, correctly: D7's tick values (pacing/feel) and D2's
visual identity (art direction). The 6 itself was already the user's.
RETIREMENT OF THE CLIMB HACK: ruled retire ON EVIDENCE, not on landing.
ADR-0009's two discrete mutations stay, each gains a telemetry counter,
and the anti-vacuity levers require both to read ZERO for the build
phase — so a firing FAILS the lever instead of masking a scaffolding
failure. ADR-0009 is untouched today.
ADR-0007 -> v1.1; control-manifest -> 2026-07-27 with three new required
bullets and one new forbidden bullet ("never make scaffolding solid,
never generalize the vertical edge").
Task: Sprint 12 — story-034 TD rulings
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Commit d214c7f was meant to carry the TD's one-line ADR-0007 log entry in .claude/docs/technical-preferences.md. It also carried 26 lines that are NOT mine: the user's "Bundled Fonts" table (Cinzel, EB Garamond, MedievalSharp, Caveat and the reserve face, with their licence note) and their "UI Quality Gates" section, including the contrast checker that had never been run before today and immediately found three failures. That file was explicitly on my do-not-touch list, because the user is working on assets and UI in parallel. I passed the path anyway without checking what else was in it — the same mistake as this morning's sweep, just narrower, and caught by reading my own diff instead of by luck. Nothing is lost and nothing is reverted: the content is the user's, it belongs in the repo, and rewriting already-pushed history to re-attribute it would cost more than it is worth. This note exists so the record is accurate rather than tidy. Practice restored: check `git show --stat` on any shared-file path before committing it, not only after. Task: Sprint 12 — accidental payload in d214c7f Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Story: building-system story-034. A full implementation pass was written
and then deliberately backed out. The gate was red and the work
regressed a previously green test, so it was not committed. The entire
diff and every new file are preserved at
production/parked/story-034-scaffolding-WIP.patch — nothing is lost and
the next pass starts from there.
TWO REAL DEFECTS WERE FOUND AND FIXED DURING TRIAGE, both kept in the
parked patch:
1. The same-column gate broke ADR-0007 section 1b's own binding promise
that a caller passing no scaffold source sees EXACTLY pre-amendment
behaviour. It refused every same-column pair; the predicate used to
fall through and return true. The TD rationale — two stacked cells
can never both be standable, so the case never arises — holds only
for callers that check standability first, and not every caller
does. Correct gate: both scaffold is legal, exactly one is illegal
(that is what closes general climbing), neither falls through.
2. The same defect existed a SECOND time, copied verbatim into
villager_ai's _is_step_legal_after_write. Those twins feed
would_trap_builder, so the builder believed far more writes would
trap it than actually would.
Fixing both turned walkability_predicates_test 18/18 and the new
scaffolding levers 5/5 green.
WHAT STOPPED IT, unresolved: villager-ai-024's regression test drops
30/30 to 27/30 with an entire CORNER COLUMN stuck, all three cells
PLANNED and never claimed — a different shape from 024's original
top-layer symptom. Ruled out: the job-selector change is purely
additive, and report_unreachable only sets a flag that claim_job clears.
Prime suspect, unconfirmed: the new same-column escape loop tells
would_trap_builder an upward escape exists onto the block being placed.
That escape is real only through 024's sanctioned discrete climb, not
through a legal step, so seal prevention now permits writes it used to
refuse, and one of them seals the corner approach.
Also recorded, not acted on: the reachability corpus measured 60.83s
against its 60s ceiling on an idle machine with the tree restored to the
last green commit; the same corpus measured 45.78s earlier today on
identical code. That is load drift, not a regression. Its Cut-Lever
Policy would permit shrinking the corpus and the lever was deliberately
NOT pulled — coverage is not traded away for a transient.
Task: Sprint 12 — story-034 first pass parked
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Story: building-system story-034, second pass. The first pass was parked red (4b73f47); this restores it from the parked patch and resolves what stopped it. Suite 1640/1640 green, 0 orphans, parent-verified. THE CORNER-COLUMN REGRESSION, pinned by bisect rather than guessed. villager-ai-024's regression test fell 30/30 -> 27/30 with an entire corner column left PLANNED and unclaimed. Two hypotheses were tested and DISPROVEN first — the job selector change is purely additive, and the new vertical escape loop was not it either (guarding it scaffold-only changed nothing). Disabling D5's reporting made the test pass; keeping the report but dropping the cooldown write ALSO made it pass. That isolates it exactly: _unreachable_retry_after_tick is read by the CANDIDATE FILTER. D5 wrote every pre-claim probe miss into it, so the villager stopped re-probing those cells for 20 ticks, built other cells first, and sealed the corner off. A pre-claim probe is cheap and must repeat every pass, because a cell that is unreachable now routinely becomes reachable as the build progresses. FIX: the throttle gets its OWN map. The TD's intent — no report storm — is honoured; selection is left alone. Reporting is throttled, reachability is not. THREE MORE DEFECTS FIXED, each instructive: 1. The same-column gate broke ADR-0007 section 1b's binding promise that a caller passing no scaffold source sees EXACTLY pre-amendment behaviour. It refused every same-column pair; the predicate used to fall through and return true. Correct gate: both scaffold legal, exactly one illegal (that is what closes general climbing), neither falls through. 2. The same defect existed a SECOND time, copied verbatim into villager_ai's _is_step_legal_after_write, which feeds would_trap_builder. 3. A new test asserted the blanket refusal — it encoded the wrong semantics and was corrected, not deleted, with the reason inline. Another gave a villager no escape route at all and then demanded would_trap_builder answer false; it now has a real scaffold cell below, because the predicate was right and the fixture was wrong. 4. The registry idempotence test counted signal emissions in an int captured by a lambda — GDScript captures scalars BY VALUE, so the counter read 0 forever. Array-and-append. This is the exact trap named in every briefing today, and it still landed in code written under that briefing. CUT LEVER PULLED on reachability_property_corpus_test, PAIRS_PER_SEED 5 -> 4, exactly as that file's own policy directs: reduce pairs before seeds, re-measure once, escalate. The ceiling was NOT relaxed and the test was NOT skipped. Measurements: 45.78s at midday, 60.83s in the evening ON IDENTICAL CODE with an idle machine and the tree restored to the last green commit — the baseline drifted, the algorithm did not. Scaffolding then added 2.4% (60.83 -> 62.27), inside ADR-0007 v1.1's own +5% budget. After the cut: 49.11s. Earlier today I said I would not pull this lever because the drift looked transient; it is not, and the evidence changed the decision. ESCALATED: if the baseline keeps drifting, the next lever is not another cut but a TD ruling on whether a wall-clock ceiling guards the right thing, since it measures the machine as much as the code. STILL NOT DONE, named not hidden: ScaffoldRegistry, ScaffoldErectionCoordinator and ScaffoldPresentation are NOT yet wired into Valley, so scaffolding does not yet erect itself in the running game — the levers pass against the production classes called directly. The live dismantle orchestrator on project DONE and on cancel is also outstanding, as is the payoff-loop demo and the telemetry-zero proof. D7 (tick values) and D2 (visual identity) remain the user's. Task: Sprint 12 — building-034 second pass Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… of them real Story: building-system story-034, third pass (the Valley hosting). Parked at production/parked/story-034-valley-wiring-WIP.patch; the tree is back at 6cc9002 and green. Second consecutive park on this story, which is itself the finding: it is too large to land in one pass and the next attempt should be cut into hosting / erection / dismantle as separate landable pieces. WHAT THE PASS PROVED, and it is the important part — the D5 to erection path works IN THE RUNNING GAME, observed directly against a real boot: the real hosted ConstructionJobQueue.report_unreachable fires the real job_reported_unreachable signal, the real hosted ScaffoldErectionCoordinator plans and registers real SCAFFOLD-kind BuildProjects in the real BuildProjectRegistry (ids 2/3/4, kind=2, owner=1), and those cells build to completion through the real ConstructionTickLoop into the real ScaffoldRegistry. Both ADR-0009 telemetry counters read ZERO in that configuration — the climb hack no longer fires. Pre-change verbatim, before any wiring: PROBE cell=(1032, 8, 1039) state=1 claimed_by=0 is_unreachable=false PROBE cell=(1032, 9, 1039) state=0 claimed_by=-1 is_unreachable=true PROBE cell=(1032, 10, 1039) state=0 claimed_by=-1 is_unreachable=true WHY IT DID NOT LAND — five failures, 1633 cases: 1. gameworld_e2e_loop_test — exact injected-tier module count moved to 27. Mechanical, expected, needs a conscious update. 2. world_root_valley_attach_test — exact hosted-child count moved. Mechanical, same. 3. scaffolding_hosting_test lever1 — the new test file itself is unstable. It drives claims and positions directly, bypassing real AI travel, and a queue-level release_claim does not reset VillagerAi's own pursuit state, so the villager re-fires its detection mid-loop and spawns extra scaffold structures that shift the geometry the test assumes. Also only 1 of its 3 test functions executes per invocation, undiagnosed — so lever2, the dismantle proof, has never actually run. 4. transition_persistence_test — a GREP GUARD: scene_world_management source must never reference TimeTickSystem, and the wiring introduced exactly such a reference. A clean architectural violation, not a test problem. Whatever the dismantle orchestrator needs from the clock has to arrive by injection. 5. wall_room_no_plateau_test — villager-ai-024's regression test is RED AGAIN. This is the one that matters. With scaffolding live the room should build BETTER, not worse, so something about erecting real scaffolding mid-build changes the geometry or the ordering destructively. Not diagnosed. NEXT PASS SHOULD, in this order: 1. Fix (4) first — it is a one-line architectural violation and cheap. 2. Diagnose (5) BEFORE writing anything new, with the same bisect method that pinned the last corner-column regression: disable one seam at a time against the real hosted boot until the wall test goes green, then name the mechanism. 3. Land hosting alone, with only the boot invariant and the count updates as its lever. That is a small, provable piece. 4. Land erection second, using the direct observation above as its lever rather than the unstable claim-driving test. 5. Land dismantle last, with a test that constructs BUILD and SCAFFOLD projects directly and never involves the AI — the shape lever2 was reaching for and never got to run. Task: Sprint 12 — story-034 Valley wiring parked Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Story: building-system story-034, fourth pass. The third pass tried to land hosting, erection and dismantle together and was parked red (da7dc89). This lands the piece that is provable on its own and holds the rest back for a MEASURED reason, not for tidiness. WHAT LANDS: Valley hosts one ScaffoldRegistry, injects that SAME instance into every hosted villager (the default one and every roster member), subscribes the nav graph to it, and hosts ScaffoldPresentation. Boot invariant added. Suite 1643/1643 green, 0 orphans. WHAT IS HELD BACK, and why it is a finding rather than a cut: connecting ScaffoldErectionCoordinator to job_reported_unreachable makes villager-ai-024's regression test fall 30/30 -> 27/30 with a whole corner column left PLANNED and unclaimed. Isolated by bisect, not guessed: with the erection response disabled the test passes; with it enabled it fails; the boundary is exactly that one signal connection. Scaffolding is supposed to MAKE cells reachable, so this is a real defect and not a tick-budget effect, and it must be understood before it ships. Dismantle waits with it — there is nothing to dismantle until erection runs. TWO REAL DEFECTS FIXED ALONG THE WAY: 1. GREP-GUARD VIOLATION: the wiring resolved /root/TimeTickSystem directly from valley.gd, and Scene & World Management is forbidden to reference TimeTickSystem at all. The clock is now taken from ConstructionTickLoop, which already resolves and holds it — both compliant and a guarantee that the two coordinators share one clock instead of racing two. 2. A LATCH IN THE ERECTION COORDINATOR: it marked a cell "served" BEFORE checking whether a plan existed, so a cell whose plan failed once was suppressed forever, even after the world changed and a plan became possible. A failed plan is a "not yet", never a "never". Fixed and kept, though the coordinator does not run yet. THE BOOT INVARIANT ASSERTS ONLY WHAT THIS PIECE WIRES. The parked version asserted the erection and dismantle coordinators too; asserting on something this piece deliberately does not construct would be a lie about what is wired. Their invariants land with them. The new hosting test is deliberately small and AI-FREE. Its predecessor drove villager claims and positions directly and was unstable, because a queue-level release_claim does not reset VillagerAi's own pursuit state, so the villager re-fired detection mid-run and moved the geometry the assertions assumed. This one asserts identity — same registry instance in the presentation tier, the tick loop and every villager — plus ADR-0007 section 1b's binding promise that a caller passing no scaffold source sees exactly pre-amendment behaviour. That last one is the invariant whose first implementation broke it and turned the suite red. One fixture bug of my own, fixed and recorded: the section-1b assertion first probed a cell at y=40, outside max_y=16, where every read is treated as blocking — so the cell was unstandable for a reason that had nothing to do with scaffolding. The predicate was right; the fixture was wrong. Two exact-count assertions moved (26->27 modules, 30->31 children), updated consciously with the reason inline. Task: Sprint 12 — building-034 occupancy tier Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Story: building-system story-034, erection tier. The occupancy tier landed in c3036df with this deliberately held back, because connecting it dropped villager-ai-024's regression test from 30/30 to 27/30. That defect is now understood and fixed. Suite 1645/1645 green, 0 orphans. THE CAUSE, measured rather than guessed. Instrumenting the coordinator against a real hosted build of a 30-cell room printed 20+ unreachable reports — and `planned=true` for EVERY ONE, including cells that were perfectly reachable moments later: SCAFFPROBE report cell=(1002, 7, 1006) owner=1 planned=true cells=1 SCAFFPROBE report cell=(1003, 8, 1006) owner=1 planned=true cells=2 ... 20+ of them, essentially every wall cell in the room ... A pre-claim probe calls a cell unreachable whenever it is unreachable AT THAT INSTANT, and with one villager walking around a site that is most cells most of the time. Erecting on the first report therefore floods the queue with scaffold jobs — and since a villager may hold only ONE claim, the actual wall cells starve. The corner column that stayed PLANNED was not blocked; it was outcompeted by scaffolding for cells that never needed any. THE FIX IS THE USER'S OWN RULE, made literal: scaffolding is built only when it is NEEDED. A cell must now report unreachable REPORTS_BEFORE_ERECTING times before it earns a scaffold. One report means "not right now"; repeated reports mean "not without help". A momentarily blocked cell recovers on its own and costs nothing. Two tests, both AI-free by design — an earlier attempt drove villager claims directly and was unstable, because a queue-level release_claim does not reset VillagerAi's own pursuit state, so the villager re-fired detection mid-run and moved the geometry the assertions assumed: - a single report never erects anything (the persistence gate itself, and the assertion that would have caught this defect on day one); - the coordinator is not merely constructed but actually SUBSCRIBED to the real seam — hosted-versus-wired being this project's most repeated failure mode. One API slip of my own, caught by the test and fixed: I called get_project_ids() on BuildProjectRegistry, which has get_projects(). Still to come: the dismantle tier, with a test that constructs BUILD and SCAFFOLD projects directly and never involves the AI. Task: Sprint 12 — building-034 erection tier Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Story: building-system story-034, dismantle tier. Completes the wiring the occupancy tier (c3036df) and the erection tier (9542c68) began, and finishes what two earlier all-at-once attempts could not land. Valley now constructs ScaffoldDismantleCoordinator and connects it to both triggers the ruling names: the owning project reaching DONE, and the player cancelling it mid-build. The clock comes FROM ConstructionTickLoop rather than being resolved here — Scene & World Management is forbidden to reference TimeTickSystem at all, there is a grep guard on the directory, and taking the tick loop's own instance also guarantees the two coordinators share one clock instead of racing two. The boot invariants for both coordinators are restored now that Valley genuinely constructs them; while it did not, asserting on them would have been a lie about what was wired. TWO TESTS, AI-FREE ON PURPOSE. Two earlier attempts at proving this half drove real villagers and were unstable: a queue-level release_claim does not reset VillagerAi's own pursuit state, so the villager re-fired its detection mid-run and moved the geometry the assertions assumed. These construct the projects directly, so what is under test is the ORDERING and the TRIGGER, never the pathfinder. - Both connections are asserted by IDENTITY, not by the coordinator merely existing. Constructed-but-unsubscribed is this project's most repeated defect and the reason six such gaps were closed yesterday. - Top-down ordering is asserted against deliberately SHUFFLED input, so the planner has to impose the order rather than inherit it. - SC-INV-1: a cell a worker's body column occupies is skipped, and the one below is taken instead. Without that, "top-down" would delete the floor from under the worker riding the structure down — the exact stranding scaffolding exists to prevent. One trap of my own, worth recording because I have warned every agent about it all day and still walked into it: the occupied-body-column fixture used an untyped inner array literal, which crashes on assignment to Array[Vector3i]. Typed, with the reason inline. Suite 1648/1648 green, 0 orphans — verified on a tree that also carries the user's in-flight world-height work (max_y 16 -> 96), so this figure covers both. Task: Sprint 12 — building-034 dismantle tier Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…defect First payoff-demo run with scaffolding fully wired, in the 96-height world. 30/30 wall cells BUILT in 16.1s — every previous run of this demo stalled at 27/30 and hit its cap. Scaffolding is visible in 04-built.png as orange blocks (placeholder; visual identity is still the user's call). The user's own design proposal is now load-bearing in the game. AND IT EXPOSED THE NEXT DEFECT. The roof reached only 10/12 before its cap, the bed claim was never reached, and there were five bedless sleeps — every one at y=10, above the walls (6..8) and above the roof plane (9). The villager is stranded on top again. Working hypothesis, not yet confirmed: dismantle fires when the WALL project reaches DONE and removes the scaffolding while the villager is still up there building the roof, taking away its way down. SC-INV-1 protects the cell a villager STANDS IN; it does not protect the route it needs to descend. If so, the dismantle trigger is too eager in precisely the way the erection trigger was — 'the project I served is done' is not 'nobody needs this structure any more' — and the fix mirrors the persistence gate that fixed erection. The demo label corrected last night earned its keep immediately: it now prints 'a villager asleep above the build site is stranded, not merely tired' with the cell height. The old GROUND-sleep wording is exactly what made me misread this same symptom as a pacing question. Task: Sprint 12 — building-034 visual proof and follow-on finding Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…V-2) Story: building-system story-034. Found by the first payoff-demo run that scaffolding actually completed — 30/30 wall cells in 16.1s, a first — and then stalled anyway: the roof reached only 10/12 and the villager slept five times at y=10, above the walls (6..8) and above the roof plane (9). THE DEFECT: dismantle fired the moment the WALL project reached DONE. The roof is a SEPARATE project, drafted afterwards, so the scaffolding came down while the builder was still up there working on it — taking away its descent. SC-INV-1 protects the cell a villager STANDS IN, which is not enough: a builder that climbed up to lay the top course has its own cell untouched and no way back to the ground. SC-INV-2 is the missing half: a structure is not dismantled while any villager's body column sits at or above the structure's own base within its footprint. The served project being finished is not the same as nobody needing the structure — the exact over-eagerness the erection side had before its persistence gate, one level up. A GAP IN MY OWN FIX, caught before it shipped: a deferred owner would never have been revisited, because the construction-completed trigger fires once and is then gone for good. Deferred owners now go on their own list that the tick re-polls, and they are retried BEFORE the already- draining ones so a villager that has just climbed down does not wait an extra tick. The new test constructs the projects directly and never involves the AI — the third time that shape has proven necessary in this story, because a queue-level release_claim does not reset VillagerAi's own pursuit state. Suite 1667/1667 green, 0 orphans. Task: Sprint 12 — building-034 SC-INV-2 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Decision D11's own intent, finally implemented. The bands were supposed to be anchored to the achievable terrain range; they shipped as absolute Y values, so they did not travel — and every world-size change broke them in a different direction. BOTH ABSOLUTE ANSWERS WERE WRONG, which is what makes the fractional one right rather than merely tidier: - `[2, 4, 5]`, written for the 16-high world: raise the world to 96 and terrain runs y≈16..64, so EVERY cell sits above the top boundary and the whole world renders in one band. Observed as a uniform cream mass. - `[24, 48, 72]`, quarters of the WORLD as art bible §4.3 reads it: the top band then lands entirely above the reachable ground, so that material never appears at all. A dead band instead of a single one. (The parallel biome session had noted these and reached the same conclusion independently.) Boundaries are now derived from `band_split_fractions` across `base_height ± amplitude` — the range terrain generation actually produces — so "half way up" means half way up at any world size. THE DESIGN CHOICE IS SURFACED, NOT BURIED. Art bible §4.3 thinks of the bands as quarters of the WORLD, because a snow line is an absolute height; that reading is self-consistent and it is exactly why a flat world has no snow. Anchoring to the achievable range guarantees all four materials appear at every world size, at the cost that in low relief the peak material sits on a hilltop rather than a mountain. The default is even quarters, which keeps the art bible's proportions; pushing the last fraction up (e.g. [0.3, 0.6, 0.9]) reserves the peak for genuine crests. That dial belongs to the art director, so it is data, and the trade-off is written where they will read it. An explicit `band_boundaries` list still wins outright, so one specific world can be hand-tuned. `validate()` learned the derivation mode and now checks the fractions instead — and two things that would otherwise have been rejected: a single-band world needs no split points at all, and the band_ids family checks must keep running in derivation mode rather than being skipped by an early return. Both were caught by existing tests. Test expectations now read `effective_band_boundaries()` — the same source production uses — instead of the raw field, which is what a test computing "what should this config produce" always meant. Suite 1667/1667 green, 0 orphans. Task: Sprint 12 — D11 implemented properly Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Second payoff-demo run with SC-INV-2 and the derived bands. Walls again 30/30 in 16.2s, so scaffolding's win is reproducible. Everything else is identical to the run before the fix: roof still 10/12, the same five bedless sleeps at the same five cells. The evidence PNGs came out byte-identical, which incidentally confirms end-to-end determinism. So the hypothesis was wrong. Dismantle taking the builder's descent is not what stalls the roof. SC-INV-2 stays — it provably defers dismantle while a builder is above the structure and its test passes on its own terms — but it was not this defect, and claiming otherwise would be taking credit for a coincidence. Three refuted hypotheses in one night: the vertical escape loop, the served-cells latch, and now the dismantle trigger. Every one was plausible from reading. Every one fell to a bisect. Reading identified no real cause tonight; measurement identified all of them. The defect is now sharper: y=10 is on top of the roof plane (walls 6..8, roof 9), so the villager stands on built roof cells and cannot descend, and the two missing cells are the interior ones reachable only by standing on already-built roof — villager-ai-024's 'cannot chain two extensions', one storey up. Next diagnostic written down and deliberately not yet run: the two ADR-0009 telemetry counters at the end of the demo, and the ScaffoldRegistry contents during the roof stage. Non-zero counters would mean the villager climbed via the hack and scaffolding never served the roof at all. Task: Sprint 12 — building-034 roof defect narrowed Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…es not Two diagnostics added to the payoff demo, plus a control run, because my earlier claim that scaffolding took the walls from 27/30 to 30/30 rested on a before/after coincidence rather than evidence. DIAGNOSTIC RUN: room walls: all 30 cells reached BUILT after 16.3s roof construction result: 10 / 12 cells reached BUILT scaffold cells standing at roof stage: 0 [] ADR-0009 climb mutations: self_seal_climb=40 marooned_relocation=9 CONTROL RUN, erection response disabled, everything else identical: room walls: WAIT CAP (220s) hit with 27/30 cells BUILT roof construction result: 9 / 12 THREE THINGS ARE NOW SETTLED, and one of them corrects me. 1. Scaffolding's contribution is real and is exactly the last three wall cells. Disable erection and the demo falls back to precisely the historical 27/30; enable it and the room closes. I should have had this control before making the claim, not after. 2. The roof gets NO scaffolding at all — zero cells standing at that stage. So the roof stall was never a dismantle problem: the erection trigger simply never fires for roof cells. The defect is now located instead of suspected, which also explains why SC-INV-2 changed nothing there. 3. The ADR-0009 retirement criterion is nowhere near met. The TD ruled the climb mutations retire on EVIDENCE — the counters reading zero — not on scaffolding landing. They read 40 and 9. Both mechanisms carry the build today and scaffolding is the smaller contributor; retiring the climb hack now would drop the walls back below 27/30. The likely reason the roof gets nothing is written into the story: a roof cell's support would have to rise from inside the room the walls just enclosed, and the planner prefers the column directly below the target. Deliberately NOT acted on — the next step is one more print and one run, because three hypotheses were read confidently tonight and all three were refuted by bisect. Task: Sprint 12 — building-034 contribution measured Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…efect One print, one run, and the answer matched none of the three earlier hypotheses. SCAFFDIAG cell=(993, 9, 1002) seen=3 PLANNED=true cells=1 SCAFFDIAG cell=(993, 9, 1003) seen=3 PLANNED=true cells=1 scaffold cells standing at roof stage: 0 Exactly two roof cells ever report unreachable — the two interior ones, matching 10/12 exactly. Both clear the persistence gate. Both plan SUCCESSFULLY. And nothing is standing at the roof stage. The coordinates settle it: the four wall segments enclose x 992..994, z 1001..1004, so the interior is the single column x=993, z=1002..1003 — exactly where the two missing roof cells are. Their scaffold support would have to stand INSIDE that interior, and the interior is sealed. The 30/30 wall success closed the room completely: four segments, no gap, NO DOOR. Nobody can get in, so the scaffold is never built, so the middle of the roof is never finished. Scaffolding behaved correctly throughout — it detected the need, cleared its gate and produced a valid plan. It planned a structure in a room nobody can enter. Worth noticing: this was invisible while the walls stalled at 27/30, because an unfinished wall IS a doorway. Fixing the walls is what sealed the room. Every fix tonight exposed the next problem one layer up — walls, then descent, then entry. Next step specified in the story: give the demo's wall drafting a deliberate one-cell doorway at ground level and re-run. That is a demo change, not a system change, and it is the smallest thing between this tool and a finished roofed room. Task: Sprint 12 — building-034 roof stall located Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ncept The specified next step was to give the demo a doorway. Done through the real RemovalTool, and measured: doorway at (992, 6, 1002): erased room walls: WAIT CAP (220s) hit with 24/29 cells BUILT roof construction result: 9 / 12 Against 30/30 with no doorway. The doorway made the walls WORSE, so the change was reverted rather than kept and tuned until the numbers looked better. The reading that fits: with an opening the villager walks INSIDE and builds from within, and as the remaining cells would close it in, seal prevention correctly refuses them. A builder must not trap itself — and it has no rule saying 'leave, then finish from outside', so those cells never get built at all. Without a doorway it worked only because the villager was never inside. SO THE FINDING IS NOT THAT THE DEMO LACKS A DOOR. It is that the building system has no DOOR CONCEPT. An improvised gap is not a door, it is a hole that disorders the build. A real door would be a component that room recognition treats as a legal opening rather than a breach, that the build plan knows to place LAST and from OUTSIDE, and that seal prevention can reason about — today it can only see that a write would trap someone, never that a doorway means it would not. Until then a finished room is either sealed (no entry, interior roof unbuildable) or open (builder trapped inside a shell it refuses to close). Both are reachable today and neither is a house. Nothing here retracts scaffolding: its measured contribution on the sealed geometry stands at 27/30 -> 30/30. Recommended next story is building-system: doors, sized as a real story, because it blocks the roof, therefore the bed, therefore scene-009, therefore milestone criterion Donchitos#5 in the product. Task: Sprint 12 — door concept identified as the blocker Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The previous commit said the doorway run failed because the villager walks inside and seal prevention then refuses the closing cells, and called that 'the reading that fits'. It does not fit. The position data contradicts it: villager after construction wait: current_cell=(992, 9, 1004) y=9 with walls at 6..8 is ON TOP of the wall, not inside the room. The villager was never trapped in a closing shell. That was a guess wearing the clothes of an analysis, and since it is in the permanent record it gets a correction rather than a quiet edit. What remains measured: 30/30 walls with the room sealed and the roof stuck at 10/12 because the interior roof cells need scaffolding inside and nothing can enter; 24/29 with the improvised doorway; 27/30 without scaffolding erection at all. What is NOT established is WHY the doorway made the walls worse — candidates exist (project re-partitioning, changed job order, lost scaffold support, different seal-prevention evaluation around an opening) and none is tested. Tonight's score for hypotheses formed by reading is 0 for 4. The door-concept conclusion still stands, but on the sealed-room measurement, which is direct and does not depend on explaining the gap regression. If anything, a hole that makes things worse for reasons nobody can name is a further argument that a hole is not a door. Recorded as a precondition: bisect the doorway regression BEFORE writing the door story, or it builds on sand. Task: Sprint 12 — correction to the doorway analysis Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…the erase does not The correction set a precondition: bisect this before writing a door story. Done, in one run. Same project mutation, different geometry — erase the TOP cell of a wall column instead of the GROUND cell. One drafted cell removed either way; only one creates an opening a villager can walk through. BISECT erase TOP cell (992, 8, 1002): erased room walls: all 29 cells reached BUILT after 15.6s Against 24/29 when the erased cell was at ground level. So the erase itself costs nothing: removing a cell from a released project does not re-partition it, does not disorder the jobs, does not starve the scaffold planner. 29/29 in 15.6s is the same speed as the untouched 30/30 run. The cost is the ground-level OPENING — the fact that a villager can now get inside. That puts the original 'builds from within, then correctly refuses to seal itself in' reading back on the table, this time on measured ground. What refuted it earlier was the villager's position at the END of the wait; that says nothing about where it was DURING the build, and I over-read it. The mechanism inside that window is still unmeasured, and the next step is one print: which cells stay unbuilt, and where the villager is each time the count stalls. What this already settles for the door story: a hole is not a door, and now there is a number attached. An opening a builder can enter is not a neutral gap — it changes how the wall gets built, measurably and for the worse. A door component cannot be 'a cell we skip'; it has to be something the build plan and the seal-prevention rule both understand. Task: Sprint 12 — doorway regression bisected Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r inside
One print, one run, and it kills two of my own readings at once.
STALLDIAG room walls villager=(993, 9, 1004) state=5 pending=5
[(994,6,1004) (994,7,1004) (994,8,1004) (992,7,1002) (992,8,1002)]
STALLDIAG room walls villager=(992, 9, 1004) state=3 pending=5
The interior is x=993, z=1002..1003 at y=6..8. The villager sits at y=9
throughout — on the wall crown, not inside — wandering, then sleeping,
not building. The pending set never changes.
So "walks in and correctly refuses to seal itself in" is dead, and so is
"the erase disorders the project". What is happening is the same defect
as the roof: a builder that climbs onto something it built cannot get
down.
The pending cells corroborate it. Two of them sit directly ABOVE the
erased door cell — a floating column with its support gone, the hardest
possible reach. The other three are an untouched corner column on the
far side, unbuilt only because the single builder is marooned on a wall
several cells away.
THIS REFRAMES THE DOOR CONCLUSION. "The building system needs doors" was
the right observation attached to the wrong cause. The recurring defect,
now seen in three guises tonight, is that a villager who climbs onto its
own work cannot reliably get off it: walls layer 3 (solved by
scaffolding, 27/30 -> 30/30), roof interior (no scaffolding is ever
built there), and the wall crown with a doorway present (builder strands
and five cells go unbuilt).
SC-INV-2 defers dismantling while someone is up there, which is
necessary but not sufficient — it protects a descent that EXISTS. It
does nothing where no scaffolding was ever built. The ADR-0009 climb
mutations firing 40 and 9 times a run are the same story from the other
side: that is how villagers get UP, with no counterpart for getting DOWN
that does not depend on scaffolding happening to be there.
Next story should therefore be a DESCENT GUARANTEE, not doors: assert on
a real booted game that after any construction job completes,
find_path(villager, settlement ground) is non-empty. That fails today in
three distinct geometries, all reproduced above. Doors remain a real and
separate need — a sealed room still cannot be entered — but a door story
written now would inherit an unsolved descent problem and look like it
failed.
Task: Sprint 12 — stall window measured, descent identified as the root
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The root cause behind three separate stalls, written up from measurement
rather than from reading. villager-ai-024 gave builders a way UP — the
discrete climb, plus scaffolding as the real mechanism. Nothing
guarantees the reverse, so a builder ends up marooned on a wall or a
roof, wandering and then sleeping there while the rest goes unbuilt.
Three geometries, all from the real hosted demo:
1. Wall layer 3 — SOLVED, and it proves the mechanism: 27/30 without
scaffolding erection, 30/30 with it. Scaffolding supplies ascent and
descent together, so nothing strands.
2. Roof interior — the two cells are detected, clear the persistence
gate and PLAN successfully, yet zero scaffold cells ever stand,
because the support would sit inside a room the finished walls
sealed. Roof stops at 10/12.
3. Wall crown with a ground-level opening — villager at y=9 throughout,
WANDERING then SLEEPING, pending frozen at five cells that never
move.
The story records the five hypotheses already refuted tonight so nobody
re-treads them, and carries the working rule that produced every real
answer: measure in the stall window, because end-of-run positions say
nothing about what happened during it — reading them as if they did
produced two of the five wrong answers.
Anti-vacuity is two assertions in two different geometries so neither
can mask the other: crown descent (trips within seconds today) and roof
descent (empty path at y=10 today).
Doors are explicitly OUT of scope and stay a separate need — a sealed
room still cannot be entered — because a door story written on top of an
unsolved descent would inherit this failure and look like its own.
Task: Sprint 12 — villager-ai-025 authored
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An implementation pass on villager-ai-025 produced a test that reproduces the defect and fails for exactly the right reason: the villager never regains a path to settlement ground after stranding on its own finished column. Parked as evidence rather than landed, because it fails and this project does not land failing tests. It also is not the story's lever. It builds a synthetic TestEnv, and AC1 says the guarantee must be asserted on a REAL booted game. A proof at the wrong level of abstraction is the half-proof this whole line of work exists to avoid — five hypotheses fell tonight because something plausible was checked instead of the real thing. Its own TICKDIAG output says the same from another angle: climb=0 marooned=0 throughout, so in that fixture the ADR-0009 mutations never fire at all, while the real demo fires them 40 and 9 times. The geometry does not match, which is precisely why a fixture cannot stand in for the boot here. The pass also left a diagnostic print inside villager_seal_prevention_gate.gd; reverted, tree verified parseable and clean in my own areas. It lands as a live test once story-025's real-boot lever exists and passes. Task: Sprint 12 — villager-ai-025 reproduction parked Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… success retracted Story: villager-ai-025, third attempt. Lands the plumbing and says so; the payload is NOT proven and is parked. THE REAL DEFECT THIS UNCOVERED, in already-committed work: the constructor-time clock connection silently did nothing. Valley builds both scaffold coordinators during _wire_build_project_lifecycle, and at that moment ConstructionTickLoop has not run its own setup, so its time_tick_system is still null and the connect was skipped. Consequence, precise and invisible: SC-INV-2's deferred dismantle retry could NEVER fire in the shipped game — a dismantle deferred because a builder was still on the structure would simply never be retried. No test covered it. scaffold_dismantle_live_test asserts the deferral DECISION and the construction/cancel signals, never the tick that retries. It surfaced only from a diagnostic printing dismantle_connected=false on a real boot. Both coordinators now take a deferred connect_tick(), called from world genesis after the tick loop has resolved its clock, and scaffold_tick_wiring_test pins it by connection identity. A FALSE SUCCESS IS RETRACTED. An earlier run appeared to show more scaffolding and I described it that way. It was invalid — it predated the connect_tick fix, the trigger was inert, and its numbers were byte-identical to the baseline. The extra scaffolding in that frame came from the doorway geometry. There is still NO valid post-fix measurement of either lever; both pre-fix numbers stand, recorded in the evidence file. WHAT IS PROVEN of the descent trigger: it receives ticks, and a single marooned observation never erects anything — the persistence discipline that stops this repeating the queue flood which starved the walls. WHAT IS NOT: a persistently marooned villager does not actually get a descent scaffold erected. That assertion is parked with its verbatim failure. Its body was lost while splitting the file and is recorded as lost rather than reconstructed from memory. Shipping the trigger as "wired, therefore working" would add another hosted-but-inert instance while fixing one, which would be absurd. It ships as plumbing. Suite 1670/1670 green, 0 orphans. Task: Sprint 12 — villager-ai-025 plumbing, payload parked Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nd one regression First run in which the descent trigger was actually connected. LEVER 2, ROOF DESCENT — PASSES: before: villager=(994, 10, 1003) find_path(...).size()=0 empty=true after: villager=(1008, 4, 1000) find_path(...).size()=11 empty=false The villager is off the roof and on the ground with an eleven-step path home. That is the guarantee the story exists for. LEVER 1, CROWN — improved, not passing: before: villager=(993, 9, 1004) state=5 pending=5 final 24/29 after: villager=(998, 6, 1010) state=3 pending=2 final 27/29 No longer marooned on the crown; y=6 is ground. The two cells left are exactly the pair above the erased door cell, floating with no support — a different problem from stranding. The mechanism is visibly working: 21 scaffold cells standing where there were 0, and the bed completed 2/2 for the first time ever. CAVEAT, stated before the conclusions rather than after: two other Godot processes were already running when this started. Every wall-clock-capped stage was competing for CPU. Position results are unaffected; completion counts are not trustworthy until repeated on a quiet machine. AND A REGRESSION THAT NEEDS THAT RE-RUN: roof fell from 10/12 to 0/12. Either scaffolding work is eating the tick budget the roof used to get, or the run was starved by the foreign processes. Both plausible, neither measured — and tonight's record for concluding from plausible-looking evidence is 0 for 5, so it stays unconcluded. Telemetry unchanged at 40/11: the climb mutations still carry the ascent, and the TD's retirement criterion remains far off. This story never claimed to reach it. Task: Sprint 12 — villager-ai-025 first valid measurement Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…irst time ever
The payoff loop's last step ran for the first time. The demo produces
these frames only when the stages genuinely happen, so their existence
is the result:
stage 6: villager id=0 claimed bed cell (993, 6, 1002), owned by
BuildProject id=1
stage 6: worker_ids=[0] — built by claiming villager id=0: true
stage 7: villager id=0 is SLEEPING at (993, 6, 1002)
It claimed a bed it built itself, and the attribution is checked rather
than assumed.
MILESTONE CRITERION Donchitos#5 IS STILL NOT MET, and that must not be blurred:
shelter verdict for (993, 6, 1002) = false
credited recovery = 0.3500 -> matches UNSHELTERED (x0.70);
sheltered would be 0.5000
It sleeps in its own bed, in the open. The roof reached 0/12 this run, so
the room does not classify as sheltered and the villager is credited the
worse rate. Criterion Donchitos#5 requires it to sleep BETTER in a room you built.
The first half now holds; the second does not.
The chain that works today: builds wall -> builds bed -> claims it ->
sleeps in it. What is missing is the roof — and the roof count is exactly
the number this run cannot be trusted on, because two foreign Godot
processes were competing for CPU throughout.
Task: Sprint 12 — payoff loop stages 6 and 7 reached
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The previous note said the roof count could not be trusted because two foreign Godot processes were competing for CPU. Repeated with none running, and the outcome is identical: construction result: 27 / 29 wall cells roof construction result: 0 / 12 scaffold cells standing at roof stage: 19 bed construction result: 2 / 2 stage 7: villager id=0 is SLEEPING at (993, 6, 1002), recovery 0.3500 So the regression is mine, not the machine's. Roof was 10/12 before this change and is 0/12 after. THE TRADE, stated plainly. Gained: descent works (off the roof with an eleven-step path home, off the crown at y=6 instead of y=9), three more wall cells, the first completed bed ever, and the payoff loop's stages 6 and 7 reached for the first time — the villager claims a bed it built itself and sleeps in it. Lost: the roof, entirely. Most likely cause, held as a HYPOTHESIS and not a finding: nineteen to twenty-one scaffold cells are real construction jobs and there is exactly one villager, so the attention that used to reach the roof now goes into building the descent scaffolding. If that is right the fix is not to weaken the trigger but to stop erecting scaffolding the villager does not need, or to make a descent scaffold cheaper than a wall. Written down to be tested, not acted on — tonight's record for plausible-reading hypotheses is 0 for 5. Cheapest test named in the note: how many of the 19 cells are descent scaffolds versus job scaffolds, and how many ticks each consumed. Task: Sprint 12 — roof regression confirmed Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This session takes The Last Seal from mid-vertical-slice to the end of Pre-Production propagation — 81 commits covering the slice's final feature packages, its formal conclusion (verdict: PROCEED), the completed Art Bible, and the propagation of all playtest findings into GDDs and ADRs.
Vertical slice — final packages (prototypes/last-seal-vertical-slice/, throwaway code)
Slice conclusion
Art Bible completed (design/art/art-bible.md, all 9 sections approved)
Propagation into design & architecture
Reviewer notes
🤖 Generated with Claude Code