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>
This commit is contained in:
m3ultra 2026-07-15 01:41:27 +10:00
parent 3724a65505
commit 0b84560457
5 changed files with 70 additions and 17 deletions

View File

@ -4,7 +4,20 @@
---
## Round 6 (finish v2 wiring + pay review debts → v2.0-alpha) — IN PROGRESS
## Round 7 (the flip round → v2.0-beta) — IN PROGRESS
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 (146150 active), `?roster=v1` streamMode:false (96), both render, 0 errors, ≤300 draws, harness GREEN. |
| **F2 — harness to strict** | ⏳ next: flags failures fail qa.sh; add `stock=real` + `weather=1` smokes (new flags at warn). |
| **F3 — tag v2.0-beta** | ⏳ after F2 + B weather / A osm-parity land (decision #6). |
---
## 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 796 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 KiB

View File

@ -27,8 +27,15 @@ ROOT = pathlib.Path(__file__).resolve().parent.parent
PORT = 8130
HOST = f'http://127.0.0.1:{PORT}'
SEED = 20261990
GOLDEN_HASH = 0x3fa36874 # frozen determinism anchor (Lane A selfcheck)
BASE_DRAWS, BASE_TRIS = 163, 19000 # flags-off DBG.shot('street_noon') snapshot (v1.1, measured); ±40% warn tolerance
GOLDEN_HASH = 0x3fa36874 # frozen determinism anchor (Lane A selfcheck) — UNCHANGED by the R7 flip
# flags-off DBG.shot('street_noon') snapshot. RE-PINNED at the R7 roster flip (prime-law amendment):
# old (v1.1, roster-off): 163 draws, 19000 tris
# new (R7, roster default-on): 164 draws, ~66000 tris
# Draws barely move — E1's ped sub-mesh merge makes each near-rig ~1 draw, which is exactly what let
# the roster flip to full density. Tris jump is the streamed crowd (each near-rig ~2.4k tris); it is
# inherently variable frame-to-frame (how many rigs are near at sample time), so the drift WARN below
# is DRAWS-ONLY — tris is guarded strictly by the STREET_TRIS_MAX hard cap, not a soft snapshot.
BASE_DRAWS, BASE_TRIS = 164, 66000
STREET_DRAWS_MAX, STREET_TRIS_MAX = 300, 200_000
KNOWN_FLAGS = ['winmap=1', 'dig=1', 'roster=stream'] # plansrc=osm auto-appended if Lane A landed it
@ -98,7 +105,7 @@ def flags_off_regression(p):
return { draws:i.drawCalls, tris:i.tris, mode:i.mode,
winmap: !!(P.winmap && P.winmap.active),
digActive: !!(P.interiorMode && P.interiorMode.digActive),
streaming: !!(c.streaming || c.mode==='stream') };
streamMode: !!c.streamMode }; // R7: real roster-mode flag (was reading a nonexistent prop)
}""")
# determinism anchor — run Lane A's selfcheck in-process (golden fingerprint)
r = subprocess.run(['node', 'web/js/citygen/selfcheck.js'], cwd=str(ROOT),
@ -108,23 +115,40 @@ def flags_off_regression(p):
if hash_ok and r.returncode == 0: OK(f'plan fingerprint == golden {hex(GOLDEN_HASH)} (selfcheck green)')
else: FAIL(f'plan fingerprint != golden {hex(GOLDEN_HASH)} — determinism/prime-law broken')
if state['winmap'] or state['digActive'] or state['streaming']:
FAIL(f"a v2 subsystem is ACTIVE on default boot: {state}")
else: OK('all v2 subsystems inactive on default boot (winmap/dig/roster off)')
# winmap + dig stay OPT-IN (off by default). The streamed roster is now the shipping DEFAULT
# (R7 flip / prime-law amendment) — so it must be ON, not off, on a no-flag boot.
if state['winmap'] or state['digActive']:
FAIL(f"an opt-in v2 flag is active on default boot (winmap/dig): {state}")
else: OK('opt-in flags off on default boot (winmap/dig)')
if state['streamMode']:
OK('R7 roster flip in effect — streamed roster ACTIVE on default boot')
else: FAIL('roster flip REGRESSED — default boot is not streaming (expected streamMode:true)')
if state['draws'] <= STREET_DRAWS_MAX and state['tris'] <= STREET_TRIS_MAX:
OK(f"flags-off street view within v1 budget (draws {state['draws']}{STREET_DRAWS_MAX}, tris {state['tris']}{STREET_TRIS_MAX})")
else: FAIL(f"flags-off street view OVER v1 budget: draws {state['draws']}, tris {state['tris']}")
OK(f"flags-off street view within budget (draws {state['draws']}{STREET_DRAWS_MAX}, tris {state['tris']}{STREET_TRIS_MAX})")
else: FAIL(f"flags-off street view OVER budget: draws {state['draws']}, tris {state['tris']}")
# Drift WARN is DRAWS-ONLY — tris is crowd-variable post-flip (guarded by the hard cap above).
dd = abs(state['draws'] - BASE_DRAWS) / BASE_DRAWS
dt = abs(state['tris'] - BASE_TRIS) / BASE_TRIS
if dd <= 0.40 and dt <= 0.40:
OK(f"draws/tris within 40% of v1.1 snapshot ({state['draws']} vs {BASE_DRAWS}, {state['tris']} vs {BASE_TRIS})")
if dd <= 0.40:
OK(f"draws within 40% of re-pinned baseline ({state['draws']} vs {BASE_DRAWS}); tris {state['tris']} (crowd-variable, ≤cap)")
else:
WARN(f"draws/tris drifted >40% from v1.1 snapshot ({state['draws']} vs {BASE_DRAWS}, {state['tris']} vs {BASE_TRIS}) — investigate")
WARN(f"draws drifted >40% from baseline ({state['draws']} vs {BASE_DRAWS}) — investigate")
if errs: FAIL(f"{len(errs)} console error(s) on default boot; first: {errs[0][:140]}")
else: OK('0 console errors on default boot')
# R7 escape hatch: ?roster=v1 must restore the fixed roster (streamMode:false), render, no errors.
b2, pg2, errs2 = new_page(p)
try:
boot(pg2, 'roster=v1')
esc = pg2.evaluate("() => ({ streamMode: !!(window.PROCITY.citizens||{}).streamMode, mode: window.DBG.info().mode })")
if not esc['streamMode'] and esc['mode'] == 'street':
OK('escape hatch ?roster=v1 → fixed roster (streamMode:false), renders')
else: FAIL(f"escape hatch ?roster=v1 broken: {esc}")
if errs2: FAIL(f"?roster=v1: {len(errs2)} console error(s); first: {errs2[0][:140]}")
finally:
b2.close()
finally:
b.close()

View File

@ -147,10 +147,26 @@ const interiorMode = createInteriorMode({ THREE, renderer, camera, plan, fleet,
// open and re-lock (on click) after. digActive gates the unlock→leaveShop guard below so opening a bin
// doesn't read as "walked out of the shop".
window.addEventListener('procity:digOpen', () => player.unlock());
// [Lane F integration] street pedestrians (Lane D). graph = plan.streets directly; with the rig fleet the
// near tier shares GLB meshes (cheap). `?pop=` tunable. setTimeOfDay/update in the street loop.
const citizens = new CitizenSim({ renderer, scene, camera, citySeed: plan.citySeed, graph: plan.streets, fleet });
citizens.setPopulation((parseInt(params.get('pop'), 10) || 140) >>> 0); // midday ≈96 active
// [Lane F §F1 — ROUND 7 ROSTER FLIP · prime-law amendment] The chunk-streamed roster is now the
// DEFAULT: the town is permanently busier. `?roster=v1` restores the old fixed roster (escape hatch);
// `?roster=stream` is still accepted (now a no-op — stream is default). Gated on Lane D's GO: E1's
// ped sub-mesh merge makes each near-rig ~1 draw, so full density (perChunk 16) = 241 worst-street
// draws ≤300. Plan goldens do NOT move (roster doesn't touch the plan). See LANE_D_NOTES → Lane F.
const rosterV1 = params.get('roster') === 'v1';
const citizens = new CitizenSim({ renderer, scene, camera, citySeed: plan.citySeed, graph: plan.streets,
fleet, chunkStream: rosterV1 ? null : { radius: 2 } }); // default-on
citizens.setPopulation((parseInt(params.get('pop'), 10) || 140) >>> 0); // fixed-roster (?roster=v1) size; stream = per-chunk density
// [Lane F] hours-aware: keep the open-late block lively at night (Lane D3 setNightLivelyChunks). Keys via
// sim.chunkKeyAt so they match sim's own chunk-key format; openLate shop = hours close ≥22 (Lane A contract).
if (!rosterV1) {
const late = plan.shops.find((s) => s.hours && s.hours[1] >= 22);
const lot = late && plan.lots.find((l) => l.id === late.lot);
if (lot) {
const keys = [];
for (let dx = -1; dx <= 1; dx++) for (let dz = -1; dz <= 1; dz++) keys.push(citizens.chunkKeyAt(lot.x + dx * 64, lot.z + dz * 64));
citizens.setNightLivelyChunks(keys);
}
}
document.addEventListener('visibilitychange', () => citizens.setPaused(document.hidden));
// spawn on the footpath near the west end of the strip, looking east down main street