F 
Thanks — that's very helpful. Both parent repos are now present (`90sDJsim` reappeared in the listing), and I have ultra access if needed. Let me quickly ground my shot/soak harness in the actual house pattern (90sDJsim's `tools/shots.py`) since that's the reference F is told to reuse:

That's the exact house shot pattern — Playwright driving a `window.DBG.shot(name)` hook, with a contact sheet vs. `before/` and `references/`. Now I have everything I need to author F's deliverables grounded in real contracts. Let me write the integration runbook first (the durable technical spec), then the harnesses, V2 ideas, and the progress report.

Now the browser QA harnesses — ready to run the moment Lane B's `index.html` lands. First the tour-shot capture (adapted from 90sDJsim's `tools/shots.py` to PROCITY's DBG contract):

Now the soak-test harness — the 10-minute scripted-walk memory/leak/error gate (gates 2, 3, 4):

Let me syntax-check both Python harnesses and fix the pointless walrus in soak.py:

Now the docs/shots scaffold and V2_IDEAS. Let me create the shots tree with a README, then author V2_IDEAS:

Now `docs/V2_IDEAS.md` — the parking lot for everything discovered but out of v1 scope:

Now let me re-run the QA suite to get the freshest readiness snapshot (lanes keep moving) before writing the progress report:

Lane A's `plan.js` just landed — my scaffold_check now runs the plan-determinism deep checks automatically. Let me see that section:

Lane A's `generatePlan` passes F's determinism gate cleanly — 712 shops, town "North Cressy Reach", 2.9ms, JSON-clean. That's a real green QA result against live lane output.

Since Lane A's plan **and** registry both exist now, I can run a genuine **cross-lane consistency check** right now (exactly F's job) — do the plan's shop types/skins actually match the registry and the asset set? Let me inspect their shapes:

Real cross-lane data to check. I can see two things worth verifying: (1) a toy shop got `facade-boutique.jpg` — is that actually in the registry's `toy` pool? and (2) the name "Tex's's Toys" has a doubled possessive. Let me build a **cross-lane consistency gate** (plan ↔ registry ↔ assets) that runs now against real output:

The consistency check surfaced two real cross-lane signals. Let me investigate both properly before reporting — especially `chunkIndex 0/904`, which could be either my probe using the wrong API shape or a genuine Lane A bug that would break Lane B's streamer:

chunkIndex returns `{chunkSize, <something>}` — my probe guessed the wrong shape (it grabbed `chunkSize`). Let me read Lane A's actual `chunkIndex` so F's check matches the real API, and confirm the name bug:

Now I have the true API: `chunkIndex(plan)` → `{chunkSize, chunks}` where `chunks["cx,cz"].lots` is an array of lot **ids**, and a lot may bucket into several chunks. My probe used `idx[key]` instead of `idx.chunks[key]` — so the `0/904` was **my bug, not Lane A's**. Good that I checked. Let me fix the coverage probe to test it correctly:

The consistency check is now correct and **green**: chunkIndex covers all lots, all facadeSkins are within their registry pools, integrity clean across seeds. The only real finding is Lane A's cosmetic doubled-possessive name bug. Let me wire this gate into `qa.sh`:

Lane A's `selfcheck.js` also just landed and passes — the QA suite is actively exercising real lane output (3 gates green). Now let me write the requested `F-progress.md`. Let me grab a final fresh readiness snapshot first:

Lanes are landing fast (A 4/5, B has 7 world modules but no shell/streamer yet, C 3 support files, D 4 modules, E 2 pipeline files). Core integration blockers remain: **Lane B's `index.html` shell + `chunks.js`, Lane C's `interiors.js`, Lane E's `manifest.json`**. Let me write the `F-progress.md` checkpoint for fable:

Now, per the ultracode mandate, let me run an adversarial review of F's deliverables — independent agents that read my QA scripts and runbook, run them against the **live** repo, and hunt for false-confidence, robustness holes, and (most valuable) wiring-contract assumptions that don't match the lane code that has actually landed:

The adversarial review is running in the background. While it works, let me check whether the integration blockers (B's shell, C's interiors API) have cleared, since lanes are landing fast:

