Commit Graph

28 Commits

Author SHA1 Message Date
type-two
7b26e45fa0 Lane B R33: THE WANTLIST in the crate panel · the arrival toast · the build-race fix the shot found
hud.js: THE WANTLIST section in the crate (non-empty only — no header over nothing): hunted
rows, ✕ stops hunting, refresh watches wants length so an open panel follows adds/clears.
THE FIX: R32's game surface BUILT only in street update() frames — a door entered fast after
boot had no crate/bar inside at all, and the interior tickGame() refreshed a UI that never
existed. Every gate idles on the street long enough to build, so green gates missed it; the
R33 money-shot script entered faster and exposed it. tickGame() now builds-or-refreshes in
ANY mode (shots are a detector, not decoration — filed in LANE_F_NOTES §33).
index.html: game.traveled at boot → '🚌 <town> — the ride cost a day. Day N' toast (save.js
already charged the fare and re-keyed the week before the shell read game.day).
2026-07-20 19:01:40 +10:00
type-two
bb30767b62 Lane B R32 (§31.6 queue 1–3): the crate lives in shops · cluster-pose spawn · dawn reads dawn
hud.js: #pc-game rides document.body (position:fixed, z 30) instead of the mode-hidden street
root — day/cash/CRATE/SLEEP are YOURS inside a shop too (the playtest's 'crate at the counter').
C toggles the crate ANYWHERE; the surface yields to the dig/sell cards and the map (they own
the screen). tickGame() exported so the interior/map frame branches keep it live (buys update
the count while you shop); dispose removes the body-mounted wrap.
index.html: the frozen spawn (-96,9,east) was tuned for the synthetic fixture — on real towns
it faced dirt (§31.6-1). Non-classic boots now spawn ON the main-street footpath door-line
(block kind 'mainstreet', both generators; every-door fallback) at the door nearest the shop
cluster's heart, facing the LONGER run of shopfronts down the strip's dominant axis. Pure plan
math, zero draws — no stream moves; ?classic=1 keeps the frozen pose forever.
lighting.js: dawnSky opt (shell passes high-cirrus, null under classic) — the DAWN segment
swaps the dome off the golden-SUNSET default that read dusk-orange (§31.6-3), and swaps back.
setSky() is now an explicit override: weather's rain/overcast dome always wins over base+dawn.
2026-07-20 18:26:56 +10:00
m3ultra
046668e5af feat(gig): club dancers play real dance clips, not procedural sway
loadPedFleet gains dance:!CLASSIC (mirrors the sit/look gate) → fleet.danceClips
= 4 mesh-free mixamorig club dances (party/medium/drink/sway). _make picks one
per dancer off a fresh gigdance seeded stream (zero impact on existing draws /
the same-seed-same-crowd covenant), spawnRig plays it, and update() drops the
fake bounce for real-clip dancers (procedural sway stays as the classic/noassets
fallback). ?classic fetches nothing, byte-identical.

Verified: default boot fetches all 4 dance GLBs (gated load runs), both modules
parse + export clean, page boots. Same clips + _canon/_rotOnly/spawnRig proven
animating in 90sDJsim (its crowd/rigs.js is this file ported).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 02:11:55 +10:00
m3ultra
50385c0f08 Lane F R31 wave 1 (v7.0-alpha close): THE DIG FLIP — the alpha-blocker Fable's playtest found. DIG_ON = flagOn('dig') (default-ON, ?dig=0 opt-out, ?classic=1 off — the v3.1 pattern; the v2-era opt-in survived 6 epochs past the README's 'dig on' claim because every R30 gate booted dig=1 explicitly: the explicit-flag blindfold). Fenced forever: default_boot_gate asserts dig REACHABILITY on a NAKED boot (E at a bin → digActive true), classic_regression asserts dig INERT at the bin (zero pcdg DOM, measured not assumed). PROCITY.flags gains dig. Splash de-staled ('Every door opens.' — no more '(soon)'; controls line carries E riffle/sell · C crate · SLEEP to save) + README manual row (sell at counter · C crate · SLEEP = save/advance/rotate). PROCITY_QA_PORT env override (flags_check, interior_scale_check, town_matrix) so the suite runs port-isolated instead of silently reusing whatever holds :8130. Verified both ways on :8951 (naked boot digs + closes clean; dig=0 and classic zero dig DOM, classic ZERO storage calls; noassets digs parody, 0 errors). qa.sh --strict --matrix on :8931: 7/0/0/0, flags_check 0 fails 0 warns, MATRIX 10 towns green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 16:37:02 +10:00
m3ultra
2c9cb94b8e Lane F R30 wave 3 (v7.0-alpha ledger #5 + §9.4): THE GATES + the sell routing — E chain aimed-bin→dig · counter+sellable→C's sell card (removeFind-first onSell, veto-safe) · forgiving-bin · shelf; aim-priority amendment measured both ways (counter-adjacent bin sells, wrong-aim bin still digs); 3 shell seams (sellOpen unlock, sellActive guards). Five STRICT suite gates in flags_check: routing live-loop ($9 dig → +$4 sell → HUD $186·CRATE 0), save/load determinism (byte-equal state+export, plan fp unchanged, weekNight re-key), no-pump 5/5 strictly negative (Σ−$30) + C's negative control (wallet.buy invoked-and-false ⇒ recordFind unreachable, positive arm discriminates), classic purity (Storage-prototype instrument, 0 calls classic/game=0, positive control sees procity-save, plan fp game-on==off), rotation over VERTEX DATA (day 1/2/3 distinct, re-entry + cross-boot byte-identical, game=0==day1). qa.sh --strict --matrix: 7 passed · 0 failed · 0 warn · 0 skipped, MATRIX 10 towns green. NO TAG per brief.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 15:10:08 +10:00
m3ultra
207bcffb54 Lane F R30 (v7.0-alpha ledgers #1+#3): THE SAVE CORE + SLEEP=SAVE=TOMORROW — save.js (procity-save/1, delta law by shape, loud reject + stash, beforeunload), game-backed wallet facade on the proven seam, buy seams record the collection (type/sku|slotId/title, C's §9 asks), day-salted stock rotation (stk-* seam in interiors/layout [marked], dig binSeed; day 1 = pre-v7, REAL never rotates), gig weekNight = (day-1)%7 (amended from day%7 with the measurement, §30.3), wake at DAWN. classic/game=0: layer never constructed, ZERO storage touches measured. Verified 7 legs green in fresh contexts; qa.sh --strict 6/6, 0 warn 2026-07-18 14:26:35 +10:00
m3ultra
10025d4082 Lane D R29 (v6 Spike 1): look.glb bound and wired — peds glance, feet planted (wave 0)
The spike reaches the game. E's look.glb (mesh-free, 65 joints, 6.5s 'Look') is bound
through the fleet gate; street peds now glance around during window-shop stops. `lean`
is absent and never existed (E's R28 measurement). Goldens untouched — clips sit outside
every plan hash; the synthetic anchor stays R27's amended 0x5f76e76.

WIRED: loadPedFleet(base, {sit, look}) -> fleet.lookClip, the exact twin of the R16 sit
gate; the shell passes look:!CLASSIC so ?classic fetches NOTHING (a raw fetch would have
breached the zero-fetch-delta covenant — E flagged it, the gate is the answer).
makeActor gains lookA, played only on setLooking(true) — crossfaded (0.3s), not snapped
like sit, since idle->idle-variant reads naturally and there's no replant for a fade to
fight. sim.js gains a dedicated `glance` rng stream, rolled ALWAYS (deterministic) but
only flipped when a clip exists => classic inert at the source. Mutually exclusive with
bench-sit (sit rolls first at 35%, glance takes 40% of the rest). RigPool threads
lookClip; release snaps the glance off so no rig is pooled mid-look.

THE FINDING — my own prediction was wrong, and the measurement caught it. I wrote that a
STANDING clip needs no foot replant ("no hip descent to recover — that trap was sit's
alone"). Measured over the full loop: idle keeps the lowest bone within 4cm of the ground
(-0.04..0.00); look.glb ranges -0.009..+0.205 — the ped HOVERS up to 20.5cm, drifting
through the loop. Same trap, different coat: _rotOnly drops the Hips POSITION track for
rig-height independence, so the clip's authored weight-shift dip can't move the hips and
comes out as the FEET RISING. Sit's one-time replant can't fix it — the float varies per
frame.

FIX: plantFeet() — the per-frame twin of sit's replant. Reset to bind plant -> measure
posed feet -> drop inner by float/scale. ABSOLUTE (reset->measure->correct), never
incremental, so it cannot drift. Reproduces the authored motion exactly: the hips dip
relative to the ground instead of the feet leaving it. Scale-aware like sit's. Foot bones
cached once; cost paid only by glancing peds, on frames their mixer ran (both mixer sites
— the drummer's post-mix lean taught that coupling rule).

PROOFS: foot float 0.205m -> 0.000m (pinned); head yaw sweep span 1.735 (-0.85..+0.89) so
the glance still animates; ?classic — no look fetch, no Look action on any rig, glance
never flips (0); identity signature unchanged, no glance term; sit AND glance never
simultaneous (0); 0 NaN; goldens 0x5f76e76 untouched. A glancing ped is NOT tagged
seated/posed — standing pose at standing stature, so F's no-giants gate needs no arm.

D->F: the pose gate HAS ITS SUBJECT — un-SKIP it. Fresh ?localdepot=1 boot shows a ped
glancing on the footpath, head sweeping, feet planted.
Spike 2 readiness: plantFeet() is the general machinery the brief asked for ("data, not
new code") — riffle and wall-lean should land as clip + roll; the lean's wall-contact
placement is the only genuinely new part.
FLAGGED (A's file, A rests): selfcheck.js:301 still says "the synthetic golden above stays
0x3fa36874" while line 267 pins the amended 0x5f76e76. A stale comment, not a rule — but
the same species as the epoch's five holds, so: flagged, not touched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 18:44:07 +10:00
m3ultra
39cfc3d3ed Lane F R27 (v5.0): the tier-2 reader — pick-then-omit, and the server killed mid-session
#2 THE READER, built to C's §8 ruling (direct wire, no hook) and to what the waves measured,
not to the brief's letter:
  · `pack.gone` set, `price` updated IN PLACE — items[] never added to, removed from, or
    reordered, because its identity AND ORDER are the pick's stability (C §8.3). Filtering the
    array instead reshuffles the crate: C measured ONE sale changing 21 OTHER records.
  · fire-and-forget at room build, 1200ms abort, etag-cached, circuit-broken on first failure.
    The dig never blocks on the network (charter risk #1). No await anywhere near the door.
  · fires ONLY for a real-sourced shop. G's fence 404s a mint shop, and asking anyway would be
    R26's blind probe wearing a server. The manifest already knows which is which.

TIER 2 IS OPT-IN (`?live=1` / `?live=<url>`; absent → byte-identical to the beta). That is the
R26 lesson applied to a server: a default boot that probed for a GODVERSE host would ask a
question with no answer on every machine that isn't John's. Tier 2 is a place you go, not a
thing that happens to you. Auto-discovery is a v5.x question with a reachability contract.

PROVEN IN THE BROWSER (formal smoke class still to land):
  · sold-means-gone, via G's make-fixture (production `gone` is EMPTY — 0 sales since
    2026-07-01 — so a live assert would pass vacuously forever; G built the subject before the
    gate could be born blind): 3 sold → gone[3] → items[] 120→120 IDENTITY AND ORDER INTACT,
    117 survivors, COLLATERAL 0. C called this: both pick-then-omit and filter-the-array hide
    the sold record, so "the gone item never renders" cannot tell them apart — the obvious
    assertion is vacuous and goes green. Collateral is the one that discriminates.
  · KILL THE SERVER MID-SESSION → enter took 13.1ms, worst frame gap 14ms, the crate still
    renders its own 120 real covers, and ZERO console errors. Charter law #1 proven by
    execution instead of assertion — the thing A correctly refused to retire from the risk
    list until this gate went green.

Recorded, not hidden: after a mid-session kill the etag-cached `gone` persists for the session,
so a killed server does not resurrect sold records mid-walk. That is tier-1-plus-last-known, not
tier-1-exactly. It is the honest behaviour (a network blink must not re-stock a shop) and a
server-down BOOT is still pure tier 1 — but it is a nuance the brief's "degrades to tier 1
exactly" doesn't cover, so it goes in writing rather than in the gaps.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 14:34:42 +10:00
m3ultra
528829eeba Lane F R26 (v5.0-beta): the manifest consumed, the tolerance retired — tag HELD on the mint-id rule
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>
2026-07-17 11:38:44 +10:00
m3ultra
29942002eb Lane F R24 (v5.0-alpha): THE CRATE WALKS — the per-shop wire + a gate that can't lie
You can boot redhill_godverse, walk down Musgrave Road into Monster Robot Party, riffle its
own real crate and buy a real record. Proven falsifiably, not by eyeball:
  base      assets/stock_godverse/3962749/ (its own, not the town-wide)
  TITLES    120/120 the shop's atlas · 0/120 the generic pack
  TEXTURES  2 from stock_godverse/3962749/*.webp · 0 generic — the pixels' own file
  BUY       rec_0000 "Abstract Latin Lounge II (Part II)" @ $15 → cash 191→176, exact
  REBOOT    191/0 restored — gone-this-session, back next boot
Ladder: ?noassets → ZERO network requests · keyed-but-atlas-less shop → 404 → parody, live ·
newtown_real → base null, 350 items: the wire is a NO-OP off the godverse path.
flags_check GREEN (0 fails, 0 warns).

#6a THE WIRE: godverseBaseFor(shop), exported and used by BOTH the shell's boot preload and
the room's lookup — C's cache identity is the LITERAL (type, base) pair, so two sides building
that string differently would drop a real shop to parody, a bug indistinguishable from "no
stock" by eye. One function, one string, one key. Gated on stockReal, never the id alone.

#6b THE GATE: smoke_real_crate + DBG.stockInfo() — permanent, and it cannot pass without
touching its subject (SKIPs with a printed reason when the town/atlas is absent).

FINDING — THE BRIEF'S OWN HONEST-GATE SPEC WAS VACUOUS. It specified id equality. Both packs
number items POSITIONALLY (rec_0000…), so all 120 atlas ids are generic-pack ids too: an
id-equality gate goes GREEN on the generic pack — the exact failure the vacuous-gate law was
written to stop, reproduced inside its first application. Ids there are slot numbers, not
identity. Titles (0 overlap) and the texture URL discriminate; F asserts on those.

FINDING — THE ID SPACES COLLIDE, and it bit F's own selector inside the anti-vacuous gate.
Plan ids (1..N) and godverse ids (31, 767, 3962749) share a numeric space: Silky Oak's godverse
id is 31 and another shop's PLAN id is 31, so enterShop(31) silently entered "Wholefood Cafe"
and the soft-fall assertion PASSED ON AN UNKEYED CAFE. Fixed both ends: 'g:<n>' selects a
godverse id explicitly, a bare number stays the plan id and now REPORTS the collision, and the
smoke asserts it landed in the shop it asked for before asserting anything about it.

FINDING — F'S OWN GATE CRIED THE LOUDEST WOLF WE OWN. classic_regression reported "plan
fingerprint != golden 0x3fa36874 — determinism/prime-law broken" while the covenant was
provably intact. F wrote it in R16 as `hash_ok and returncode == 0` — two assertions, ONE
verdict, reported with the fingerprint's message — so any unrelated selfcheck red screamed that
the byte-identical-forever covenant had broken. Two assertions, two verdicts now. It isn't
enough to fail for a reason; you have to fail for YOUR reason.

FINDING — fail-soft-by-404 vs the 0-console-errors law. The boot preload must resolve a keyed
shop's pack before the door opens (getStockPack is sync), so it probes blind: 9 of Red Hill's
10 keyed shops have no atlas → 404 → parody. That IS fail-soft working, and it is also 8
console errors no .catch() can suppress. Fix is not to loosen the law but to stop probing for
what isn't there: an atlas index in G's namespace (or hasStock on the cache entry, A+G). Filed
as a contract ask, not invented. Until then the smoke counts and NAMES the probes and fails on
any other error — tolerance stated out loud.

Verified the lift is clean: cache 10 keyed → plan 9 keyed, every one a real secondhand shop.
No cafe keyed, zero duplicate ids — there is no mis-stocking.

F did NOT touch A's identity sweep or E's validator. F was the party that would benefit, and
changing a red gate to green in another lane's file to unblock F's own tag would retroactively
devalue every green F has ever reported. Filed instead — and R25 has since landed A's
reconciliation and the six pins, which is the right hands doing it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 08:43:29 +10:00
m3ultra
201a2bb868 Lane F R21 (v4.0-beta close): the beta gate — tram dimension, the re-measure, the beta shot
All five lanes in (A's venue cluster bias, B's selector-from-index, C's density door-soak, D's relocation
verify PASSES, E's 22-town pack non-gating); F gated and tagged.

- town_matrix.py: a `tram` dimension — B's R20 shop-adjacency ruling verified EXACTLY (newtown runs 16 stops
  after B's phantom-stop fix, castlemaine 10; katoomba/fremantle/bendigo FENCED at 3/2/1 shops fronted, all
  below the 5-shop floor). 10 towns x 7 gates: boot/determ/district/roads/tram/noassets green on all ten.
- index.html: expose window.PROCITY.tram — B built `routeInfo` FOR F's smoke but nothing published it; F owns
  the shell, so F wired the seam.
- RECORDED (ledger #6b — the instruction was "record the new number"): the venue_night re-measure. A's cap
  WORKED (posters 438->111) but E's density widening ate it — katoomba 200,965 (+965, R19) -> 221,935
  (+21,935, +11%); bendigo 201k (+0.5%); fremantle/newtown/castlemaine in budget. Draws fine everywhere
  (151/300 — half budget); tris-only, at the worst night stress view. Filed as R22's first item, where the
  tri-diet backlog (instrument LOD, tram tri diet) already lives. katoomba is the outlier: 966 edges, 72 shops.
- Ruling (ledger #6d): the town selector stays ALWAYS-IN-HUD, not ?dbg-gated — THE REAL MAP's product IS the
  towns. Corollary (F's own gap): money shots hide the HUD; the R19 alpha shot had the selector in-frame
  because F's harness screenshotted the full viewport.
- Beta money shot: Fremantle's real street at golden hour — a corridor of shopfronts, footpaths, a crossing,
  gum trees, and a genuinely busy crowd (the density widening, visible). 126d/167k tris, HUD hidden.
- docs: LANE_F_NOTES §20 (the honest why-R20-had-no-tag record) + §21, README beta paragraph, F-progress.

qa.sh --strict GREEN; selfcheck 154141/154141 (A's re-pinned goldens hold).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 21:37:04 +10:00
m3ultra
e6fcb7b365 Lane F R19 (v4.0-alpha): B's BIG_CITY one-liner — big-graph towns stream like big cities
Real towns can have FEW shops but a HUGE road graph (real Katoomba: 20 shops / 799 edges / 5 km), so the
shop-count-only heuristic left them on small-town streaming and blew the tri budget (280k > the 200k gate).
Extend the trigger to the graph: BIG_CITY = shops>120 || edges>200. B proved the effect; landed EARLY so
D/B's post-fix re-measures see it (per the R19 order).

Verified: katoomba_real 799 edges -> BIG_CITY -> 61 draws / ~12k tris (was 280k), 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 17:19:08 +10:00
m3ultra
e4a49b5bc8 Lane F R17 (v3.2): real towns boot in the engine + the town-matrix scout gate (ledger #7)
F wired the last mile of the real-map scout and gated the whole matrix.

- index.js barrel re-exports registerTownCache/validateTownCache; the shell fetches + registers
  assets/towns/<key>.json before generatePlanFor when the town isn't a checked-in fixture — so
  ?plansrc=osm&town=bendigo_real boots a REAL AU town in the engine (the gap: E's caches were on disk +
  in the node selfcheck, but the shell never loaded them → silent Melbourne fallback). Fail-soft
  (404 / invalid / ?noassets -> fixture fallback); opt-in, never on the default or ?classic path.
- tools/qa/town_matrix.py (opt-in qa.sh --matrix): boot / determinism / budget / district / ?noassets
  across 10 towns (2 synthetic hero seeds + 3 osm fixtures + E's 5 real AU caches). ALL 5x10 GREEN —
  Castlemaine at the 6-shop floor still lands a 3-venue district. The existing CityPlan contract eats real
  Australian geography: the evidence John charters v4 = THE REAL MAP on.
- docs: LANE_F_NOTES §17 (the town x gate table), README real-town row, F-progress R17.

qa.sh --strict --soak GREEN 7/7. Verified: ?plansrc=osm&town=bendigo_real -> Bendigo, 9 shops, 3 venues, 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 15:23:15 +10:00
m3ultra
a4946b7ca2 Lane F R16 (v3.1 THE FLIP): defaults on + ?classic covenant + seated-stature gate (ledger #1, #3)
The town shows its best by default. gigs / weather / winmap / tram flip ON (each keeps a ?flag=0 opt-out;
?classic=1 forces the exact v2 boot). The prime-law covenant MOVED from "flags off" to "?classic=1" —
byte-identical forever (synthetic fingerprint 0x3fa36874). The default boot is now the full experience,
deterministic to the gig golden 0xb1d48ea1 (A's R16 corner-poster re-pin).

- index.html: CLASSIC + flagOn(); gigs/weather/tram default-on; loadPedFleet({sit:!CLASSIC}) for the seated
  drummer (?classic keeps the zero-fetch-delta covenant); a window.PROCITY.flags intent surface for the gates
- buildings.js: winmap default-on + classic-aware (the one cross-lane flip line the flag placement requires)
- flags_check.py: flags_off_regression -> classic_regression (?classic=1 byte-identical); a new default_boot_gate
  (all four flags on, gig layer present, gig golden, budget); every gig smoke re-pointed at the DEFAULT boot
- seated-stature gate (ledger #3, published for D): interior_scale_check.py + flags_check.py accept
  fig.userData.procitySeated at stature [0.9,1.5] m (the drummer); standing figs stay [1.4,2.0]
- qa.sh flags-harness gate name updated (classic regression + default-boot gate)

Verified: ?classic byte-identical (0x3fa36874, gig layer absent); default boot = the full town (14 gigs, 15
posters, tram, gig golden green, 112 draws @ the venue block); the seated drummer passes at 1.32 m stature;
district (3 venues / 3 genres), continuity, and cover all green on the default boot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 13:20:43 +10:00
m3ultra
687d23f654 Lane F R15 (v3.0): identity continuity — wire D's tonight-roster into the crowd (ledger #3)
The ped you followed into a venue now turns up in its crowd. D published the seam in R14; F wires the three touches:
- interior_mode.js: crew.spawn({ roster: rosterOf(shop.id) }) — the front crowd slots become tonight's roster
- index.html: rosterOf=(id)=>citizens.tonightRoster(id) into interior_mode; onAdmit=(e)=>citizens.recordVenueEntry(id,e)
  on the queue (each admit relays into the roster); the clear is automatic on the existing setGig(id,false)
- flags_check.py: smoke_continuity — asserts the seam (crowd includes roster-cap, pedIndex in tonightRoster),
  empty-roster injects nobody (shell side of D's byte-identical law), + ledger #5 settled-tris honesty

Verified: 2 queue admits carry into the crowd; empty roster 0-injected; settled interior 71k->182k tris
(C's finding — interior gate is draws <=54, no violation). 0 console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 11:19:19 +10:00
m3ultra
a358c5d9ef Lane F R13 (v3.0-beta, the district): per-venue gig state + walla/applause + queue wiring; qa --strict 6/6
Wires A–E + D's district together and fires it. Seed 20261990 → "Boolarra Heads": 3 venues, 2 playing
tonight (The Exchange Hotel pub gig-pubrock + an RSL gig-covers, one dark), Screaming Utes $10 on the door.

- gig_state.js → PER-VENUE latches off the shared procity:segment spine (one per venueShopId); all three
  hard-won R12 laws kept. New runtime surface window.PROCITY.gigs.byVenue + onOf/openOf/gigOf/coverOf/
  bandNameOf/paidOf(id) + markPaidOf/venueShopIds; the R12 single-venue alias kept for one round.
- interior_mode.js: crowd-walla rides the interior tone layer under the live band bed while `on`; an
  applause sting fires once on the on->done edge. DELETE the GIG_BED bridge — debt #1, and it was a LIVE
  BUG: E renamed pubrock-live->gig-pubrock, so the bridge (gig-pubrock->pubrock-live) pointed at a dead
  key => the band would have mimed in silence. room.audio.gigKey (already the manifest key) feeds directly.
- index.html: per-venue cover charge (a night at two venues is two covers), concurrent per-venue setGig
  surges, and the outdoor VenueQueue lifecycle (D shipped the class + left the street-side seam to F:
  spawn at doors off B's queueZoneFor, drive each frame, dispose by done), exposed as queueCountOf(id).
- interior_scale_check.py: human-size assert now measures STATURE (crown-foot, platform-independent);
  world-crown ceiling-clip assert kept as its own line (debt #6).
- flags_check.py smoke_gigs -> THE DISTRICT: band->4, per-venue loop (every gigKey resolves across 3
  genres, crowd <= its own watchPoints, no-giants by stature), street budget at the busiest venue block,
  the queue assert; plus the R12 determinism/cover/noassets/flags-off arms.
- CITY_SPEC: pin the window.PROCITY.gigs runtime surface. gig_shot.py -> r13 interior + venue_night shots.

qa.sh --strict GREEN 6/6, 0 warn. Interior 63 draws/35k tris; street @ venue block 121 draws/51k tris;
band+crowd stature 1.61-1.81 m under a 4 m ceiling; flags-off fingerprint 0x3fa36874 unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 00:22:03 +10:00
jing
2498fdc892 Lane F R12: wire the v3.0-alpha gig layer (?gigs=1) — state machine, cover charge, band+crowd, gig audio
F last: five landed lanes → one Friday night. Seed 20261990 → The Thornbury Hotel,
tonight SCREAMING UTES, $10 on the door. qa.sh --strict GREEN 6/6.

- gig_state.js (new, F-owned): quiet → doors (DUSK) → on (NIGHT) → done (DAWN) → quiet.
  Rides lighting's procity:segment event (a poll only sees the segments it samples, and
  missed the night roll entirely); `state` is a getter because B's audio reads it from its
  own rAF while the player is inside a shop.
- ?gigs=1 seam: custom_bands.json fetched in the bootstrap (no fetch flag-off or ?noassets)
  → generatePlanFor(seed, src, {gigs:true, customBands}). 7 of John's 10 names fill the week.
- Cover charge on the R8 buy seam, zero new UI: paid debits once with a toast, re-entry the
  same night is free, broke → polite knockback, free nights walk straight in.
- interior_mode: opts.gig → C's gigKey; D's GigCrew (band 3 + crowd 8, 3 dancing) at C's
  stage/watch points; both disposed with the room (leak-free over 4 cycles).
- Cross-lane fix at the glue: C emits gigKey 'gig-pubrock', E shipped the bed as
  'pubrock-live' — unresolved the pub plays to a silent room and nothing errors. Bridged
  here; C/E/Fable owe CITY_SPEC a contract line. Details + 2 more findings in LANE_F_NOTES §12.
- smoke_gigs (16 gates): schedule determinism, band==3, crowd ≤ watchPoints, dance mix, bed
  resolves, ≤350 draws (47 rig / 171 placeholder), no-giants by STATURE (the band stands on a
  0.32m deck, so world-crown fails a correct band), cover ruling, ?noassets+?gigs.
  Flags-off regression gains a v3 arm: no state machine, no plan.gigs, no pub, no venue geo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 21:09:56 +10:00
m3ultra
f7dd44f55a Lane B (Streetscape): round-11 audio — WebAudio engine (street side)
- web/js/world/audio.js: one AudioContext unlocked on first gesture; day/night ambience crossfade, rain (weather.intensity), footsteps, shop-door music spill (nearest open music-shop, distance-gain), tram rumble+bell, enterShop SFX. Consumes Lane E manifest.audio (3x retry). Self-ticks off window.PROCITY.
- House audio law verified live: silent pre-gesture (0 fetches), ?mute=1 silent surface (0 fetches), ?noassets=1 zero audio/manifest fetches, lazy-load (8.7MB<=25MB), no per-frame alloc.
- window.PROCITY.audio for Lane F: playInterior({musicKey,toneKey})/stopInterior (street beds duck while inside), playSfx, setMasterGain, mute, state diag. Confirms Lane C room.audio={musicKey,toneKey} contract.
- Small guarded [Lane B R11 audio] loader in index.html.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 16:00:31 +10:00
m3ultra
5a24f8aa52 Lane F R9 F1+F2: interior presence + tram + buy-anywhere wiring; harness graduated + new smokes
Wiring (F owns index.html + interior_mode.js):
 • Interior presence (C->D->F seam): occupancyOf closure -> interior_mode spawns browser rigs at
   C's room.browsePoints (one per patronage occupant, cap 3); freed by exit()'s keepers.disposeAll.
   Door points now carry shopId for D's occupancy truth.
 • Tram (Lane B, ?tram=1): createTram + update in loop (2 draws, non-blocking).
 • Buy-anywhere (Lane C C2): E aimed at a book-spine/toy-box buyMesh buys over the same wallet
   (collapseBuyItem + toast); preload book+toy packs too. Records keep the dig.

Harness: graduated buy-v0 / patronage / book-toy stock warn->STRICT (katoomba golden already
strict). New warn smokes: interior presence (browsers==min(occ,3), dispose clean), shelf-buy
(book spine bought, cash drops), tram (present). Book-stock check now counts isStock OR buyMesh
(C2 tags book spines buyMesh, not isStock). flags_check GREEN 0/0; qa.sh --strict GREEN 5/5.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 11:42:44 +10:00
m3ultra
9cc00ad29c Lane F R8: wire town/weather/patronage/buy + graduate harness + new smokes
Shell seams (F owns index.html): A &town=<key> -> generatePlanFor(seed,'osm',{town}) (Katoomba);
B weather (createWeather on ?weather=1; PROCITY.weather={state,intensity}, {clear,0} off; update in
loop); C session wallet bound to the dig BUY (getCash/onBuy in interior_mode); D patronage door
points -> citizens.setShops + ?patronage=0 off-switch + setWeather each frame.

Harness: 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). Determinism gate: pinned osm/katoomba golden 0x0f652510 keyed on (seed,plansrc,
town) + fixed a hex zero-pad bug the katoomba golden exposed (0x0f652510 vs unpadded 0xf652510).

No patronage baseline re-pin needed (nets fewer draws, within tolerance). qa.sh --strict GREEN 5/5.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 09:09:11 +10:00
m3ultra
b94f86b49f Lane F R7 F2: harness → strict + wire ?stock=real (real GODVERSE covers in the crates)
qa.sh: flags harness warn_gate → run_gate — flags-off regression + the 4 existing flags +
all-on combo are now STRICT (a harness FAIL fails qa). New flags stay warn-level in-harness.

?stock=real wiring (F owns the shell + interior bridge): shell preloads the record stock pack
(preloadStockPack('record'), fail-soft, off under ?noassets) + passes stockReal to the bridge.
interior_mode builds makeStockAdapter(getStockPack(shop.type)) and passes it to BOTH buildInterior
(static crate sleeves) and dig.open (riffle) — null pack → parody canvas (Lane C fail-soft).

Harness: added stock=real smoke (assert non-parody = batched userData.isStock atlas meshes > 0;
verified 7 real sleeves in the record shop) + weather=1 smoke (auto-skips until Lane B lands),
both warn-level (decision #4). qa.sh --strict GREEN (5 gates); crates now show real covers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 01:56:14 +10:00
m3ultra
0b84560457 Lane F R7 F1: roster flip — streamed roster is now the DEFAULT (prime-law amendment)
The first deliberate flags-off baseline change. On D's GO (43edabf: E1 ped sub-mesh merge
447188a validated → ~1 draw/near-rig → full density 241 worst-street draws <=300, leak-free).

index.html: chunk-streamed roster default-on (chunkStream:{radius:2}); ?roster=v1 restores the
old fixed roster (escape hatch); ?roster=stream still accepted (now a no-op). Hours-aware
setNightLivelyChunks keeps the open-late block lively at night.

Flags-off regression baseline RE-PINNED (same commit, prime-law amendment):
  OLD (roster-off, v1.1):        163 draws, 19000 tris
  NEW (roster default-on, R7):   164 draws, ~66000 tris
Draws barely move — E1's merge makes each near-rig ~1 draw (exactly what gated the flip). The
tris jump is the streamed crowd (D worst-view 65,899); it is frame-variable, so the drift WARN
is now DRAWS-ONLY, tris guarded by the STREET_TRIS_MAX hard cap. PLAN GOLDENS UNCHANGED
(synthetic 0x3fa36874, osm 0x34cfdec0).

Also fixed the harness roster probe (read a nonexistent prop c.streaming → was blind to
streamMode) + flipped the assertion to REQUIRE streamMode on default boot + added a ?roster=v1
escape-hatch check. flags_check GREEN; qa.sh --strict green; 0 console errors both modes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 01:41:27 +10:00
m3ultra
781baea4e2 Lane F R6 F2: wire ?plansrc=osm shell selector + pin osm golden + dig nearest-bin fallback
A landed the plansrc seam (52eb109); F owns the shell bootstrap. index.html: ?plansrc=osm
-> citygen.generatePlanFor(seed,'osm') (real-data 'Melbourne' 95 shops); default synthetic
'Boolarra Heads' unchanged (prime law). scaffold_check.mjs: pin BOTH goldens keyed by
(seed,plansrc) — synthetic 0x3fa36874, osm 0x34cfdec0 (deterministic) — + assert the selector
routes synthetic|osm. flags_check auto-detects + smokes plansrc + the all-on combo (4 flags).

interior_mode.js: restored binUnderAim's nearest-bin fallback (Lane C test-page parity) so E
riffles a nearby bin without perfect aim / before the bin GLB async-loads — fixes the dig
smoke's raycast-miss under fast headless AND improves real UX.

qa.sh --strict GREEN; flags_check GREEN (all 4 flags + all-on combo, 0 console errors).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 22:59:45 +10:00
m3ultra
26d68cdb4f Lane F R5 F2: wire ?dig=1 crate-riffle into interior mode
C shipped dig.js + the flag but left the in-game input/mode hook to F (LANE_C_NOTES C2).
interior_mode.js (F-owned): aim at a userData.kind==='bin' fitting + press E -> createDig +
dig.open (per-bin seed binSeed(shop.seed,pos)); the dig owns the frame (renders dig.scene,
suppresses interior walk); WALK OUT/Esc closes back to the room; closed on interior exit.
Shell (index.html): ?dig=1 -> dig: opt; procity:digOpen releases pointer-lock (riffle is
cursor-driven); the unlock->leaveShop guard reads interiorMode.digActive so opening a bin
isn't read as walking out; canvas re-locks for interior walk after close.

Fresh-chromium smoke: E opens the riffle (seeded sleeves + prices render), WALK OUT closes
to the interior, leak-free (steady-state geo/tex flat over 3 open/close cycles), 0 console
errors. Flag off => no listener, dig stays null => byte-identical to v1 (prime law).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 22:03:31 +10:00
m3ultra
aad9baa584 Lane F R4: gate 3 PASS (draws 138/tris 31k) + remove dead setExposure call
Gate 3 (budget) official re-measure vs committed decimated peds (E1 518678d, D2
signed off a5e4b64): busiest node, pop 200, midday, 12-yaw peak -> draws 138 (<=300),
tris ~31k (<=200k). Baseline was 372k. Green.

D3 (a5e4b64) made the impostor toneMapped:true so exposure is global via
renderer.toneMappingExposure; citizens.setExposure() became a no-op, so the F1 wire is
removed (removing it before D's commit would have regressed night brightness). Boots
clean, 0 console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 19:02:19 +10:00
m3ultra
9416d0ae08 Lane F R4: wire citizens.setExposure (F1) + permittedMax storeys-checker fix (F2)
F1: pass renderer.toneMappingExposure into CitizenSim each street frame so mid-tier
impostors track the animated day/night exposure (per LANE_D_NOTES). Verified: boots
clean, 0 console errors, exposure animates night 1.18 <-> midday 0.98.

F2: scope the consistency storeys check to permittedMax = max>=2 ? min(max+1,3) : max
(Lane A's corner-anchor rule, LANE_A_NOTES R3). Consistency now 0 warnings across 6
seeds; a single-storey type at >1 still trips. qa.sh --strict GREEN 4/4.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 18:15:42 +10:00
m3ultra
53f472d0d7 Lane F R3: hours/closed-shops + manifest/rig-fleet/?noassets + --depot + QA harness fixes
§3.5 hours: isOpen() gates enterShop — closed shops locked; at night only the openLate video
rental opens. §3.4: ?noassets (zero-network primitive path, verified via Performance API),
interior fitting GLB upgrades from the 3GOD depot (useGLB), and the rig-fleet upgrade
(models/peds/*.glb) so peds + keepers become shared GLB rigs, leak-free (shared loadGLB cache
proven, not a leak). qa.sh manifest gate now --depot (16 GLBs live) — GREEN 4/4.

Browser QA harness fixes so shots.py/soak.py actually run: DBG async-poll (was racing the async
install), plan via window.PROCITY (DBG.plan unexposed), enterShop bare-id, shop.lot is a lot id,
midday pin (§3.5 else closes shops mid-walk), GLB-cache warmup, budget peaks -> warnings (gate 3
clean pass is authoritative). Gate 2 soak PASS both asset modes; gate 4 asset-free PASS;
docs/shots/v1_tour/ (10 shots) + contact sheet captured.

Findings (LANE_F_NOTES §9): D/E decimate tri-heavy ped GLBs (gate 3 tris ~279k > 200k budget;
draws fine ~200/300). B: add 3 shots bookmark poses, fix headless composer letterbox in
DBG.shot(), render the §3.5 closed-facade visual (predicate window.PROCITY.isOpen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 17:19:11 +10:00
m3ultra
5313402e43 Lane B (Streetscape): chunk-streamed walkable town shell
First-person shell: chunk streaming, instanced buildings + facade texture atlas
(22 facade materials -> 1; 5 skin materials city-wide), signs, awnings, furniture,
day/night lighting, minimap, pixel-accurate collision (incl. arbitrary-angle lots),
door raycast -> procity:enterShop, DBG harness, all-fallback mode. Renders Lane A's
full generated town (seed 20261990 'Boolarra Heads', 493 shops); worst continuous-
walk view ~261 draws (<=300 gate). 6 adversarial-review bugs fixed (collision sign,
house doors, awning skin, sign atlas, furniture seed hash, shot-mode restore).

index.html and skins.js include Lane F's inline integration seam edits (marked
'[Lane F integration]'): interior/keeper/citizen wiring + facade filename fix.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 14:28:47 +10:00