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 merge447188avalidated → ~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:
parent
3724a65505
commit
0b84560457
@ -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 (146–150 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
|
||||
|
||||
BIN
docs/shots/laneF/flip_default_busy.png
Normal file
BIN
docs/shots/laneF/flip_default_busy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 796 KiB |
BIN
docs/shots/laneF/flip_v1_escape.png
Normal file
BIN
docs/shots/laneF/flip_v1_escape.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 815 KiB |
@ -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()
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user