Lane A is now **5/5 complete** (map.html landed). The core blockers (B shell, C interiors, E manifest) remain. Since Lane A is fully done, let me do a real F QA action while the review runs: bring up the server and verify Lane A's `map.html` actually renders towns in-browser (its acceptance criterion), capturing a laneA reference shot:

Server's up. Let me load Lane A's `map.html` in the browser to verify it renders a real town (F verifying a landed deliverable):

Lane A's `map.html` renders a genuine, legible town — **"North Cressy Reach"** (seed 1234): 22 streets, 35 blocks, 706 lots, 516 shops, 153 chunks. The main-street spine (vertical corridor), the pink dept anchor, the market-square stall grid (center-left), cross streets, and the residential collar (green house lots ringing the edge) are all visible, with shop dots colored by type — record 113, video 94, opshop 82 … milkbar 2, dept 1 (matching the spec's "2–4 milkbars, one dept anchor"). That's Lane A's acceptance criterion verified in-browser by F. Let me confirm a second seed produces a distinct town:

Seed 88 gives a completely distinct town — **"Mirboo Springs"**, different spine and cross-street geometry, 521 shops, 4 milkbars. Lane A verified: deterministic, varied, and it reads as a town. Let me check on the adversarial review workflow:

The workflow is still running. Let me wait for it to complete since its findings directly improve the deliverables I'm handing to fable:

Let me stop polling and check lane progress instead (the review will notify me on completion):

The review completed **and** all integration blockers cleared simultaneously — Lanes A/B/C/D are now complete, E has `manifest.json`. Two priorities: (1) the adversarial review found **real false-confidence bugs in my own QA scripts** — I must fix those so F's tools are trustworthy; (2) integration can finally run. Let me read the full findings first:

14 confirmed, adversarially-verified findings — the review did its job. The runbook findings (11–14) are especially important now that integration is unblocked: **the real landed APIs differ from what I assumed from the spec** (chunks.js is a `createChunkManager` factory, sim.js has no per-chunk roster methods, keepers uses `spawn/remove/disposeAll`). I need to fix my QA scripts *and* correct the runbook against reality. Let me fix the scaffold_check bugs first:

Now fix the shots.py IndexError (finding 9) and the consistency_check issues (4, 5, 6). First shots.py:

Now the consistency_check fixes need real data to be correct. Let me inspect how Lane A actually encodes hours/storeys/late-night so my checks are meaningful, not inert:

Confirmed — there are off-range storeys (toy/book at 3, video at 2 where its range is [1,1]). That's likely CITY_SPEC's "occasional 3-storey corner anchor" exception, but a video shop at 2 storeys is worth surfacing for Lane A to adjudicate. Let me apply findings 4, 5, 6 to consistency_check — add a storeys check (as a warn), fix the dead late-night branch, and remove the dead metric:

Now the soak.py findings (7, 8, 10) — heap heuristic, vacuous shop count, and the no-op `--minutes`. Let me fix these to not give false confidence:

Let me read the walk-loop start so I can restructure it to (a) honor `--minutes`, and (b) count only verified interior loads:

Now add `import time`, and fix the heap heuristic (finding 7) to not give false confidence when heap isn't reported:

Now let me verify all the QA-script fixes compile and still pass against live data:

