reikhelm/.dev/2026-05-28-procgen-map-core/state/progress.md
Parley Hatch 1d003ec5fc chore: record Phase 3 results + door-topology decision (Variant A, door_chance 0.5)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 22:14:47 -06:00

55 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Progress Ledger — reikhelm procgen core
Orchestrator's external memory. One entry per task as it completes.
## Environment notes
- Rust 1.96.0 stable. `~/.cargo/bin` NOT on PATH — prepend `export PATH="$HOME/.cargo/bin:$PATH"` in every cargo shell call.
- Resolved dep versions: rand 0.10.1, rand_chacha 0.10.0, rand_core 0.10.1, serde 1.0.228 (derive), macroquad 0.4.15. **rand 0.10 line** — RNG task must target 0.10 API (prefer building helpers on RngCore::next_u64).
## Execution schedule
- Phase 0: Task 1 (scaffold) — direct dispatch, de-risk toolchain/version resolution.
- Phase 1: Tasks 2→3→5 chain + Task 4 (RNG) — core library layer.
- Phase 2: Task 6 (engine) — keystone Pass/Pipeline contract + validator.
- Phase 2.5: orchestrator pre-stubs 5 pass files + wires passes/mod.rs.
- Phase 3: Tasks 711 (passes) — parallel, worktree-isolated; then adversarial verify.
- Phase 4: Task 12 (recipe + integration) — heavy determinism/connectivity verification.
- Phase 5: Task 13 (viz) — build + boundary check.
## Task log
### Task 1 — Workspace scaffold ✅ (commit 08e99e3)
- Two-crate workspace, resolver "2", edition 2021. core deps: rand/rand_chacha/serde(derive); viz deps: macroquad + reikhelm-core (path). `cargo build`+`cargo test` green (0 tests). lib.rs has only crate doc; main.rs plain `fn main()` stub. `.dev/` plan committed into repo root (fine for greenfield). No rendering dep in core ✓.
### Tasks 25 — core library layer ✅ (commits f707bd1, dbfd44a, 6ffe0cc, 659ef00)
Ran as Phase 1 workflow (sequential 2→3→4→5). All 41 tests green, no warnings. Reviewed all source directly.
- **T2 geometry**: Point/Rect/Line + extras (OFFSETS4/8, offset, right/bottom/is_empty, sign). Fixed iteration orders for determinism. Point derives Hash. Line::cells handles diagonal as connected staircase (documented).
- **T3 grid**: bounds-safe Grid<T>, row-major, OOB read=None/write=no-op. iter_rect avoids Rect::iter borrow lifetime. Now also derives PartialEq/Eq (see fix below).
- **T4 rng**: ChaCha8 wrapper. `fork` mix = splitmix64(basis) → FNV-1a over label bytes → splitmix64 finalizer. NO DefaultHasher. fork(&self) order-independent, doesn't mutate parent. range=half-open w/ rejection sampling; shuffle=hand-rolled FisherYates on next_u64; chance clamps + 53-bit. **Adversarial RNG verify never ran (worktree error) — I reviewed it manually: contract holds.**
- **T5 data model**: Tile{Wall(default),Floor,Door}; RegionId(pub usize) id==index invariant; RegionKind{Room,Corridor}; Region/Edge fields pub; Edge.at=Option<Point>; ConnGraph new/add_edge/edges/edges_mut/neighbors; Map all-pub; to_ascii `#`/`.`/`+`.
### Orchestrator fix — derive PartialEq/Eq on Grid<T> + Map ✅ (commit 8c4ef2e)
T5 deliberately skipped Eq on Map (Grid wasn't Eq) and used a serde-string compare workaround. Added the derives at the data-model layer so Tasks 6 & 12 determinism tests can use `assert_eq!(map_a, map_b)` directly. Purely additive, 41 tests still green.
### ⚠️ Environment constraint discovered
**Worktree isolation is UNAVAILABLE** (`WorktreeIsolationError: not in a git repository and no WorktreeCreate hooks configured`) — even though `git rev-parse` confirms a valid repo. Do NOT use `isolation: 'worktree'` in workflows or Agent calls. Phase 3 (parallel passes 711) must use a different anti-race strategy: orchestrator pre-stubs all 5 pass files + pre-wires passes/mod.rs, commits, then passes are implemented — likely SEQUENTIALLY in the shared tree (or with each agent told to only Write its file + not run concurrent cargo) to avoid build races. Re-decide at Phase 3.
### Task 6 — generation engine ✅ (commit e0a20f7)
Direct dispatch + my full code review (skipped separate validator — keystone read line-by-line; Task 12 integration tests are the end-to-end backstop). 53 tests green, clippy-clean.
- `Pass::apply(&self, ctx, rng)` exact. `GenContext{tiles,regions,graph,blackboard}` + `add_region`→`RegionId(len())`. `Snapshot{label,tiles,regions,edges}`. `Pipeline::new(w,h)/then/run/run_with_snapshots`.
- **RNG isolation correct**: per-NAME occurrence counter (`HashMap<&str,u32>`), key `"name#occ"`, `root.fork(key)` per pass. Isolation test inserts draw-then-discard X between A,B and proves their streams unchanged. ✓
- `run`/`run_with_snapshots` share private `run_inner(seed, collect)` → cannot diverge. Snapshots clone-after-apply, RNG-untouched. ✓
- `Blackboard` HashMap<String,Box<dyn Any>>; wrong-type get→None, take non-destructive. ✓
- `passes/mod.rs` created with contract doc comment, NO pub mod lines (711 append).
### Phase 3 — five passes ✅ (commits for bsp/room/connect/corridor/door) + adversarial verify
All 5 passes individually PASS (101 tests green, clippy clean). Adversarial verifier found an EMERGENT corridor↔door integration bug (see smell-ledger). Per-pass notes: BSP tiles map exactly; RoomCarver skipped-leaf draws zero rng + Room.cells = room interior; MstConnect is rng-INDEPENDENT in v1 (deterministic from room set; Prim + sorted candidates, no hash order) — N-1 edges, connected under tie/collinear/dup centers; CorridorCarver center-to-center, one Corridor region per edge in edge order, draws one chance(0.5) leg-order coin per edge; DoorPlacer (original) correct in isolation but wall-threshold rule incompatible with pierced corridors.
### DECISION (user) — door topology = Variant A, door_chance 0.5
Backed by 2000-seed experiment (A: 0 orphans, ~50/50 mix; B: 66.5% orphans). DoorPlacer being REVISED to pierce-aware door-at-mouth + DoorConfig{door_chance:0.5 default}. See smell-ledger for the exact model. This is a change to a committed pass (Task 11). Recipe (Task 12) must expose door config + adjust integration expectations (doors exist; edge.at = Some only for doored edges, None for open archways).
## Phase 3 plan (REVISED — no worktrees)
Run passes 7→8→9→10→11 SEQUENTIALLY in shared tree (forced by no worktree isolation). Each implementer creates its file + appends its own `pub mod`/`pub use` to passes/mod.rs (sequential = no race, like Tasks 2-5 did with lib.rs). No pre-stubbing needed. Sequential also lets later passes (e.g. DoorPlacer) read earlier passes' real cell-population conventions. Then a PARALLEL adversarial verify fan-out (read-only, no isolation) over the 5 passes for algorithm/determinism/bounds bugs. Heavy integration verification deferred to Task 12.
## Open concerns
- Determinism is the highest-risk surface: RNG fork stability (T4) + pipeline per-pass forking (T6). Both get adversarial verification.
- Parallel batch (711) shares passes/mod.rs — handled by orchestrator-owned pre-wiring + worktree isolation.