The closing half of F's bookend. All gates green on the flipped tree (qa.sh --strict --soak: classic
regression + default-boot gate + smokes + no-giants incl. the seated drummer + the full-week soak).
- tour_shots.py -> docs/shots/release_v3_1/: the money shots on the DEFAULT boot (no per-shot flag juggling
now the flip covers it) + a ?classic=1 before/after ("the town before v3"). 7 shots, settled, 0 page errors.
- week_soak.py: re-pointed to the default boot; the leak check now treats an at/below-baseline OR non-climbing
trail as leak-free (a decreasing tex trail is GC/atlas-settle, not a leak — it was false-failing at warn-level).
- docs: README v3.1 flags table (defaults on + ?classic=1), CITY_SPEC v3.1 amendment (the rewritten prime
law + classic covenant, A's deferred edit), LANE_F_NOTES §16, F-progress R16.
Numbers (seed 20261990): default @ venue block 124 draws / 57k tris (<=300/200k); ?classic 161 draws / 24k
tris (the v2 baseline); seated drummer 1.32 m stature; week soak 42 cycles leak-free (net +0/-6).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
40 KiB
PROCITY — Lane F progress (INTEGRATION & QA)
Session: 2026-07-14 · Author: PROCITY-F · For review by: fable
Round 16 (v3.1 THE FLIP) — F bookends; the town shows its best by default
The gig layer soaked through three v3 stages, so v3.1 flips it (and the mature v2 flags) ON by default. F owns the flip; A–E landed their polish against it (seated drummer, town-wide pools, backline, corner-poster).
Opening commit a4946b7 (the round's foundation):
- The flip —
index.htmlCLASSIC+flagOn(): gigs/weather/tram default-on,loadPedFleet({sit:!CLASSIC}),window.PROCITY.flags;buildings.jswinmap default-on + classic-aware.?classic=1forces the exact v2 boot. - The covenant moved —
flags_off_regression → classic_regression(byte-identical0x3fa36874); a newdefault_boot_gate(all four flags on, gig layer present, gig golden0xb1d48ea1, budget); every gig smoke re-pointed to the DEFAULT boot; qa.sh gate renamed. - Seated-stature gate (ledger #3) —
interior_scale_check.py+flags_check.pyacceptprocitySeatedfigs at [0.9,1.5] m; the drummer passes at 1.32 m.
Verified: ?classic byte-identical (0x3fa36874, gig absent); default = full town (3 venues / 3 genres, gig golden,
112 draws @ venue block); classic/default/district/continuity/cover all green. Close: re-baseline, re-shot tour
→ release_v3_1/ + a ?classic=1 before/after, docs (CITY_SPEC v3.1 flip+classic law, README flags table,
LANE_F_NOTES §16), tag v3.1.
Round 15 (v3.0 RELEASE CLOSE, ?gigs=1) — F ran last; the release is closed
R14 landed A–E's hardening but F never ran, so v3.0 stayed untagged. R15 = the close. All deps were in
before F ran (A's poster flip + new golden 0x4f4a549d, D's amp + R14 continuity seam, B/C verifies). The
six-item brief, each committed atomically:
- Continuity wiring + smoke (
687d23f) — the ped you followed is in the crowd:crew.spawn({roster})+ the queueonAdmit → recordVenueEntryrelay;smoke_continuityasserts the seam on identities + settled tris. - Alias deletion (
146b5f3) — the R12 scalar alias retired; every read keyed byvenueShopId; tools + spec migrated. - Full-week soak (
edc0c47,tools/qa/week_soak.py) — 7 nights × all venues: cover/roster per night, leak-free (plateau), 28 cycles. - Money-shot tour (
6a35b29,tools/qa/tour_shots.py) —docs/shots/release_v3/+ contact.html; heroqueue_nightshows A's now-visible poster; settled measurements. - Docs — README v3 section, LANE_F_NOTES §14/§15, this note, five freezes confirmed.
- Acceptance + tag —
qa.sh --strict6/6 + continuity smoke + week soak green → tagv3.0.
Ledger #5 vindicated C: the gig interior settles to ~182k tris after the 5 instrument GLBs load (not
the ~34k measured pre-load); the interior gate is draws (≤56), so no budget violation — the tour + smoke
now measure settled. Full runbook: LANE_F_NOTES.md §15.
Round 13 (v3.0-beta — THE DISTRICT, ?gigs=1) — WIRED + VERIFIED + TAGGED
A–E landed, then D (4-piece + instruments + queue + RY fix). F wired the district together and it fires.
**Seed 20261990 → "Boolarra Heads": 3 venues, 2 playing tonight — The Exchange Hotel (pub, gig-pubrock)
- an RSL (
gig-covers), one dark (reads true).** All 7 F tasks done,qa.sh --strictGREEN (6/6, 0 warn), tagv3.0-beta. Shots:docs/shots/laneF/r13_v3beta_gig_interior.png+r13_v3beta_venue_night.png.
What F did (ROUND13 §Lane F):
- Per-venue state machine —
gig_state.jsrewritten: one latch per venue off the sharedprocity:segmentspine, keyed byvenueShopId; all three hard-won R12 laws preserved. New runtime surfacewindow.PROCITY.gigs.byVenue+ per-venue getters (onOf/openOf/gigOf/coverOf/paidOf…); the R12 single-venue alias kept one round. B'svenue.js/audio.js+ D'ssetGigread it. - Walla + applause — the crowd bed
crowd-wallarides the interior tone layer under the live band bed whileon; anapplausesting fires once on theon→doneedge while inside. Verified:iMusic=gig-pubrock,iTone=crowd-walla. - Cover per venue — the door seam keys off the shop entered, so a night at two venues is two covers.
- Debt #1 closed — was a LIVE BUG — E renamed
pubrock-live→gig-pubrock, so F's R12GIG_BEDbridge (rewrotegig-pubrock→pubrock-live) pointed at a dead key → the band would have mimed in silence. Deleted; the room'saudio.gigKey(already the manifest key) feeds the engine directly. - Stature gate —
interior_scale_check.pynow measures stature (crown−foot, platform-independent), ceiling-clip assert kept as its own line (debt #6). - District smokes —
smoke_gigs: band→4, a per-venue loop (every gigKey resolves across 3 genres, crowd ≤ its own watchPoints, no-giants), street budget at the busiest venue block, the queue assert, plus the R12 determinism/cover/noassets/flags-off arms. All green. - The outdoor queue — D shipped
VenueQueueand left the street-side lifecycle to F (its documented seam): F wires one queue per venue in the shell (spawn at doors off B'squeueZoneFor, drive each frame, dispose bydone), exposed asqueueCountOf(id). Verified: 2 in line at doors → 0 by done.
Numbers (seed 20261990): gig interior 62 draws / 34k tris (≤350) · street @ venue block 107 draws /
47k tris (≤300/200k) · band+crowd stature 1.61–1.81 m under a 4 m ceiling · cover $10 debited-once/re-entry-
free/broke-knockback + free night (seed 1234) · flags-off fingerprint 0x3fa36874 unchanged, gig layer wholly
absent. Full runbook + the R13 debt-ledger closeout in LANE_F_NOTES.md §13.
Round 12 (v3.0-alpha — the gig layer, ?gigs=1) — WIRED + VERIFIED
A–E all landed before me, so F did what F does: turned five parts into one Friday night. Seed
20261990 → "Boolarra Heads", venue = The Thornbury Hotel, tonight = SCREAMING UTES, $10 on the door.
Acceptance shot: docs/shots/laneF/r12_v3alpha_gig.png.
| F task (ROUND12 §Lane F) | result |
|---|---|
| 1 — gig state machine | ✅ new F-owned web/js/world/gig_state.js. quiet → doors (DUSK) → on (NIGHT) → done (DAWN) → quiet, verified forwards AND backwards on the hand-driven clock. On window.PROCITY.gigs. |
2 — ?gigs=1 seam + flags-off |
✅ shell bootstrap fetches custom_bands.json (no fetch when flag-off or ?noassets=1) → generatePlanFor(seed, src, {gigs:true, customBands}). Flags-off verified wholly absent: no state machine, no plan.gigs/posters, no pub, no venue geometry, zero band-file fetches, golden 0x3fa36874 unmoved. |
| 3 — cover charge | ✅ all three halves of John's ruling verified live: $10 debited once (191→181, cover — Screaming Utes in the wallet), re-entry the same night free (181→181), broke on a new night → polite knockback, no entry. Free nights (seed 1234) walk straight in, wallet untouched. Zero new UI — rides the R8 buy seam. |
| 4 — audio wiring | ✅ gig bed inside via C's gigKey, B's muffled spill outside reads PROCITY.gigs.state. Found + bridged a real C↔E key mismatch — see below. |
| 5 — smokes | ✅ smoke_gigs in flags_check.py: schedule determinism · band==3 · crowd ≤ watchPoints · dance mix · bed resolves · ≤350 draws · no-giants · ?noassets=1+?gigs=1. Plus the v3 arm of the flags-off regression. |
| 6 — shot + tag | ✅ shot captured. Tag pending the harness run (below). |
Numbers. Gig-night interior 42–50 draws with the rig fleet, 171 draws on ?noassets=1
placeholders (worst; budget ≤350) · ~40k tris · street at the venue 69 draws/29.6k tris · leak-free
(geo 66→66, tex 63→63 over 4 gig cycles) · band 3 + crowd 8/8 watch points, 3 dancing / 5 standing
· band stature 1.68–1.77 m, crowd 1.60–1.77 m, tallest crown 2.09 m under a 4.0 m ceiling.
John's drop-in works: 7 of your 10 hand-written names fill all 7 nights (Screaming Utes, The Dead
Ringers, The Rissoles, The Flannel Shirts, Boganvillea, Chunderbolt, Amyl & The Servos). Covers rolled
10,0,0,3,2,0,9 — 3 free of 7. Under ?noassets=1 it falls back to the pure generator ("The Wombatts")
with zero fetch, exactly as A specced.
Three bugs F found in its own work (all caught by verification, fixed, re-verified)
- The state machine only advanced when polled. Driving NIGHT→DAWN→MORNING→NIGHT with nothing
reading in between (player inside the pub, audio muted) skipped the night roll — the cover was
never due again. Now it rides
procity:segment, whichlighting.jsfires on every change. - Rewinding the clock left
donestuck on a midday town (the latch only cleared at MORNING). - The night only rolled if the clock passed through DAWN — so a jump from NIGHT to MORNING left
last night's paid stamp valid and a broke punter walked straight in. Caught by my own smoke, not
by hand: stepping with
[/]always crosses DAWN, so only jumps (DBG/shots/soak) exposed it. The roll now keys on landing in the daytime, not on having observed one particular segment.
Also worth recording, because it nearly shipped a wrong gate: "no giants" must measure stature, not
world crown. The band stands on C's 0.32 m deck, so a perfectly human 1.73 m guitarist has a 2.05 m
world crown and the naive R10 check failed a correct band. The smoke now measures crown − base.y
and keeps the world-crown assert only for "never clips the ceiling" — the real R10 failure mode.
Three findings for other lanes (detail + rulings in LANE_F_NOTES.md §12)
- ⚠ C ↔ E: the gig bed key never met. C emits
gig-pubrock(and asked E for that name); E shippedpubrock-live. Unresolved, the pub plays to a silent room and — because the audio law fails soft — nothing errors, you just get a band miming. F bridged it at the glue so alpha ships. This is the R1 facade-skin filename trap again. → needs a named contract line in CITY_SPEC. - ⚠ D + E: E's 5 instrument GLBs landed; nothing wires them. D holds primitives and published
instrumentForas the seam "when they land" — they've landed, nobody owns the join. Non-blocking (asset law; reads fine in the shot). F did not silently do it inside D's rig. → R13. - ⚠ spec ↔ C: the band has no drummer. ROUND12 §D.1 says "drummer seated bob" and E built a merged
kit; C's
bandPosesare guitar/vocal/bass and the drum riser is set-dressing. D flagged it and built to C's poses. A spec/implementation divergence no gate can catch → Fable/John to rule.
Harness note
This MacBook had no Chromium/Chrome, so the Playwright gates couldn't run locally; John authorised
the install (done — 93.5 MB, Playwright CDN). /Volumes/m3ultra/Documents/procity is a mount of
m3ultra's ~/Documents/procity (same tree), so ssh m3ultra@100.89.131.57 runs the real gates on the
real files — but node isn't on the non-interactive ssh PATH: use
env PATH=/opt/homebrew/bin:$PATH tools/qa.sh --strict or every node gate reports a bogus FAIL.
Round 11 (the audio round) — DONE ✅ (v2.1)
John greenlit "generate freely". E generated the pack (23 assets, web/assets/audio/, 8.7 MB ≤ 25),
B built the WebAudio engine (audio.js, self-unlocking, self-ticking), C added room.audio = {musicKey,toneKey} to buildInterior. Lane F wired + verified + tagged v2.1:
| task | result |
|---|---|
| F1 — interior beds | ✅ interior_mode enter → PROCITY.audio.playInterior(current.audio) (fade in), exit → stopInterior() (0.7 s fade). Guarded/no-op when muted/noassets/pre-gesture. 2 lines, the seam B/C designed for. |
| F2 — audio smokes | ✅ new smoke_audio in the flags harness (fresh Chromium): pre-gesture silence (ctx not unlocked), 0 boot errors, ?mute=1 muted, ?noassets=1 zero audio fetches, enter/exit leak-free (12 cycles, 8 shops with a music bed, live AudioNodes bounded at 5, made 42). Caught + fixed my own gesture-via-mouse-click tripping PointerLockControls in headless → gesture via keyboard. |
| F3 — soak + tag | ✅ soak with audio on PASS (heap 48 MB stable, 0 errors, no drift). qa.sh --strict GREEN 6/6. v2.1 tagged + pushed. |
Cross-lane (F's own gate, noted to B): B's audio.js:143,145 use Math.random() for footstep SFX
variant + gain jitter — legitimate transient runtime FX (which shop plays which bed is seeded upstream
in interiors.js), but it tripped F's generation-determinism Math.random ban. F scoped the ban
correctly: web/js/world/audio.js is runtime playback, not generation → exempted in
scaffold_check.mjs (B may instead add a // cosmetic marker; either is fine).
Round 10 (fix the R9 giant-rig blocker, re-shoot, re-tag) — verify + ship
R9 shipped a blocking regression: interior rig figures came out ~2× room scale (keeper head 3.83 m in
a 3.4 m room) because rigs.js buildFigure normalized off the head bone's bind-pose Y. Lane D
fixed it (R10, commit 3432fcc): normalize by the feet→crown span, plus a new qa.sh --strict
no-giants gate (interior_scale_check.py). Lane F verify + re-shoot + soak + re-tag:
| task | result |
|---|---|
| F1 — verify the fix | ✅ qa.sh --strict GREEN 6/6 incl. the new scale gate: 24 interior figs / 6 shops all crown ∈ [1.4,2.0] m and under-ceiling (Second Time Redfern, the giant scene: 1.66–1.86 m). Live-measured too — the 3.83 m I first saw was a stale ES-module cache in a day-old browser tab, not a regression (served + fresh-chromium code both correct). |
| F2 — re-shoot | ✅ browsers.png re-shot: browser at the rack + keeper at the counter, human-sized (figures human-sized vs door/fittings: yes). night_crowd.png re-framed to a readable "lit VIDEO REGAL amid CLOSED town" — see the honest note below. |
| F3 — soak | ✅ full-default soak PASS: 37 chunks, 20 shops, heap 54 MB stable (no perf drift from the keeper fix — it's a build-time scale calc), draws 248, 0 errors. Tri budget still ~327k > 200k (pre-existing rig-model item, D/E decimation — not an R10 change, not the blocker). |
| F4/6 — docs | ✅ tour README updated with stable v2 filenames + captions; this addendum is the R10 release note. |
| F5 — tag | ⏸ v2.0 annotated tag staged on the fixed commit; holding the push for John given the night_crowd finding (a public release + his flagged money shot). |
Honest finding — night_crowd has no crowd, and it can't without new work. John flagged it as
near-black/empty. Re-framed it readable (clean night, tight on the neon). But a visible street crowd
does not form: Lane D's night patronage parks ducked-in patrons hidden inside the shop (they are
the interior browsers in browsers.png), and seed 20261990's video shop is a low-traffic corner
(tested default streamed roster + patronage-on at night: 0 patronage, 0 visible peds at the shop).
This is not a framing bug and not (clearly) a regression — it's that the "night crowd" was always the
interior presence. A visible outdoor queue is a v3 Lane-D mechanic (loiter-outside-the-openLate-
shop). The ~20 fps in night captures is a headless software-GL artifact (128 draws / 65k tris is light).
→ Flagged for D: confirm night patronage at the openLate shop still behaves as the v2.0-rc notes claim.
Round 9 (the v2.0 ship round) — DONE (v2.0 tag pulled, re-tagged in R10)
All lanes landed (C browse points + buy-anywhere, D browser rigs, A CITY_SPEC freeze + closing-time ruling, E VRAM audit + half-res book/toy atlases, B tram + tour bookmarks). F wired the one cross-lane seam, graduated the harness, shot the tour, soaked, and tagged the epoch.
| task | status |
|---|---|
| F1 — interior presence (C→D→F) | ✅ interior_mode reads occupancyOf(shop.id) (closure to citizens) and spawns browser rigs at C's room.browsePoints, one per patronage occupant, cap 3; freed by exit()'s keepers.disposeAll. Door points carry shopId. Verified: enter occupied "Second Time Redfern" → 1 browser == min(occ,3), disposed clean, 0 errors. |
| also wired | ✅ Tram (?tram=1, createTram+update). Buy-anywhere (C2): E at a book-spine/toy-box buyMesh buys over the wallet (collapseBuyItem+toast); preload book+toy packs. Verified: bought a book spine, cash 191→177. |
| F2 — smokes to strict | ✅ buy-v0 / patronage / book-toy / katoomba graduated warn→STRICT. New warn smokes: interior-presence, shelf-buy, tram. Fixed the book-stock check to count isStock OR buyMesh (C2 tags spines buyMesh). qa.sh --strict GREEN 5/5, harness 0 fails / 0 warns. |
| F3 — tour + soaks | ✅ tools/v2_tour.py → 11 shots (docs/shots/v2_tour/, un-letterboxed) incl. the rain-verandah money shot (rain + winmap-lit open video shop + CLOSED dark neighbours at night) + browsers + dig-real + katoomba + tram_stop + contact sheet. Both soaks PASS (full-default + all-on: 37 chunks, 20 shops, heap stable, 0 errors, leak-free). |
| F4 — docs freeze + tag v2.0 | ✅ Flags table finalized (below); v2.0 tagged on a green tree. |
| Marshal | C1 (the round's SPOF) landed early; all lanes committed; no slips. |
v2.0 flags — FINAL
| flag | owner | status | default |
|---|---|---|---|
| roster | D | graduated → DEFAULT-ON (R7 flip); ?roster=v1 escape hatch |
on |
| patronage | D | default-on (?patronage=0 off) |
on |
?dig=1 |
C | opt-in (crate riffle) | off |
?winmap=1 |
B | opt-in (parallax window glass) | off |
?stock=real |
C/E | opt-in (real GODVERSE covers/spines/boxes + buy-anywhere) | off |
?weather=1 |
B | opt-in (seeded rain/overcast/clear; ?weather=rain forces) |
off |
?plansrc=osm[&town=] |
A | opt-in (real-OSM towns: melbourne, katoomba) | off (synthetic) |
?tram=1 |
B | opt-in (spine tram loop) | off |
?noassets=1 |
— | opt-in (primitive-only, zero-network) | off |
Determinism goldens frozen: synthetic 0x3fa36874 · osm/melbourne 0x34cfdec0 · osm/katoomba 0x0f652510. |
Round 8 (catch-up + the town comes alive → v2.0-rc) — DONE ✅
All lanes landed (E packs, B weather, A 2nd town, C buy, D patronage). F wired the shell seams, graduated the harness, tagged.
| task | status |
|---|---|
| shell wiring (F owns index.html) | ✅ A &town=<key> → generatePlanFor(seed,'osm',{town}) (Katoomba, 19 shops, verified). B weather (3-line contract): createWeather on ?weather=1, PROCITY.weather={state,intensity} ({clear,0} when off for D), weather.update in loop. C session wallet (createWallet(seed)) bound to the dig BUY (getCash/onBuy in interior_mode). D patronage: shop door-points per chunk → citizens.setShops, ?patronage=0 off-switch, citizens.setWeather each frame. All boot clean (0 console errors, settled). |
| F1 — smoke graduations + additions | ✅ stock=real + weather=rain graduated warn→STRICT. New warn smokes: buy-v0 (dig BUY→wallet: cash 191→179, bag 0→1), patronage (7 peds visit shop doors/~18s), book/toy stock (6/11 real atlas meshes). Katoomba golden 0x0f652510 pinned in the determinism gate (fixed a hex zero-pad bug it caught). |
| F2 — patronage baseline | ✅ No re-pin needed — flags-off regression held (patronage nets fewer draws, inside tolerance; ≤300 cap + draws-±40% both green). |
| F3 — tag v2.0-rc | ✅ TAGGED. qa.sh --strict GREEN 5/5 (harness strict). |
| Marshal | All lanes committed round-8; no slips this round. |
Round 7 (the flip round → v2.0-beta) — DONE ✅ (v2.0-beta tagged)
Critical path resolved: E1 ped-merge (447188a), E2 stock pack (0c12dac), D's GO (43edabf),
C1 ?stock=real (3724a65) all landed. F executes flip → strict harness → tag.
| task | status |
|---|---|
| F1 — roster flip (prime-law amendment) | ✅ DONE + verified. index.html: streamed roster is now the default (chunkStream:{radius:2} per D's spec); ?roster=v1 = escape hatch (fixed roster); ?roster=stream still accepted (no-op). Hours-aware setNightLivelyChunks on the open-late block. Same commit re-pins the flags-off baseline: old (163 draws/19k tris, roster-off) → new (164 draws/~66k tris, roster-on) — draws barely move (E1's merge = ~1 draw/rig, the whole point), tris = the crowd (D worst-view 65,899; drift-WARN now draws-only, tris under the hard cap). Plan goldens UNCHANGED (0x3fa36874). Also fixed the harness's roster probe (was reading a nonexistent prop → blind) + flipped the assertion to require streamMode ON + added an escape-hatch check. Verified: default boot streamMode:true (146–150 active), ?roster=v1 streamMode:false (96), both render, 0 errors, ≤300 draws, harness GREEN. |
| F2 — harness to strict + new-flag smokes | ✅ DONE + verified. qa.sh flags gate warn_gate → run_gate — the harness (flags-off regression + 4 existing flags + all-on combo) is now STRICT (a FAIL fails qa). Wired ?stock=real (F owned the seam): shell preloads the record pack + passes stockReal; interior_mode builds makeStockAdapter(getStockPack(shop.type)) and passes it to both buildInterior (static crate sleeves) and dig.open (riffle) — fail-soft to parody if the pack's absent. Added stock=real + weather=1 smokes at warn-level (decision #4). Verified: crates show real GODVERSE covers (smoke: 7 real atlas sleeve meshes, non-parody batched); weather auto-skips (Lane B not landed); qa.sh --strict GREEN (5 gates). |
| F3 — tag v2.0-beta | ✅ TAGGED (no-hostage rule). Criteria met: roster default-on + escape hatch ✓, harness strict+green ✓, ?stock=real real sleeves ✓, qa strict green ✓. |
| ⚠ schedule-harness flag | B (?weather=1) and A (osm parity + 2nd town) did NOT land round-7 — no commits, tree clean. Both are additive (not headline keys); tagged v2.0-beta without them per the no-hostage rule. Weather smoke is in the harness ready to graduate the moment B ships. Flagging for Fable: two lanes slipped this round. |
Round 6 (finish v2 wiring + pay review debts → v2.0-alpha) — DONE ✅ (v2.0-alpha tagged)
Sequencing (Fable): F1 enforcement harness lands FIRST (protects the round), then F re-smokes as
lanes land, adds C's ≤350-draw interior assertion when C1 lands, extends the determinism gate if A's
?plansrc lands, and tags v2.0-alpha when all-green (3 flags acceptable if A no-shows).
| task | status |
|---|---|
| F1 enforcement harness | ✅ DONE + wired. tools/flags_check.py (self-contained server, headless, ~90s): flags-off regression (golden hash 0x3fa36874 + subsystems-inactive + ≤300/≤200k budget + ±40% snapshot + 0 errors) · per-flag smokes (winmap/dig/roster: cross ≥2 chunks + enter interior; dig opens+closes a riffle) · all-on combo (flag-composition law, decision #4). Wired into qa.sh as a warn-level gate (--no-flags skips fast; auto-skips without the Playwright venv). Current: all smokes GREEN, regression clean. |
| F2 plansrc | ✅ DONE + verified. A landed the full seam (52eb109). Wired the shell bootstrap (index.html, F-owned): ?plansrc=osm → citygen.generatePlanFor(seed,'osm') → real-data town "Melbourne", 95 shops (synthetic default = "Boolarra Heads" unchanged). Pinned both goldens in scaffold_check.mjs: synthetic 0x3fa36874, osm 0x34cfdec0 (deterministic, 2 runs). Harness auto-detects plansrc + smokes it (enters OSM shop "Mui Karaoke Rooms") + includes it in the all-on combo. Also restored binUnderAim's nearest-bin fallback (matches C's test page) so E riffles a nearby bin without perfect aim / before the bin GLB finishes loading. Synthetic golden frozen (selfcheck 1362/1362). |
| ≤350 interior draw assertion | ✅ DONE. C1 batching landed (35981ad). Added an interior draw-budget sweep to flags_check.py (enter all 9 shop types, assert ≤350 draws/room, dig on so it also confirms batching kept riffling). Caught a real bug in my own interior_mode.js: it rendered the interior without renderer.info.reset() while autoReset=false, so draws accumulated per frame (inflated 864/644/…). Fixed (reset per interior frame, both dig + walk render). True per-frame result: all 9 room types ≤350 (worst dept 96) — C's batching verified. |
F3 tag v2.0-alpha |
⏳ all landed flags smoke-green + regression green + qa strict green → tag (3 flags OK if A no-shows). |
Base: v1.1 (3a831fe), HEAD 40fefd9. qa.sh --strict GREEN.
Round 5 (v1.1 close-out + v2 foundations) — DONE ✅ (v1.1 tagged; ?dig=1 wired)
Lane F role: v1.1 watch + v2 flag-seam wiring + QA-harness-for-v2 + shared-tree marshal.
Full tracking in LANE_F_NOTES §10.
| task | status |
|---|---|
| fal un-park check | ✅ Verified already done — 039c179 un-parked fal in Lane E's brief (decision #4 + Lane E task 3: glass-case + bus-shelter + optional magazine-rack, ≤2 attempts, costs logged in AUDIT.md). Nothing for F to change. |
| archive R3/R4 instruction claims (F4) | ✅ Added "SUPERSEDED by R5" banner to ROUND3_INSTRUCTIONS.md + ROUND4_INSTRUCTIONS.md. |
| v2 flags table (F4) | ✅ Scaffolded in LANE_F_NOTES §10 (?plansrc=osm A, ?winmap=1 B, ?dig=1 C, ?roster=stream D) — all pending owning-lane specs. |
| F1 tag v1.1 | ✅ TAGGED. C1 (aa9c140: record_crate fixed + counter_till re-map) + E1 (c522464: 6 hero props baked 288k→48k, ≤8k each, live on depot) landed. Verified: depot serves baked props (counter_till 7999, drinks_fridge 8000, listening_booth 7986 tris ≤8k), C's glb.js maps them, record/opshop interiors render the counter_till GLB with keeper stand pose working + no double till, bins upgraded. Re-captured the 2 interior tour shots (fresh chromium → baked props). qa GREEN. git tag v1.1 (local). |
F2 wire ?dig=1 |
✅ DONE + verified. C shipped dig.js + the flag but left the in-game input/mode hook to F (LANE_C_NOTES §C2). Wired the consumer pattern into interior_mode.js (F-owned): aim at a userData.kind==='bin' fitting + press E → createDig/dig.open (per-bin seed via binSeed(shop.seed,pos)); the dig owns the frame (render dig.scene, no interior walk); WALK OUT / Esc closes → back to the room. Shell seam (index.html): ?dig=1 → dig: opt; procity:digOpen releases pointer-lock (riffle is cursor-driven); unlock→leaveShop guard reads interiorMode.digActive so opening a bin ≠ leaving. Fresh-chromium smoke: E opens riffle (seeded sleeves + prices render), WALK OUT closes to interior, leak-free (steady-state geo/tex flat over 3 cycles), 0 console errors. Flag off ⇒ no listener/no dig ⇒ byte-identical to v1. |
| F2 — other v2 seams | B ?winmap / D ?roster=stream are self-contained (no shell input hook needed); smoked clean (boot, 0 errors, budget OK). A ?plansrc not taken. |
| F3 v2 QA harness | ⏳ determinism gate (first-interior-hash per seed) · flags-off regression check (v2-prime-law enforcement) · v2 smoke → qa.sh warn-gate. Build as flags land. |
Base state: v1.0 (2698b40), qa.sh --strict GREEN 4/4, tree clean.
Round 4 (v1-tag round) — DONE ✅ (all 6 gates green; v1.0 tagged)
Executed Fable's ROUND4_INSTRUCTIONS.md Lane F tasks. All lanes committed R4; a 6-auditor
adversarial v1-readiness workflow returned GO; v1.0 tagged locally on the F finalization commit.
| task | status |
|---|---|
| F1 setExposure | ✅ Wired (9416d0a) then correctly removed (aad9baa): D3 (a5e4b64) made the impostor toneMapped:true, so citizens.setExposure() became a no-op tone-mapped globally via renderer.toneMappingExposure. Removed only after D committed (removing earlier would regress night brightness). Final state: no dead call. |
| F2 storeys-checker | ✅ permittedMax = max>=2 ? min(max+1,3) : max (Lane A's rule, 9416d0a). Consistency 0 warnings across 6 seeds; single-storey-type-at-2 still trips. A confirmed (5b8c806). |
| F3 gate-3 budget | ✅ PASS. E1 decimated peds (518678d, 924k→46k, ≤3k each) + D2 sign-off (a5e4b64, fleet ≈59.6k at 24-cap). Official measure: busiest node, pop 200, midday, 12-yaw peak → draws 138 (≤300) · tris ~31k (≤200k). Baseline 372k. |
| F4 gate-6 shots | ✅ PASS. Against committed B2 (6323d58, dbg.js letterbox+poses): shots.py v1_tour → 10 full-frame 1280×720, no letterbox; §3.5 night closed-facade (CLOSED plates + lit openLate video "VIDEO REGAL") + real record/opshop interiors (keeper + hero props). Fixed shots.py so interior shots capture via enterShop(id) (were falling back to a street bookmark). |
| F5 tag v1.0 | ✅ TAGGED on the F finalization commit (gate table all-green + shots committed). Local only — John pushes. |
| audit | 6-auditor v1-readiness workflow: 5 GREEN (gates 1/3/5/6 + release hygiene) + 1 procedural "land finalization commit first" → resolved. GO. |
Round 3 (lead lane) — DONE, verified live
Executed Fable's ROUND3_INSTRUCTIONS.md Lane F tasks. All wiring verified in-browser on seed 20261990.
| task | result |
|---|---|
| §3.5 hours / closed shops | isOpen() gate on enterShop. Midday: open. Night (22:00): all closed except the openLate video rental (Video Regal [11,23]) — verified toy shop blocked, video enters. |
§3.4 ?noassets |
Zero network (Perf API: 0 GLB/depot/manifest/ped-model requests); 100% primitive, legible. |
| §3.4 interior GLB | useGLB → fitting GLBs load from the 3GOD depot (bookshop shelves, +8 meshes, visually confirmed). |
| §3.4 rig fleet | 19 ped GLBs → peds and keepers upgrade placeholder→GLB rigs; leak-free (shared-cache proven, cycle2/3 flat). |
--depot on qa.sh |
validate_manifest.py --depot = 0 err (16 GLBs live). qa.sh GREEN 4/4. |
| Gate 2 soak | PASS both modes — assets: 20 interiors leak-free (+GLB-cache warmup), heap 98MB stable; noassets: 37 chunks, heap 15MB. 0 console errors. |
| Gate 4 asset-free | PASS. |
| Gate 6 shots | docs/shots/v1_tour/ (10 shots) + contact sheet captured; letterbox + 3 fallback bookmarks are Lane B dbg.js. |
Findings → other lanes (details in LANE_F_NOTES §9):
- D/E: rig ped GLBs are tri-heavy (~45k each) → gate 3 tris ~279k > 200k budget (draws fine ~200/300).
Decimate the ped GLBs; F holds
?pop=140until then. - B: add 3 shots bookmark poses; fix the headless composer letterbox in
DBG.shot(); render the §3.5 closed-facade visual (dark windows + CLOSED plate; predicatewindow.PROCITY.isOpen). - Fixed 5 F-owned harness bugs so
shots.py/soak.pyactually run (DBG async-poll,DBG.plan→PROCITY.plan,enterShopbare-id,shop.lotis an id, midday-pin + GLB-cache warmup + budget→warning).
Git: working tree synced to canonical main (862bbcd) mid-session — my R2 work is committed as aa4ed4f.
R3 edits below are staged by pathspec (see Housekeeping). Nothing pushed.
TL;DR (round 2 — for context)
All five lanes (A–E) landed; F stood up the QA harness, adversarially reviewed and fixed its own tooling, then wired the lanes into a walkable, living town — interiors, shopkeepers, and street crowds all integrated and verified live:
- Interiors — every door opens (§3.2). A door opens into a themed, seeded, self-lit 90s-AU
interior; walk it, walk back out (or Esc), room disposes. Verified across all 9 shop types,
leak-free, worst build 8.4 ms. F-owned bridge
web/js/world/interior_mode.js. - Shopkeepers (§3.3a). A keeper stands at the counter of every shop and turns to greet you; disposed with the room, leak-free over 5 cycles. (Asset-free placeholder; rig-fleet upgrade later.)
- Street crowds (§3.3b). Deterministic pedestrians walk the footpaths (
graph = plan.streetsdirectly), density follows time-of-day (busy midday, empty at night), LOD-tiered. Draw budget holds — worst main-street view ~191 draws (budget 300). Shell wiring inindex.html. - Plan swap (§3.1) + facade skins fix (prior pass): boots on Lane A's real town, textured.
tools/qa.sh is GREEN (4/4 gates, 0 skipped). Remaining: manifest GLB upgrades + ?noassets
(§3.4 — also upgrades keepers/peds to shared rigs), hours/closed-shops (§3.5), draw-budget shave.
Scoped in docs/LANES/LANE_F_NOTES.md §3.4–§3.5,§7.
Lane readiness — ALL COMPLETE ✅ (node tools/qa/scaffold_check.mjs)
| Lane | status | notes |
|---|---|---|
| A CITYGEN | 5/5 | plan.js, registry.js, names.js, selfcheck.js, map.html — determinism gate green, verified in-browser |
| B STREETSCAPE | 4/4 | index.html shell, chunks.js streamer, buildings.js, fixture_plan.js — walkable town verified live |
| C INTERIORS | 2/2 | interiors.js (buildInterior), interior_test.html |
| D CITIZENS | 3/3 | rigs.js, sim.js (CitizenSim), keepers.js (KeeperManager), citizens_test.html |
| E ASSETS | 3/3 | manifest.json (validates green), validate_manifest.py, AUDIT.md + pipeline |
What F built / did this session
QA harness (F-owned, tools/) — trustworthy, all green
| file | what | state |
|---|---|---|
tools/qa.sh |
gate runner; --strict = v1 umbrella |
✅ 4/4 green |
tools/qa/scaffold_check.mjs |
scaffold + PRNG determinism (golden-locked) + live readiness matrix + plan-determinism | ✅ |
tools/qa/consistency_check.mjs |
cross-lane gate: plan ↔ registry ↔ assets ↔ manifest | ✅ |
tools/shots.py · tools/soak.py |
Playwright beauty-tour + 10-min soak/budget/--noassets (gates 2,3,4,6) |
✅ ready; need Lane B window.DBG hook (§4) |
Adversarial self-review (Workflow, 23 agents)
Ran a 4-auditor + verifier workflow against F's own scripts + runbook. It confirmed 14 real defects in F's tooling (false-confidence checks + wrong API assumptions). All applied:
scaffold_check: JSON round-trip was a tautology (fixed → real deep-compare w/-0norm); Math.random-ban regex had false negatives (fixed → anchored to comments); irange golden check re-seeded per draw (fixed → single stream).consistency_check: added a storeys-vs-registry-range check, fixed a dead late-night branch, removed a dead metric.soak.py: heap heuristic no longer silently passes when heap isn't reported; shop count now requires verified interior loads (not justenterShopcalls);--minutesnow honored.shots.py: fixed anIndexErroron a trailing--seed.- Runbook (
LANE_F_NOTES.md): corrected against the real landed APIs —chunkIndexreturns{chunkSize,chunks}(not callable); chunks is acreateChunkManagerfactory with no lifecycle hooks;CitizenSimis graph-driven, not per-chunk; keepers usespawn/remove/disposeAll.
Integration passes (verified live in-browser)
web/js/world/interior_mode.js(new F-owned bridge) + thin marked seam inindex.html→ §3.2 interiors: every door opens.enterShoplooks the shop up in the plan, attaches its lot dims, calls Lane CbuildInterior, and switches to a newinteriormode that renders the room in its own scene and walks it via the room's occupancy grid. Exit on walk-out /procity:exitShop/ Esc →dispose()+ player restored to the door. Verified: door → Toy Shop renders; exit state-machine correct; leak-free (134 geo/37 tex → 217 loaded → 134/37 after dispose); all 9 shop typesok+pathOK, worst build 8.4 ms; 0 console errors.- Keepers (§3.3a) — wired into
interior_mode.js:KeeperManager(no fleet → placeholder actor), spawned at the counter stand pose (places.find(p=>p.userData.keeperStand)), ticked in the interior loop,disposeAll()on exit. Verified: 11-mesh keeper at the counter, greets the player (turns 0.21 rad, eases back), leak-free over 5 cycles/5 types (net growth 0). - Citizens (§3.3b) —
CitizenSiminindex.html:graph = plan.streets(no adapter needed),setPopulation(140)(?pop=),setTimeOfDay((seg+frac)/6)+update(dt)in the street loop,visibilitychange→setPaused. Fixed a NaN bug (getClock().houris a string). Verified: 96 active midday, peds walk footpaths ~1.5 m/s, budget-safe (worst ~191 draws across all main edges). web/js/citygen/index.js(barrel) → game boots on Lane A's real generated town (was the fixture). Verified: console "using Lane A generatePlan", HUD "Boolarra Heads · 493 shops".web/js/world/skins.js(1-line chokepoint fix) →facadeMatnormalizes full-filename skins. Verified:facade-*.jpgrequests now 200 OK, town textured (was all flat-grey).
Docs (F-owned)
docs/LANES/LANE_F_NOTES.md— integration runbook (real APIs, wiring steps, QA gates, DBG hook request).docs/V2_IDEAS.md— parked scope (content firehose, override layer, weather, venue, …).docs/shots/— reference-shot tree (the other lanes are already dropping acceptance shots into it).
Findings for the lanes (F flags; the two blocking-visual ones are already fixed)
| # | lane | finding | status |
|---|---|---|---|
| 1 | B | shell imported non-existent js/citygen/index.js → ran on fixture |
fixed by F (barrel) |
| 2 | B | skins.js facadeMat double-wrapped full-filename skins → facades 404 |
fixed by F (normalize) |
| 3 | B | street measures ~334 draw calls at spawn (radius 3) — over CITY_SPEC ≤300 | open — shave (radius 2 or more merging) |
| 4 | A | ~10% of shop names have a doubled possessive ("Tex's's Toys") — names.js |
open (cosmetic) |
| 5 | A | some shops have storeys outside the registry type range (e.g. video at 2, range [1,1]) | open — confirm corner-anchor intent |
| — | contract | facadeSkin is a full filename in the registry but skins.js expected a bare key |
worth a CITY_SPEC line so ground/awning/interior skins avoid the same trap |
Remaining integration (scoped in LANE_F_NOTES §3; ready to execute)
- ✅
Interiors (§3.2)— DONE. - ✅
Citizens + keepers (§3.3)— DONE (both verified live; see Integration passes above). - Manifest +
?noassets(§3.4) — GLB upgrades frommanifest.json; primitive-fallback flag. Doubles as the rig-fleet upgrade that makes keepers/peds cheap (shared meshes) so?pop=can rise. - Hours / closed shops (§3.5) and the draw-budget shave (finding 3).
- Full QA gates 1–4,6 once Lane B exposes the
window.DBGhook (§4) my harnesses drive.
Next natural step is §3.4 (manifest + ?noassets) — it's the asset-free gate AND the fleet upgrade
that upgrades placeholder keepers/peds to shared GLB rigs. §3.5 (hours) is a small data-driven follow-on.
Note on verification: pointer-lock doesn't engage in the automated browser, so a real walk is
best playtested by a human (cd web && python3 -m http.server 8130 → localhost:8130?seed=20261990).
F drives/inspects via window.PROCITY + JS for programmatic checks.
Housekeeping
- Nothing committed (all working tree). F's edits are minimal, commented
[Lane F integration], reversible. New F-owned file:web/js/world/interior_mode.js(interior + keeper bridge). Shell seam edits inindex.html: interior wiring (import, bridge create,enterShop/leaveShop, loop branch,setModelock, Esc-exit, M/P guards,window.PROCITYhooks) + citizens (import,CitizenSimcreate +setPopulation, street-loopsetTimeOfDay+update,visibilitychangepause). Also edited:skins.js(facade fix, prior pass). Suggested commit once reviewed — use a pathspec (lanes share one tree, see memory):git commit -- web/js/world/interior_mode.js web/index.html web/js/world/skins.js web/js/citygen/index.js tools docs/LANES/LANE_F_NOTES.md docs/V2_IDEAS.md docs/shots F-progress.mdmsgLane F: integration — interiors + keepers + street peds + QA harness + barrel + skins fix. - A local
python3 -m http.server 8130is running for the smoke test (harmless; kill when done). - Lane prompts hard-code
/Users/jing/Documents/PROCITY; real path is/Users/m3ultra/Documents/procity.