All QA-script fixes are working and now catch real signal (storeys warning fires, late-night positively confirmed, and **Lane E's manifest is now validated** — "every registry facade skin catalogued"). Let me confirm the fixed JSON round-trip check passes on the real plan (it has `-0` in `ry`, which the `-0→0` normalization handles) and run the full suite:

The QA harness is now trustworthy — 4 gates green (Lane E's `validate_manifest.py` also landed), and the checks catch real signal instead of passing vacuously. Now the **runbook contract errors** (findings 11–14) — these matter most because I'm about to wire against these APIs. Let me read the *actual* landed integration surfaces:

The real APIs differ from the spec-derived ones I documented (confirming findings 11–14). Critically, `index.html` already dispatches `procity:enterShop` and listens for `procity:exitShop` — I need to see how much wiring Lane B already did vs. what F must fill. Let me read the shell and the class APIs:

Now I understand the real integration state. Critically, the shell (`index.html:68`) imports `./js/citygen/index.js`, but Lane A shipped `plan.js` — and `enterShop()` (line 133-135) only toasts "interiors coming (Lane C)"; it never calls Lane C's `buildInterior`. **So doors don't actually open, and the game may be silently running on the fixture plan, not Lane A's generator.** Let me verify both, and check whether lanes are still churning (safe-to-wire check):

Confirmed three real integration bugs: (1) `citygen/index.js` doesn't exist so the shell **silently falls back to the 14-shop fixture** instead of Lane A's 516-shop town; (2) interiors landed but aren't wired — doors just toast; (3) citizens not wired. Lanes appear settled (nothing modified recently). This is exactly F's job. Let me read the real APIs I'll wire against (and correct the runbook with):

`buildInterior`'s return matches my runbook (good — §3.2 is accurate), and `player.teleport(x,z,yaw)` is available. Now let me read the citizen/chunk APIs for the runbook corrections (findings 11, 13, 14):

Now I have all the real APIs (confirming findings 11–14: `createChunkManager` factory with no lifecycle hooks, `CitizenSim` graph-based not per-chunk, `KeeperManager.spawn/remove/disposeAll`). Lanes are settled, QA green, and Lane B explicitly left `enterShop` as the wiring seam. Let me **execute the integration**. First, the safe zero-collision win — the barrel that makes the game run on Lane A's real generated town instead of silently falling back to the fixture:

Barrel works — the shell will now boot on Lane A's real town. Let me verify live in the browser by loading the actual game:

Another real cross-lane bug surfaced immediately: `skins.js` builds paths like `facade-facade-fibro-blue.jpg.jpg` — **doubled `facade-` prefix and doubled `.jpg`**. Lane A's registry stores full filenames (`facade-fibro-blue.jpg`) but Lane B's `skins.js` re-wraps them, so every facade texture 404s to flat colour. Let me confirm the boot used the real plan and see the visual state:

The barrel fix worked — **"using Lane A generatePlan"** (was falling back to fixture before). Let me see the town render and click into it:

"Boolarra Heads · seed 20261990" — the real Lane A town name confirmed in the shell. Let me walk in and see the 3D street:

My click was below the visible area (screenshot is 800×450; I clicked y=469). Also, pointer-lock likely won't engage in an automated browser. Let me use the JS inspection tool to hide the start overlay and confirm the 3D town renders + inspect the live state:

The game is **live on Lane A's real 523-shop town "Boolarra Heads"** — 31 chunks streaming, 31 door meshes (raycast targets), 24.7k tris. Two budget/visual findings: **draw calls 337 > 300 budget**, and the skins path bug means facades render as flat colour. Let me see it:

The game works — a walkable 90s-AU shopping strip under a dramatic summer-storm sky, HUD reading "MIDDAY 12:30 · Boolarra Heads · draws 340 · tris 25k · chunks 31", doors and awnings and gum trees all rendering. Facades are flat-colour only because of the skins path bug. Let me read `skins.js` to see if that's a surgical contract fix:

The bug is clear: `skins.js:60` builds `assets/gen/facade-${name}.jpg`, expecting a **bare key** like `fibro-blue`, but Lane A's registry/plan stores the **full filename** `facade-fibro-blue.jpg`, so buildings.js passes the whole thing → `facade-facade-fibro-blue.jpg.jpg`. Let me confirm what buildings.js passes, then make the robust chokepoint fix:

Confirmed: `buildings.js:138` passes `shop.facadeSkin` (full filename `facade-fibro-blue.jpg`) straight to `facadeMat`, which re-wraps it. Ground works because it gets bare keys. The robust, idempotent fix is a one-line normalization at the `facadeMat` chokepoint (works for both bare keys and full filenames):

Now reload the game and verify the facades get their real 90s-AU skins:

The doubled-path warnings persist — likely the browser cached the old `skins.js` module. Let me check network requests to see what path is actually being requested now:

The fix works — network now shows correct single-form paths, all **200 OK** (`facade-besser.jpg`, `facade-stucco-pink.jpg`, `facade-corrugated.jpg` …). The doubled-path warnings were stale console history. Let me see the now-textured town:

The facades now render with their real 90s-AU skins (window glazing, shutters, weathered surfaces — all 200 OK). **Two integration fixes delivered and verified live: the game now boots on Lane A's real 523-shop town with textured facades.** This is a strong, verified checkpoint. Let me now correct the runbook against the real landed APIs (findings 11–14) and mark what's wired:

Now let me add a §7 to the runbook capturing the live smoke-test findings, then append it:

Let me fix that section ordering and run the final full QA pass to capture the end state:

Everything has landed — **all 5 lanes complete, QA fully GREEN (4/4 gates, 0 skips)**, and the other lanes even used the `docs/shots/` tree I scaffolded for their acceptance shots. Let me rewrite `F-progress.md` as the authoritative checkpoint for fable:

Let me do a final consolidated verification — QA green after all edits, and the running game has no console *errors* (only expected asset-fallback warnings):

Zero console errors in the running game, QA fully green, both edits parse clean. This is a solid, verified checkpoint. Here's the handoff for fable.

---

## PROCITY-F — session complete ✅

I'm Lane F (integration & QA). When I started, only the scaffold existed — but **all five lanes landed while I worked**, so I went from "prep the harness" all the way to a **first integration pass with two fixes verified live in the browser**.

### Headline results (both verified in-browser)
1. **The game was silently running on the 14-shop fixture, not Lane A's town.** Lane B imported `js/citygen/index.js`, which never existed (Lane A shipped `plan.js`). I added the barrel → **seed → real 523-shop generated town "Boolarra Heads" boots**, 31 chunks streaming, 31 doors. ([web/js/citygen/index.js](web/js/citygen/index.js))
2. **Every facade rendered flat-grey** — a cross-lane naming mismatch made skin URLs `facade-facade-…jpg.jpg` (all 404). One-line chokepoint fix → **facade JPEGs now 200 OK, the town is textured.** ([web/js/world/skins.js:55](web/js/world/skins.js))

### QA harness — GREEN, and trustworthy
`tools/qa.sh` runs **4/4 gates green**: scaffold+PRNG-determinism, cross-lane consistency, Lane A selfcheck, Lane E manifest validator. Centerpiece is a **live lane-readiness dashboard** (`node tools/qa/scaffold_check.mjs`).

Critically, I **adversarially reviewed my own tooling** (23-agent workflow) and it found **14 real false-confidence bugs in F's scripts** (e.g. the JSON round-trip check was a mathematical tautology; the Math.random ban had false negatives) — **all fixed**. It also caught that my runbook's API assumptions were wrong vs. the real landed code, which I corrected.

### Findings handed to the lanes
- **B:** ~334 draw calls at spawn (over the ≤300 budget — shave radius or merge more).
- **A:** doubled possessives in names ("Tex's's Toys"); some storeys outside registry range.
- **Contract:** `facadeSkin` is a full filename in the registry but consumers expected bare keys — worth a CITY_SPEC line before ground/awning/interior skins hit the same trap.

### What's left (scoped in [LANE_F_NOTES.md](docs/LANES/LANE_F_NOTES.md) §3, ready to execute)
Interiors wiring (`enterShop → buildInterior` — the "every door opens" headline), citizens/keepers, manifest GLB upgrades + `?noassets`, the draw-budget shave, and the browser QA gates (need a small `window.DBG` hook from Lane B, requested in §4).

**Deliverables to review:** [F-progress.md](F-progress.md) · [docs/LANES/LANE_F_NOTES.md](docs/LANES/LANE_F_NOTES.md) · [docs/V2_IDEAS.md](docs/V2_IDEAS.md) · `tools/qa.sh` + `tools/qa/*` · the two integration fixes.

Nothing is committed — all edits are minimal, commented `[Lane F integration fix]`, and reversible. I held off on the interior/citizen wiring since it touches Lane B's core loop and is best playtested with real pointer-lock (which the automated browser can't drive) — **say the word and I'll wire it**, or hand me your next instructions after reviewing.

A local server is still up on `:8130` if you want to walk `localhost:8130?seed=20261990` yourself.