EVERY CRATE IS DIFFERENT, and F measured it rather than taking G's 15/15 on trust — from the indexes of record, not by entering one lucky shop: 15 keyed crates, 105 pairs, 0 sharing a title; 0 crates overlap the generic v2 pack; 0 ids reused across crates (G's sku fix holds at scale — the R24 vacuity dead at the source, not papered over in F's gate). 4 crates in Red Hill + 11 in Newtown = the manifest's 15 exactly, and the manifest lists nothing not on disk. SOURCING, NOT TIER — C was right and the gate follows C. `tier` is the charter's ladder rung and a mint atlas is ALSO rung 1: still a file, still offline, still deterministic. What differs is where the stock came from. 15/15 indexes declare sourcing, every one agrees with the manifest, a mint crate can never report as real, and the gate PRINTS it per room — provenance a human never reads isn't doing anything (R24's licence lesson, one round on). THE 404 TOLERANCE IS DELETED, NOT TUNED. R24 probed every keyed shop and ate a 404 per atlas-less one; F's smoke could only cope by NAMING them, and a tolerance is a confession. F filed the real fix as a contract ask rather than inventing it; G built the manifest; F now consumes it — the shell asks for nothing unlisted. Zero 404s because nothing absent gets asked for, not because the gate stopped looking. AND DELETING IT IMMEDIATELY CAUGHT A LEFTOVER: F had wired the boot preload but left a second blind probe at the door, 404ing on every keyed-but-unfetchable shop. While the gate said "8 probes, expected", a ninth was invisible too. A named exception starts protecting new bugs the moment the real fix exists. F's beta gate GREEN: distinctness · sourcing (real + mint rooms) · soft fall silent · ZERO 404s · 0 console errors, no attribution exceptions. Selfcheck ALL GREEN 156,212/156,212. TAG HELD — atlas-QA FAIL, 14 errors, and it is not the product. E's SLOT_ID_PREFIX = "sku_" (validate_atlas.py:73) applies to every pack; E reads `sourcing` at :178 but the slot-id check is sourcing-blind. All 14 mint crates fail; the real crate passes. A mint crate HAS no POS sku — it was never in that shop's till — so the rule demands what cannot exist, the same shape as R24's sweep demanding a cafe carry a godverseShopId. F measured the rule's intent and it holds: mint_<dealgod listing id>, non-positional, sorted by it, seeded bake, 0 ids reused across all 15 crates. Only the literal prefix fails. And G refused to go green the easy way for the best reason — F's own R24 collision grown up: a POS sku and a dealgod listing id are different id spaces, and filing one under `sku_` recreates that bug INSIDE the economy, where tier-2's sold-means-gone looks up POS skus. R24's collision entered the wrong shop; the same collision in the money layer sells the wrong record. F did not fix E's one line: E's file, C's contract, C's call as its author (the principle Fable ratified when C overruled `tier`) — and F is the party that benefits, since that line is the only thing between F and the tag. Cost of waiting: one line. Cost of F being quietly wrong: a gate that green-lights id-space collisions in the layer that moves money. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
55 KiB
PROCITY — Lane F progress (INTEGRATION & QA)
Session: 2026-07-14 · Author: PROCITY-F · For review by: fable
Round 26 (v5.0-beta — EVERY CRATE DIFFERENT) — F: the manifest consumed, the tolerance retired
Every crate is different, and F measured it rather than taking G's word. Not by entering one lucky shop — from the indexes of record: 15 keyed crates, 105 pairs, 0 sharing a title; 0 crates overlap the generic v2 pack; 0 ids reused across crates (G's sku fix holds at scale — the R24 vacuity dead at the source, not papered over in F's gate). 4 crates in Red Hill + 11 in Newtown = the manifest's 15 exactly, and the manifest lists nothing that isn't on disk.
Sourcing, not tier — C was right. tier is the charter's ladder rung, and a mint atlas is also rung
1: still a file, still offline, still deterministic. What differs is where the stock came from, which is
sourcing: real|mint. E built to C's contract over the brief on the principle that the contract's author
owns the contract's shape. F's gate asserts it: 15/15 declare sourcing, every index agrees with the
manifest, a mint crate can never report as real, and the gate PRINTS it per room — provenance a human
never reads isn't doing anything (the R24 licence lesson, one round on).
The 404 tolerance is deleted, not tuned. R24 probed every keyed shop and ate a 404 per atlas-less one; F's smoke could only cope by naming them — and a tolerance is a confession. F filed the real fix as a contract ask instead of inventing it; G built the manifest; F now consumes it, and the shell asks for nothing that isn't listed. Zero 404s because nothing absent gets asked for, not because the gate stopped looking. And deleting the tolerance immediately caught a leftover: F had wired the boot preload but left a second blind probe at the door, which 404'd on every keyed-but-unfetchable shop. While the gate said "8 probes, expected", a ninth would have been invisible too. A named exception protects new bugs the moment the real fix exists.
Gate: flags_check GREEN — distinctness · sourcing (real + mint rooms) · soft fall silent · ZERO
404s · 0 console errors, no attribution exceptions. Full record: LANE_F_NOTES §26.
Round 24 (v5.0-alpha — THE ALPHA COMPLETION) — the crate WALKS; F held the tag on A's gate
THE CRATE WALKS. Boot redhill_godverse, walk down Musgrave Road into Monster Robot Party,
riffle its own real crate, buy a real record at its real price. Proven falsifiably: room base =
assets/stock_godverse/3962749/ · titles 120/120 in its atlas, 0/120 in the generic pack · the
GPU samples stock_godverse/3962749/stock_record_atlas_0*.webp, 0 textures from the generic pack ·
bought "Abstract Latin Lounge II (Part II)" @ $15, cash 191 → 176, exact debit, count 0→1 ·
reboot restores 191/0 (gone-this-session, back next boot). Ladder re-proved: ?noassets → zero
network requests; keyed-but-atlas-less shop 2289 → 404 → parody, live; newtown_real → base
null, 350 items — F's wire is a no-op off the godverse path. Full record: LANE_F_NOTES §24.
F held v5.0-alpha anyway. The tree is red — 156,193/156,201 — and none of it is the product.
2 reds are goldens G's re-emit legitimately moved (A ran before G, so A could not pin them). 6 are
conflict #2: A's identity sweep contradicts Fable's own standing Ruling 2, which mandates mixed
caches ("merge census heroes WITH the donor's texture shops"). A cafe from OSM has no GODVERSE
identity and never will. G measured it, escalated it to "A's call, Fable's ruling", nobody ruled, and
it arrived at F.
F measured the hazard that gate guards: it does not exist. 10/10 and 18/18 unique ids, zero
duplicates; and partial keying does not mis-stock — F watched 2289 fall soft to parody in the
browser, exactly as charter risk #3 prescribes. A's own two checks disagree — validateTownCache
reasons it correctly ("Missing = tier 0 (soft). Duplicate = mis-stocked (hard). They are not the same
failure") and warns; the sweep hard-fails the same condition.
Why F didn't just fix it: F is the party that benefits. Changing a red gate to green, in another lane's file, to unblock F's own tag, on the one check guarding "never mis-stocked" with Monster Robot's real crate as the prize — that move would retroactively devalue every green F has ever reported. The cost of waiting is an hour. Recommended (A's call): the sweep follows A's own validator; A pins the four goldens in the same commit; F re-gates and tags. One commit.
Four findings:
- The honest-gate spec was itself vacuous. The brief specified id equality — but both packs number
items positionally (
rec_0000…), so all 120 atlas ids are also generic-pack ids. An id-equality gate goes green on the generic pack: the exact failure the vacuous-gate law was written to stop, reproduced inside its own first application. Titles (0 overlap) and the texture URL — the file the pixels come from — are what discriminate. F's gate asserts on those. - F's own selector was lying about the epoch's shop.
DBG.enterShop(3962749)→ "no shop matching": a GODVERSE shop has two ids and F's R22 selector knew only the plan id. Fixed. - A's uniqueness check is a silent risk-#3 hole (new — G didn't catch this): on a mixed cache every
texture shop maps to
undefinedand they all collapse into one Set entry, so it fails on the undefineds and cannot detect a real duplicate. Fix it over the defined ids — that makes the guard stronger, not weaker. - The licence flag stopped reaching a human. E's validator now sees the atlas (R23's blind gate is
closed ✓) but prints
provenance.licence(British) while G now emitslicense(American, per C) — soFLAG BEFORE ANY PUBLIC/COMMERCIAL RELEASE, on real product photos, silently never prints while the gate says OK. E, one line, G already specified it.
Round 23 (v5.0-alpha — THE FIRST REAL CRATE) — F HELD the tag
v5.0-alpha is NOT tagged. The crate is real; it has no street. G's 120 real records off a real
shop's POS are in the tree and byte-identically re-bakeable — genuinely the artifact the charter asked
for. Nothing in the game can reach them. #7a isn't a gate that failed, it's a gate that cannot be
run. R18's law: release rounds don't ship known breaches. Full record: LANE_F_NOTES §23.
F executed the merge that never happened (charter law #5) — main had no stock_godverse/** at all,
so the branch F was asked to tag lacked the round's headline. Review had happened, C had verified
pre-merge and passed; only the git merge was missing. Disjointness verified before merging, not
assumed. Zero conflicts → 43b035a.
What passed — everything except the crate. qa.sh --strict --matrix 7 passed · 0 failed · 0 warn;
MATRIX GREEN — 10 towns × 7 gates; selfcheck ALL GREEN 152,015/152,015 (was 161,300 — E retired
toowoomba); flags harness green, so the ?classic=1 covenant still holds through the merge. Tier 0
?noassets → zero fetches, zero console errors (the offline law holds); tier 0 default boot on the
godverse town; tier 1 (v2 town-wide) ?stock=real. Tier 1 (v5, per-shop) — the round's whole
deliverable — is never fetched. A, D, E and C's work is sound; only the rung this round was built to
add is unattached.
Three findings, in order of how much they cost:
- The atlas contract contradicts itself.
LANE_C_PUB:271publishesstock_shop_<id>_index.json; C's own loader atstockpack.js:25fetches${base}stock_${type}_index.json. Incompatible. G built runtime-compatible (so C's base-override check passed); E built contract-compatible (so E's validator can't see it). Nobody was wrong — the contract was. F recommends amending to G's shape; it's the only one the runtime can load. - The gate built to catch that was blind and green.
validate_atlas.pyglobs a filename that can't exist at runtime, finds nothing, andreturn 0— so it passes whether the atlas is absent, misnamed, or perfect. It had never seen one until F pointed it at G's by hand, which then surfaced deeper drift (E's code reads provenance top-level, E's own docstring says nested, G nested it;licencevslicense; a ceiling stale by one round). A gate that returns 0 on an empty set is not a gate. #7awould have passed vacuously. F walked into The Vintage Record (real shop, real road) and the crates filled with real covers — from E's 350-item town-wide v2 pack, not the crate. Zero requests tostock_godverse/, ever. Eyeballed as written, the gate goes green and proves nothing.
R24 order — three gaps, none F-only: A+G land a godverse_id (verified: every godverse shop
reports godverse_id: null; the schema has no such field, and C's rule is "C does not invent it") →
E builds redhill_real (one Overpass fetch — E's file, outward-facing; not F's to invent) →
C keys the pack cache by type+base (today a cache hit returns before base is read, so two stocked
shops collide and fail-soft breaks) → F passes the per-shop base and re-gates. F deliberately did
not build its half: untestable with no street and no identity field. Filed, not guessed.
Also: A's spacing warn earned on day one — with toowoomba retired, ballarat now warns at 255 m. The thin tail has a second member.
Round 22 (v4.0 — THE EPOCH CLOSE) — F closed it
- The blocking gate CLOSED. F's R21 re-measure made the tri diet blocking; B diagnosed, the driver
traced A→E, E fixed it, F re-measured: katoomba
venue_night221,935 → 108,365 (−51%), worst town 124,682 — the 200k stress edge is closed. Selfcheck 161,300/161,300 (A's 36 goldens + 23 towns). DBG.enterShop(selector)(Lane G's ask) — id · type · exact name · substring, most-specific-first.- The release tour →
docs/shots/release_v4/: Fremantle hero · Fitzroy mecca · Toowoomba thin tail · synthetic control ·?classic=1covenant. All posed through F's R21 cluster primitive — which earned itself twice: the first cut posed viastreet_noonand the mecca came out as bare bitumen; re-posed through the cluster, Fitzroy reads. - ⚠ Honest finding (filed v4.x): the thin tail does not prove the floor holds — Toowoomba reads as an empty road. The floor is a ratio, not a count: 0.008 shops/edge vs the heroes' 0.06–0.08. The frame ships labelled honestly rather than swapped for a flattering town.
- Docs (README v4 "the towns are the product", notes §22),
qa.sh --strict --matrixgreen, tagv4.0.
Round 20–21 (v4.0-beta THE FIVE TOWNS) — F never ran R20; closed R21
R20: F never ran (no gate, no tag) — the honest record is in LANE_F_NOTES §20. Unlike R18 (where F ran and held on evidence), the slot simply didn't execute; the round also left C's door-soak, B's selector index, and D's relocation finding open. R21 closed all four.
R21: the beta gate. Waves [A,B,E] → [C,D] → [F]. All five lanes in; F gated:
- Matrix 10 towns × 7 gates — boot/determ/district/roads/tram/noassets green on all ten; selfcheck
154141/154141;
qa.sh --strictGREEN. - Tram dimension (new) — B's R20 ruling verified exactly: Newtown runs 16 stops (was 149 — B's phantom
fix), Castlemaine 10; Katoomba/Fremantle/Bendigo fenced at 3/2/1 shops fronted. Needed a new seam:
the shell now exposes
window.PROCITY.tram(B builtrouteInfofor F's smoke; nothing published it). - ⚠ venue_night re-measure — recorded, premise falsified. A's cap worked (posters 438→111) but the density widening ate it: katoomba 200,965 (+965) → 221,935 (+21,935, +11%); bendigo 201k. Draws fine (151/300). Filed as R22's first item (the tri-diet backlog already lives there).
- Selector ruling — always in the HUD (the towns are the product), + the corollary that F's harness must hide the HUD for beauty shots (the R19 alpha shot's selector-in-frame was F's own gap).
- Beta money shot — Fremantle's real street at golden hour:
a corridor of shopfronts, footpaths, a crossing, and a genuinely busy crowd. Tag
v4.0-beta.
Round 18–19 (v4.0-alpha REAL ROADS) — F held R18 correctly, then closed R19
R18: F did NOT run — the gate would have failed by design, so F held the tag and filed the failure list (the alpha's charter deliverable). Real roads landed structurally but the selfcheck was RED (katoomba golden unpinned + poster-kerb breach on all 5 real towns) and the town was fragmented (20 shops over 799 edges = an empty field). Classic/default stayed frozen — the alpha changed nothing outside the cache path. Fable's verdict agreed: "F never ran — correctly."
R19: the close. A resolved the findings (fragmentation cull/join, poster clamp, goldens pinned), D re-measured, B shipped the town selector. F ran:
- B's
BIG_CITYone-liner (e6fcb7b, early):shops>120 || edges>200— real Katoomba's 799-edge graph now streams like a big city. 280k → ~12k tris. B proved it; F owns index.html. - The alpha gate —
town_matrix.pygrew aroadsdimension (a v2 cache must build the REAL graph,mode='roads'via the plan_osm report sink); classic/default proven untouched; budgets in the green. - The money shot — Katoomba's real main street: asphalt +
lane markings, footpaths, a pedestrian crossing, a walking crowd, gig posters, B's town selector in-frame.
PROCITY's look on real bones. Tag
v4.0-alpha. (Honest note: 19 real shops sit ~1/edge — a real street, not yet a dense strip; density is a v4.0-beta concern.)
Round 17 (v3.2 THE TAIL + THE SCOUT) — F: the town matrix + the close
The tail drained (drummer lean + bench-sit, wind sway, backline verify, --verify fix) and E's real-map scout landed (5 real AU town caches + A's cache contract + hardened plan_osm). F closed it.
- Real towns boot in the engine — the barrel re-exports
registerTownCache; the shell fetches + registersassets/towns/<key>.jsonbefore the plan generates (fail-soft; opt-in; never on default/classic).?plansrc=osm&town=bendigo_real→ Bendigo, 9 shops, 3-venue district, 0 errors. - Town-matrix smoke (
tools/qa/town_matrix.py,qa.sh --matrix) — 10 towns × 5 gates all green: 2 synthetic + 3 fixtures + 5 real caches, each boot / deterministic / in-budget (69–216 draws) / a 3-venue district / silent under?noassets. Castlemaine at the 6-shop floor still lands a district. The existing CityPlan contract eats real Australian geography — the v4 = THE REAL MAP evidence. - Close:
qa.sh --strict --soakgreen, docs (LANE_F_NOTES §17, README), tagv3.2.
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.