From 40fefd92992b915816b7c5456688991c7ec9bf71 Mon Sep 17 00:00:00 2001 From: m3ultra Date: Tue, 14 Jul 2026 22:21:31 +1000 Subject: [PATCH] =?UTF-8?q?Fable=20(integrator):=20round-6=20lane=20instru?= =?UTF-8?q?ctions=20=E2=80=94=20finish=20v2=20wiring=20+=20pay=20review=20?= =?UTF-8?q?debts=20(A=20plansrc=20carried,=20F=20enforcement=20harness,=20?= =?UTF-8?q?C=20draw=20batching,=20orphaned=20assets)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- docs/LANES/ROUND5_INSTRUCTIONS.md | 4 + docs/LANES/ROUND6_INSTRUCTIONS.md | 221 ++++++++++++++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 docs/LANES/ROUND6_INSTRUCTIONS.md diff --git a/docs/LANES/ROUND5_INSTRUCTIONS.md b/docs/LANES/ROUND5_INSTRUCTIONS.md index 59cc3bc..efdea47 100644 --- a/docs/LANES/ROUND5_INSTRUCTIONS.md +++ b/docs/LANES/ROUND5_INSTRUCTIONS.md @@ -1,5 +1,9 @@ # PROCITY — Round 5 lane instructions (from Fable, integrator) +> **⚠ SUPERSEDED by [ROUND6_INSTRUCTIONS.md](ROUND6_INSTRUCTIONS.md) (2026-07-14).** Round 5 is +> complete — v1.1 tagged (`3a831fe`); B/C/D/E/F delivered, Lane A's task carried to round 6. +> Historical reference only — EXCEPT §Lane A, which round 6 carries verbatim. + Date: 2026-07-14 · Written after **v1.0 tagged** (`2698b40`, all 6 QA gates green, 6-auditor GO). You are an Opus 4.8 agent assigned ONE lane (read your session prompt). Read this file, your `docs/LANES/LANE__*.md` spec, your `-progress.md`, `docs/V2_IDEAS.md`, and any diff --git a/docs/LANES/ROUND6_INSTRUCTIONS.md b/docs/LANES/ROUND6_INSTRUCTIONS.md new file mode 100644 index 0000000..2a937bb --- /dev/null +++ b/docs/LANES/ROUND6_INSTRUCTIONS.md @@ -0,0 +1,221 @@ +# PROCITY — Round 6 lane instructions (from Fable, integrator) + +Date: 2026-07-14 · Written after the Fable round-5 review (`d71420f`). You are an Opus 4.8 +agent assigned ONE lane (read your session prompt). Read this file, your lane spec, your +`-progress.md`, and NOTES addressed to you before touching code. + +Repo state: everything committed on `main` at `d71420f`. **v1.1 tagged** (`3a831fe`). +`tools/qa.sh --strict` GREEN 4/4 (golden `0x3fa36874`, manifest `--depot` 0 errors, +**27 procity GLBs live**). Three v2 flags live and default-off: `?winmap=1` (B), `?dig=1` +(C+F), `?roster=stream` (D). fal balance ~$21.36 after E's $0.64 round-5 run. + +## Where we are / what round 6 is + +Round 5 delivered v1.1 + three of four v2 foundations. Round 6 **finishes the v2 wiring and +pays the debts the review found**: + +- **Lane A did not run in round 5** — the `?plansrc=osm` plan source carries over whole. + It is the round's biggest single item. +- **F3 (the harness that enforces the v2 prime law) never landed** — right now nothing + automatically catches a v2 flag leaking into the default path. That's unacceptable for a + codebase with three live flags; it lands this round, early. +- **Interior draw counts are hot** — C's own R5 measurements: book room **1,245 draws**, + opshop 702 (tris are fine post-bake). Almost certainly unbatched per-item stock. Fix + before any more interior content lands. +- **Five published GLBs have no consumer**: `glass_case`, `magazine_rack`, `crate_stack` + (C, unmapped — they landed after C's R5 commits) and `street_bin`, `bus_shelter` (B, + unplaced). +- **publish.py is destructive** — it glob-rewrites `pipeline/_published.json`, which + clobbered the record to 1 entry in R5 (Fable regenerated it from the live depot). E fixes + the script this round. + +End-of-round milestone: if all four flags are live and the combined smoke is green, F tags +**`v2.0-alpha`** (local — John pushes). + +## The v2 prime law (still in force) + +Default boot stays v1-identical. Golden hash `0x3fa36874` frozen. Flags default-off. +`qa.sh --strict` green at every commit. New this round (decision #4): **flags must compose**. + +## Integrator decisions (so nobody blocks) + +1. **A's round-5 brief carries verbatim** (ROUND5_INSTRUCTIONS §Lane A): plan-source + contract + OSM fixture import behind `?plansrc=osm`, fixture checked in, zero network. + Nothing else in round 6 hard-depends on it — F extends the determinism gate when it + lands, and simply doesn't if it doesn't. A: if the full import is too big for one + session, land the contract + fixture + a partial importer that boots, and document the + cut line. +2. **Interior draw budget is now law: ≤350 draws worst room** (street gate stays ≤300 / + ≤200k). C enforces via its sweep; F adds it to the harness once C's fix lands. Rationale: + interiors render alone (no street behind), so 350 is generous — 1,245 is a bug, not a + budget problem. +3. **publish.py becomes non-destructive**: merge into `_published.json` (union of existing + + newly pushed), never replace. `_published.json` is the provenance record of everything + ever published — treat it like AUDIT.md. +4. **Flag-composition law**: any subset of v2 flags on together must work. F smokes the + all-on combo (`?winmap=1&dig=1&roster=stream` + plansrc if landed). If two flags fight, + the later-landing lane owns the fix; F arbitrates. +5. **fal spend**: no new gens authorized this round. The $21.36 balance sits. (Re-gen of a + *failed* existing prop at ≤2 attempts is fine if something turns out broken in use — + log it in AUDIT.md.) +6. **Tag `v2.0-alpha`** (F, end of round): all four flags landed + flags-off regression + green + all-on combo smoke green + qa.sh strict green. If A doesn't land, tag anyway + with three flags and note it — don't hold the milestone hostage. + +## Process rules (unchanged — agents run concurrently) + +- ONE shared working tree. `git status` first; stage only your files by exact path; options + before `--`; `add` new files first; commit immediately; pin a durable per-lane ref. +- Leave `qa.sh --strict` GREEN. Update `-progress.md`; cross-lane asks in your NOTES. +- F owns `web/index.html` + `tools/`; document call sites for F instead of editing. +- `procityprogress.txt` / `settings.local.json` stay untracked. +- Repo: `/Users/m3ultra/Documents/procity`. Ports: `~/Documents/thriftgod` (A's import), + `~/Documents/90sDJsim` (reference). Dev server `:8130`. + +## Sequencing + +``` +F1 (flags-off regression + v2 smoke) ── land FIRST, everything else runs under it +E1 (publish.py fix) ── early, protects the record while others publish +C1 (interior draw batching) ──→ C2 (map 3 new fittings) ──→ F re-smoke interiors +A1 (plansrc, carried) ─────────→ F2 (determinism gate + plansrc smoke, if landed) +B1 (street_bin + bus_shelter) · D1 (roster hardening) ── parallel + all green ──→ F3 (tag v2.0-alpha) +``` + +--- + +## Lane A (Citygen) — the second plan source (CARRIED FROM ROUND 5, unchanged) + +Your round-5 brief carries verbatim — execute ROUND5_INSTRUCTIONS.md §Lane A. Summary: + +1. **Extract the contract**: document the exact CityPlan shape `generatePlan` returns in + CITY_SPEC (nodes/edges/blocks/lots/shops/registry/hours/openLate/seeds); add a + `planSource` selector — default `'synthetic'` byte-identical (golden hash law), `'osm'` + behind `?plansrc=osm`. +2. **Build the OSM source**: port the relevant parts of thriftgod `server.py:433 + build_city()` reading a **checked-in fixture** (one real AU town's shops, few hundred + max, extracted from thriftgod's `city_source.json` cache) → dedupe → suburb inference → + parody names → seeded hours → valid CityPlan. Deterministic (fixture+seed → same plan, + hash it). **Zero network.** +3. **Prove it downstream**: `?plansrc=osm` boots the shell end-to-end — streets, doors, + interiors; invariants green (parameterize selfcheck by source; synthetic golden hash + untouched). Screenshot the imported town. +4. Document the seam in LANE_A_NOTES for F's determinism-gate extension. + +**Integrator note (decision #1):** if one session can't finish, land contract + fixture + +a booting partial importer and document the cut — a half-landed seam beats another no-show. + +**Acceptance**: default boot byte-identical; `?plansrc=osm` boots a real-data town with +invariants green; fixture committed; zero network; qa green. + +## Lane B (Streetscape) — place the street props + +1. **Place `street_bin_01` and `bus_shelter_01`** (published R5, no consumer yet). Bins: + seeded placement along footpaths (corner/mid-block, sparse — this is a country town, not + a mall). Bus shelter: main-street edges, oriented to the kerb, sensible spacing (1–3 per + town) — note it's also the future stop for V2's tram/bus loop, so place it ON the street + graph (an edge attribute or deterministic edge pick), not free-floating, and document the + placement rule in LANE_B_NOTES for whoever builds the vehicle loop. +2. **Footprint/collision verify** both (same bar as your R4 furniture verify): planted, + no sidewalk clipping, player collision sane, correct facing, deterministic per seed. +3. **Re-measure** worst continuous-walk view with citizens: still ≤300 draws (the props are + instanced/batched like the rest of your furniture — don't add per-instance materials). +4. Optional polish: a `winmap` bookmark shot for the gallery (day + night through glass). + +**Acceptance**: both props placed deterministically + collision-verified; worst view ≤300 +draws; placement rule documented; qa green. + +## Lane C (Interiors) — kill the draw count, then map the three orphans + +1. **Interior draw batching (do FIRST — it's now law, decision #2: ≤350 draws worst room).** + Your R5 numbers: book 1,245 / opshop 702 / milkbar 573 draws. Diagnose first (one + `renderer.info` breakdown per room type — is it per-item stock meshes? per-sleeve + canvases? fitting clones?), then batch: merge static stock into per-fitting or per-room + geometry (`BufferGeometryUtils.mergeGeometries` on shared-material groups), or instance + repeated items. Constraints: determinism (same seed → same room), dig compatibility + (`?dig=1` riffle needs its bin's sleeves — keep dug bins' items addressable or rebuild + the bin's mesh on dig-open), leak-free dispose, keeper/stock contracts unchanged. + Re-measure ALL room types after; extend your sweep to **assert ≤350** so it can't regress. +2. **Map the three orphaned fittings** in `glb.js` (published + in manifest since E3/E2, + after your R5 commits): `glass_case` → toy/pawn/milkbar (display case — front-of-room or + counter-adjacent), `magazine_rack` → milkbar/pawn (it's the R3 thin-wire reject reborn + via fal — eyeball it in-room), `crate_stack` → record/opshop back-room dressing. Real- + metre scale + per-kind yaw as ever; sweep + soak with them on; extend the contact sheet. +3. Re-run the dig soak (`?dig=1`) after the batching change — the riffle must still work on + the batched bins. + +**Acceptance**: worst room ≤350 draws with the sweep asserting it; all three fittings live +in rooms, validated, screenshotted; dig still works + leak-free; qa green. + +## Lane D (Citizens) — harden the streamed roster toward default-on + +The roster flips to default in v2 proper; this round produces the evidence for that call. + +1. **Full soak with `?roster=stream` on**: the standard gate-2 walk (≥30 chunks, ≥15 shops) + plus your far-field walk — leak-free (renderer.info at baseline after chunk disposes), + 0 console errors, heap stable, determinism (same seed + walk → same identities). +2. **Hours-aware density** (if not already in): streamed spawns respect the day fraction + like v1; at night, density drops and the openLate video shop's block stays lively. +3. **Flag-composition check with C**: `?roster=stream&dig=1` — entering a dig from a street + with a streamed roster, exiting, walking on. No interaction with interior mode (roster + is street-tier), but prove it. +4. **The numbers memo**: write LANE_D_NOTES "roster default-on readiness" — perf deltas + (draws/tris/frame-time worst view vs v1 roster), memory over a 30-chunk walk, density + uniformity evidence, known gaps. F + Fable use it to decide the flip in round 7. + +**Acceptance**: streamed-roster soak green; composition with dig proven; readiness memo +written with real numbers; flag still default-off; qa green. + +## Lane E (Assets) — make the pipeline non-destructive, then on-call + +1. **Fix publish.py (decision #3)**: merge newly-published files into `_published.json` + (read existing → union → sorted write), never replace. While you're in there: after any + publish, verify the file against the live depot list (`/api/list` filtered to + `procity_*`) and warn on drift. Add a small check to `validate_manifest.py` (or a new + gate): every manifest `depot:` file must appear in `_published.json` — so a future + clobber fails QA instead of hiding. +2. **Re-verify the record**: run your fixed publish path's verify against the depot and + confirm the 27-entry `_published.json` Fable regenerated is exactly right (fix if not). +3. **On-call**: B may need bus-shelter/bin scale or origin tweaks once placed; C may find + `magazine_rack`/`glass_case` issues in-room (fal re-gen of a *broken* prop is authorized + at ≤2 attempts per decision #5, logged). Answer within your NOTES. +4. **No speculative generation** — the depot grows consumer-driven only. No fal spends + beyond decision #5's broken-prop clause. + +**Acceptance**: publish.py merges (proven by a dry-run + a real no-op run), QA catches +manifest-vs-published drift; `_published.json` verified against depot; asset asks answered; +qa green. + +## Lane F (Integration) — the enforcement harness, then the alpha tag + +1. **F1 — flags-off regression + v2 smoke (LAND FIRST; carried from R5 where it slipped).** + Per your own LANE_F_NOTES §"v2 QA harness extensions": + - **Flags-off regression**: boot with no flags → assert plan hash == golden + a settled + draws/tris snapshot within tolerance of the v1.1 baseline. This is the enforcement arm + of the prime law — with three live flags it is overdue. + - **v2 smoke**: for each flag (`winmap`, `dig`, `roster`, + `plansrc` when A lands): + boot flag-on, walk 2 chunks, enter 1 interior (dig: open one riffle), 0 console errors. + - **All-on combo** (decision #4): one smoke with every landed flag on simultaneously. + - Wire into qa.sh as a **warn-level gate this round** (strict in round 7). Keep it + headless-runnable and fast (<2 min) or it won't get run. +2. **F2 — plansrc integration (only if A lands)**: wire the shell plan bootstrap selector, + extend the determinism gate to pin (seed, plansrc) hashes, add plansrc to the smoke. +3. **F3 — tag `v2.0-alpha`** (decision #6): all landed flags smoke-green + flags-off + regression green + qa strict green → tag locally with a summary (three flags is + acceptable if A no-shows again — note it in the tag message). Update the flags table + + runbook + F-progress. John pushes. +4. Add C's interior ≤350-draw assertion to the harness once C1 lands (a per-room-type + check in the smoke or soak — coordinate via NOTES). +5. Marshal duty continues. + +**Acceptance**: flags-off regression + per-flag + all-on smokes running in qa.sh (warn); +determinism gate extended if plansrc lands; `v2.0-alpha` tagged on a green tree; runbook + +flags table current. + +--- + +*— Fable (integrator). Round 5's lesson: the review caught a clobbered provenance file, a +skipped harness, and a silent no-show — all three were invisible to lanes' own green +self-reports. F1 exists so the machine catches the next one. Commit atomically, pin your +refs, leave it green.*