Compare commits

...

2 Commits

Author SHA1 Message Date
m3ultra
2491f1c8ec Lane F R31 wave 2 (v7.0-alpha close): THE SHOT + the ledger. docs/shots/v7_alpha/crate_panel.png — the alpha's face: Monster Robot Party's real frontage, THE CRATE open with 3 real finds (real cover thumbs, paid/where/day honest), game bar day 1 · $116 · CRATE 3 · SLEEP, driven through the REAL loop with the dig param ABSENT (the R31 flip carries the shot), 0 console errors. LANE_F_NOTES §31 (the flip both ways, the two new gate legs + their negative control, harness lesson #4 — the explicit-flag blindfold, THE BETA QUEUE filed) + F-progress R31. Tag v7.0-alpha rides this commit, LOCAL ONLY — Fable reviews and pushes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 16:38:07 +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
8 changed files with 193 additions and 10 deletions

View File

@ -4,6 +4,32 @@
--- ---
## Round 31 (v7.0-alpha CLOSE) — THE DIG FLIP + the tag
**Fable's wave-0 playtest found the one alpha-blocker: the dig was default-OFF on a plain boot.**
`index.html` still carried the v2-era opt-in (`params.has('dig')`) six epochs after the README
claimed "dig on" — and every R30 game-loop gate booted `dig=1` explicitly, so the suite was green
while E at a bin did nothing on the boot every player gets. Fixed with the one-line flip
(`DIG_ON = flagOn('dig')` — ?dig=0 opt-out, ?classic=1 off, `dig` on the flags surface) and fenced
with two new STRICT legs: **default_boot_gate asserts dig REACHABILITY on a NAKED boot** (E at an
aimed bin → digActive true → closed clean) and **classic_regression asserts dig INERT at the bin**
(zero `pcdg-*` DOM, zero Storage calls — measured, not assumed). *Harness lesson #4: the
explicit-flag blindfold — a gate that force-feeds its subject's flag can never notice the default
is broken; every claimed-default-on flag needs at least one flag-ABSENT gate.* Splash de-staled
("Every door opens." — the "(soon)" is over; controls line = E riffle/sell · C crate · SLEEP to
save) + the README manual row. `PROCITY_QA_PORT` override so the suite never silently reuses
whatever holds :8130 (this round: Fable's own preview server).
**The re-gate (final tree, :8931): `qa.sh --strict --matrix` 7 passed · 0 failed · 0 warn ·
0 skipped; flags_check 0/0 incl. both new legs; MATRIX 10 towns green.** Money shot:
`docs/shots/v7_alpha/crate_panel.png` — Monster Robot Party's frontage, THE CRATE with 3 real
finds (real cover thumbs, honest paid/where/day), game bar day 1 · $116 · CRATE 3 · SLEEP, driven
through the real loop with the dig param absent. **Tag `v7.0-alpha` — annotated, LOCAL ONLY**
(Fable pushes). THE BETA QUEUE (Fable's design wants, filed NOT fixed) is in LANE_F_NOTES §31.6.
Commits: `50385c0` (flip + gates + splash) · shot + notes commit (tag target). Full record: §31.
---
## Round 30 (v7.0-alpha — THE SAVE AND THE CRATE) — F: the contract first, then the save core + tomorrow ## Round 30 (v7.0-alpha — THE SAVE AND THE CRATE) — F: the contract first, then the save core + tomorrow
**The contract shipped before a line of implementation** (`53fcd3c`): `window.PROCITY.game = **The contract shipped before a line of implementation** (`53fcd3c`): `window.PROCITY.game =

View File

@ -23,6 +23,7 @@ Click **START** to lock the mouse. Then:
| **W A S D** + mouse | walk / look (first person) | | **W A S D** + mouse | walk / look (first person) |
| walk into a shop door | enter the interior (open shops only — check the hours tooltip) | | walk into a shop door | enter the interior (open shops only — check the hours tooltip) |
| **E** (inside a shop) | open the crate at a record bin — then it's cursor-driven: click sleeves to riffle, click BUY | | **E** (inside a shop) | open the crate at a record bin — then it's cursor-driven: click sleeves to riffle, click BUY |
| **E** (at the counter) · **C** (street) · **SLEEP** (top bar) | sell a find to the keeper (always under what you paid) · open THE CRATE — your collection · sleep = save, the day advances, stock rotates |
| click a book spine / toy box | pull-and-buy card (real price stickers in godverse shops) | | click a book spine / toy box | pull-and-buy card (real price stickers in godverse shops) |
| walk out the door / **Esc** | leave the shop (Esc also frees the mouse anywhere) | | walk out the door / **Esc** | leave the shop (Esc also frees the mouse anywhere) |
| **M** | 2D town map (street only) | | **M** | 2D town map (street only) |

View File

@ -1663,3 +1663,94 @@ as §30.5's closed-door: a verify that forgets the world's rules reads the rules
an inventory). Buying it again is possible **and loses money every time** (the $6/trip measurement is an inventory). Buying it again is possible **and loses money every time** (the $6/trip measurement is
exactly this); scarcity-per-day would need the save to carry per-day pull records. The no-pump clamp is exactly this); scarcity-per-day would need the save to carry per-day pull records. The no-pump clamp is
what makes the infinite crate safe. Rule it in beta with the guide bands, not here. what makes the infinite crate safe. Rule it in beta with the guide bands, not here.
---
## 31. Round 31 — the v7.0-alpha CLOSE: THE DIG FLIP (wave 1) + THE TAG (wave 2)
### §31.1 The alpha-blocker (Fable's wave-0 playtest) and the flip
**The dig was default-OFF on a plain boot.** `web/index.html` still carried the v2-era opt-in
(`const DIG_ON = params.has('dig') && params.get('dig') !== '0'`) six epochs after the README's
flags table began claiming "dig on" — and every R30 game-loop gate booted `dig=1` EXPLICITLY, so
the whole suite was green while the boot every player gets had no crate-riffle at all: E at a bin
did nothing. The gates tested the game; nobody tested that the default boot IS the game.
**The flip (one line + the law):** `DIG_ON = flagOn('dig')` — default-ON, `?dig=0` opts out,
`?classic=1` master-off: the exact pattern the other flipped flags ride. `dig` joins the
`PROCITY.flags` intent surface (the gates read intent there). Measured both ways in fresh
contexts on a port-isolated server (:8951):
| boot | measured |
|---|---|
| NAKED (no params) | E at a bin → riffle **OPENED** + closed clean · `flags.dig` true · 0 errors |
| `?dig=0` | opt-out honoured — riffle does NOT open, **ZERO** dig DOM |
| `?classic=1` | dig INERT at the bin (E falls through `trySell` (null game) + shelf no-op) · ZERO `pcdg-*` DOM · **ZERO Storage-prototype calls** (instrumented) · 0 errors — the covenant untouched |
| `?noassets=1` naked | dig opens on **parody canvas** · 0 errors (existing law holds) |
*(Observation filed, pre-existing, NOT touched: `assets/gen/*.jpg` skin textures fetch under
`?noassets` — 22 fetches, fail-soft, present since v1; the dig added zero fetches to that boot.)*
### §31.2 The gate that makes the regression impossible (vacuous-gate law, turned on F's own suite)
Two new STRICT legs in `tools/flags_check.py`:
- **default_boot_gate** grows **dig REACHABILITY on the NAKED boot**: enter a record shop, E at an
aimed bin, `digActive` must go true (and close clean via WALK OUT); plus a `PROCITY.flags.dig`
intent assert. Un-flip the default again and this line goes red. Negative control: the identical
measurement on a `?dig=0` boot reads `opened:false` (pre-flight, :8951) — the detector
discriminates.
- **classic_regression** grows the **dig-INERT leg**: the old `digActive` assert was vacuously
false on the street; it is now measured AT THE BIN — E opens nothing, zero dig DOM, filed as
"measured, not assumed".
**Harness lesson #4 of the epoch (house habit): the explicit-flag blindfold.** A gate that
force-feeds its subject's flag (`dig=1` in every boot query, belt-and-braces) can never notice the
default is broken. Where a flag is CLAIMED default-on, at least one gate must exercise it with the
flag ABSENT. Now true for dig; gigs/weather/winmap/tram always had it (the default-boot gate boots
naked by construction).
### §31.3 Port isolation (small, suite-wide)
`PROCITY_QA_PORT` env override added to `flags_check.py`, `qa/interior_scale_check.py`,
`qa/town_matrix.py`. `ensure_server()` silently REUSES anything parked on :8130 — this round that
was Fable's own preview server, and a shared server is somebody else's cache semantics + somebody
else's lifecycle. The R31 re-gate rode `:8931`; default behaviour unchanged.
### §31.4 The splash (same file, same commit)
"Every door opens **(soon)**" — stale by six epochs — is gone: the tagline now sells the loop
("Every door opens. Dig the crates, sell the flips, sleep — the town remembers.") and the controls
line carries the game beats (E riffle a bin / sell at the counter · C your crate · SLEEP to save).
README manual gains the matching row (sell at the counter · C crate · SLEEP = save/advance/rotate).
### §31.5 The re-gate, the shot, the tag — RESULTS
All on the FINAL tree (commit `50385c0`), suite port-isolated on `:8931` (`PROCITY_QA_PORT` —
Fable's preview holds :8130, untouched):
- **`qa.sh --strict --matrix`: 7 passed · 0 failed · 0 warn · 0 skipped.** flags_check **0 fails /
0 warns** — both new R31 legs green in the run (`dig REACHABLE on the naked boot — E at a bin
opened the riffle (and closed clean)` · `?classic dig INERT at the bin — E opened nothing, zero
dig DOM`), all five R30 STRICT gates re-proven over the flipped tree, classic covenant fingerprint
green, no-giants green. **MATRIX GREEN — 10 towns (synthetic + fixtures + real caches) × 7 gates.**
- **The money shot: `docs/shots/v7_alpha/crate_panel.png`** — Monster Robot Party's real frontage
(redhill_godverse, `stock=real`), THE CRATE open with **3 real finds** (The Return $40 ·
First Filtration Of The Duplex Brains $15 · Blue Blackness $20 — real cover thumbs off the
per-shop atlas, every row honest: `paid $N · Monster Robot Party · day 1`), game bar
**day 1 · $116 · CRATE 3 · SLEEP**. Driven through the REAL loop with the dig param ABSENT (the
flip carries the shot): enter → E at three different bins → riffle → pull → BUY ×3 → street →
C. 0 console errors. Script: session scratchpad (`crate_shot.py`) — the PNG is the deliverable.
- **The tag: `v7.0-alpha`**, annotated, **LOCAL ONLY** on the notes commit — Fable reviews and
pushes main + tag together (treaty).
### §31.6 THE BETA QUEUE (Fable's playtest, filed NOT fixed — John's ruling queue)
1. **Spawn faces dirt/building-backs** instead of the strip — wants a cluster-pose for spawns.
2. **THE CRATE is unreachable inside shops** — C is street-only by design (hud.js); a player wants
it at the counter.
3. **Dawn sky reads dusk-orange** (cosmetic).
4. The pull card's **value hint is THE BIBLE** (chartered — the beta's guide bands).
5. Automation-only, unverified in person: **dig Esc-close under synthetic events**.
6. *(carried from §30.6)* no per-day `gone` tracking on parody/mint dig stock — scarcity-per-day
needs the save to carry pull records; rule it with the guide bands.

Binary file not shown.

After

Width:  |  Height:  |  Size: 894 KiB

View File

@ -24,7 +24,10 @@ except ImportError:
"tools/.venv/bin/pip install playwright && tools/.venv/bin/python -m playwright install chromium") "tools/.venv/bin/pip install playwright && tools/.venv/bin/python -m playwright install chromium")
ROOT = pathlib.Path(__file__).resolve().parent.parent ROOT = pathlib.Path(__file__).resolve().parent.parent
PORT = 8130 # [R31] PROCITY_QA_PORT: run the suite on an isolated port. The default (:8130) is also the house preview
# port — ensure_server() would silently REUSE a dev server already parked there, and a shared server is
# somebody else's cache semantics + somebody else's lifecycle. Gates want their own server or a named one.
PORT = int(os.environ.get('PROCITY_QA_PORT', '8130'))
HOST = f'http://127.0.0.1:{PORT}' HOST = f'http://127.0.0.1:{PORT}'
SEED = 20261990 SEED = 20261990
GOLDEN_HASH = 0x5f76e76 # [R27w5] AMENDED. Was 0x3fa36874 "forever" since R16 — and that town GOLDEN_HASH = 0x5f76e76 # [R27w5] AMENDED. Was 0x3fa36874 "forever" since R16 — and that town
@ -173,6 +176,30 @@ def classic_regression(p):
if state['winmap'] or state['digActive']: if state['winmap'] or state['digActive']:
FAIL(f"a flipped/opt-in flag leaked into ?classic (winmap/dig): {state}") FAIL(f"a flipped/opt-in flag leaked into ?classic (winmap/dig): {state}")
else: OK('flipped + opt-in flags off under ?classic (winmap/dig)') else: OK('flipped + opt-in flags off under ?classic (winmap/dig)')
# [R31 — THE DIG FLIP, classic side] dig is default-ON now, so classic's dig-lessness must be
# MEASURED at a bin, not inferred from an idle digActive (which is vacuously false on the street):
# enter a record shop, E aimed at a bin — the riffle must NOT open and ZERO dig DOM may exist
# (createDig is never constructed off-flag; the E falls through trySell(null game) + shelf no-op).
dug = pg.evaluate("""() => {
const P = window.PROCITY, D = window.DBG; D.setSegment(2);
const s = (P.plan.shops || []).find(x => x.type === 'record' && P.isOpen(x));
if (!s) return { err: 'no open record shop' };
D.enterShop(s.id);
const bins = []; P.interiorMode.current.group.traverse(o => { if (o.userData && o.userData.kind === 'bin') bins.push(o); });
if (!bins.length) { D.exitShop(); return { err: 'no bins' }; }
const bp = new P.THREE.Vector3(); bins[0].getWorldPosition(bp);
P.camera.position.set(bp.x, 1.6, bp.z + 1.4); P.camera.lookAt(bp.x, bp.y + 0.4, bp.z); P.camera.updateMatrixWorld();
window.dispatchEvent(new KeyboardEvent('keydown', { code: 'KeyE' }));
const opened = !!P.interiorMode.digActive;
const dom = document.querySelectorAll('[class^="pcdg"]').length;
D.exitShop();
return { opened, dom };
}""")
if dug.get('err'): WARN(f"?classic dig-inert leg unmeasured — {dug['err']}")
elif not dug['opened'] and dug['dom'] == 0:
OK('?classic dig INERT at the bin — E opened nothing, zero dig DOM (measured, not assumed)')
else:
FAIL(f"?classic dig LEAKED: E at a bin → opened={dug['opened']}, dig DOM nodes={dug['dom']}")
if state['streamMode']: if state['streamMode']:
OK('R7 roster flip in effect — streamed roster ACTIVE under ?classic (the v2 baseline)') OK('R7 roster flip in effect — streamed roster ACTIVE under ?classic (the v2 baseline)')
else: FAIL('roster flip REGRESSED — ?classic is not streaming (expected streamMode:true)') else: FAIL('roster flip REGRESSED — ?classic is not streaming (expected streamMode:true)')
@ -255,6 +282,37 @@ def default_boot_gate(p):
OK(f"default-boot street budget @ venue block: {state['draws']} draws ≤ {STREET_DRAWS_MAX}, {state['tris']:,} tris ≤ {STREET_TRIS_MAX:,}") OK(f"default-boot street budget @ venue block: {state['draws']} draws ≤ {STREET_DRAWS_MAX}, {state['tris']:,} tris ≤ {STREET_TRIS_MAX:,}")
else: else:
FAIL(f"default-boot street OVER budget @ venue block: {state['draws']} draws / {state['tris']:,} tris (Fable scope call — not silent-trim)") FAIL(f"default-boot street OVER budget @ venue block: {state['draws']} draws / {state['tris']:,} tris (Fable scope call — not silent-trim)")
# [R31 — THE DIG FLIP GATE] Fable's wave-0 playtest found the alpha-blocker this whole suite
# missed: every R30 game-loop gate booted `dig=1` EXPLICITLY (belt-and-braces that became a
# blindfold), so the suite was green while the NAKED boot's E did nothing at a bin — index.html
# still carried the v2-era opt-in. The gates tested the game; nobody tested that the default boot
# IS the game. So this gate now proves dig REACHABILITY with zero dig params: enter a record shop,
# E at an aimed bin, the riffle must open. Un-flip the default again and this line goes red.
f2 = state['flags'] or {}
if not f2.get('dig'):
FAIL(f"dig intent OFF on the naked boot (PROCITY.flags.dig falsy) — the R31 flip regressed: {f2}")
dug = pg.evaluate("""() => {
const P = window.PROCITY, D = window.DBG; D.setSegment(2);
const s = (P.plan.shops || []).find(x => x.type === 'record' && P.isOpen(x));
if (!s) return { why: 'no open record shop' };
D.enterShop(s.id);
const bins = []; P.interiorMode.current.group.traverse(o => { if (o.userData && o.userData.kind === 'bin') bins.push(o); });
if (!bins.length) { D.exitShop(); return { why: 'no bins' }; }
const bp = new P.THREE.Vector3(); bins[0].getWorldPosition(bp);
P.camera.position.set(bp.x, 1.6, bp.z + 1.4); P.camera.lookAt(bp.x, bp.y + 0.4, bp.z); P.camera.updateMatrixWorld();
window.dispatchEvent(new KeyboardEvent('keydown', { code: 'KeyE' }));
const opened = !!P.interiorMode.digActive;
const out = document.querySelector('.pcdg-out'); if (out) out.click();
const closed = !P.interiorMode.digActive;
D.exitShop();
return { opened, closed };
}""")
if dug.get('opened') and dug.get('closed'):
OK('dig REACHABLE on the naked boot — E at a bin opened the riffle (and closed clean); the default boot IS the game')
elif dug.get('opened'):
WARN(f"naked-boot dig opened but close unconfirmed — {dug}")
else:
FAIL(f"THE DIG IS OFF ON A PLAIN BOOT — the R31 alpha-blocker is back: {dug}")
if errs: FAIL(f"{len(errs)} console error(s) on the default boot; first: {errs[0][:140]}") if errs: FAIL(f"{len(errs)} console error(s) on the default boot; first: {errs[0][:140]}")
else: OK('0 console errors on the default boot') else: OK('0 console errors on the default boot')
finally: finally:

View File

@ -24,10 +24,10 @@ Run: tools/.venv/bin/python tools/qa/interior_scale_check.py [--seed N]
Setup: the same Playwright venv as tools/soak.py / tools/flags_check.py. Setup: the same Playwright venv as tools/soak.py / tools/flags_check.py.
Needs Lane B's window.DBG hook (?dbg=1) + window.PROCITY.interiorMode (Lane C/F). Needs Lane B's window.DBG hook (?dbg=1) + window.PROCITY.interiorMode (Lane C/F).
""" """
import sys, time, socket, subprocess, pathlib import sys, os, time, socket, subprocess, pathlib
ROOT = pathlib.Path(__file__).resolve().parent.parent.parent ROOT = pathlib.Path(__file__).resolve().parent.parent.parent
PORT = 8130 PORT = int(os.environ.get('PROCITY_QA_PORT', '8130')) # [R31] port-isolated suite runs (see flags_check.py)
HOST = f'http://127.0.0.1:{PORT}' HOST = f'http://127.0.0.1:{PORT}'
SEED = 20261990 SEED = 20261990
if '--seed' in sys.argv: if '--seed' in sys.argv:

View File

@ -16,10 +16,10 @@ Gates per town (all on the DEFAULT boot — gigs/weather/winmap/tram on, post-R1
Run: tools/.venv/bin/python tools/qa/town_matrix.py Run: tools/.venv/bin/python tools/qa/town_matrix.py
Needs the Playwright venv + Lane B's ?dbg=1 hook + Lane F's real-cache shell wiring (R17). Needs the Playwright venv + Lane B's ?dbg=1 hook + Lane F's real-cache shell wiring (R17).
""" """
import sys, time, socket, subprocess, pathlib import sys, os, time, socket, subprocess, pathlib
ROOT = pathlib.Path(__file__).resolve().parent.parent.parent ROOT = pathlib.Path(__file__).resolve().parent.parent.parent
PORT = 8130 PORT = int(os.environ.get('PROCITY_QA_PORT', '8130')) # [R31] port-isolated suite runs (see flags_check.py)
HOST = f'http://127.0.0.1:{PORT}' HOST = f'http://127.0.0.1:{PORT}'
STREET_DRAWS_MAX, STREET_TRIS_MAX = 300, 200_000 STREET_DRAWS_MAX, STREET_TRIS_MAX = 300, 200_000
# [R21 ledger #6c] B's R20 tram ruling: on a REAL-ROADS town the tram only runs if its best main chain # [R21 ledger #6c] B's R20 tram ruling: on a REAL-ROADS town the tram only runs if its best main chain

View File

@ -31,10 +31,10 @@
<div id="pc-start"> <div id="pc-start">
<h1>PROCITY</h1> <h1>PROCITY</h1>
<div class="sub">A procedurally generated, walkable 90s-Australian shopping town. <div class="sub">A procedurally generated, walkable 90s-Australian shopping town.
Every door opens (soon). Walk the strip, watch the day turn.</div> Every door opens. Dig the crates, sell the flips, sleep — the town remembers.</div>
<button id="pc-go">walk into town</button> <button id="pc-go">walk into town</button>
<div class="seed" id="pc-startseed"></div> <div class="seed" id="pc-startseed"></div>
<div class="sub" style="font-size:12px;opacity:.7">WASD move · shift run · mouse look · click a door · [ ] time of day · M map · P screenshot</div> <div class="sub" style="font-size:12px;opacity:.7">WASD move · shift run · mouse look · click a door · E riffle a bin / sell at the counter · C your crate · SLEEP to save · [ ] time · M map</div>
</div> </div>
<script type="module"> <script type="module">
@ -190,8 +190,14 @@ const minimap = createMinimap(plan);
const fleet = NOASSETS ? null : loadPedFleet('models/peds/', { sit: !CLASSIC, look: !CLASSIC }); // [R16] sit.glb (the seated drummer) + [R29] look.glb (the street glance) on the default boot; ?classic keeps the zero-fetch-delta covenant const fleet = NOASSETS ? null : loadPedFleet('models/peds/', { sit: !CLASSIC, look: !CLASSIC }); // [R16] sit.glb (the seated drummer) + [R29] look.glb (the street glance) on the default boot; ?classic keeps the zero-fetch-delta covenant
if (!NOASSETS) preloadManifest(); // prime the manifest so the first interior can upgrade its fittings if (!NOASSETS) preloadManifest(); // prime the manifest so the first interior can upgrade its fittings
// [Lane F integration] interior bridge — owns the 'interior' branch (Lane C buildInterior + Lane D keeper) // [Lane F integration] interior bridge — owns the 'interior' branch (Lane C buildInterior + Lane D keeper)
// [Lane F §F2] ?dig=1 enables Lane C's crate-riffle inside record interiors (v2). Off ⇒ byte-identical to v1. // [Lane F R31 — THE DIG FLIP] The crate-riffle is DEFAULT-ON: `?dig=0` opts out, `?classic=1` forces it off
const DIG_ON = params.has('dig') && params.get('dig') !== '0'; // — the exact flagOn pattern the other flipped flags ride. The v2-era opt-in (`params.has('dig')`) survived
// here six epochs after the README's flags table claimed "dig on", and every R30 game-loop gate booted
// `dig=1` explicitly — so the whole suite was green while the plain boot (the boot every player gets) had
// no dig at all: E at a bin did nothing (Fable's R31 wave-0 playtest, the alpha-blocker). The default-boot
// gate now asserts dig REACHABILITY on a naked boot, so un-flipping this line goes red in qa, not in a
// player's hands. ?noassets composes unchanged: the dig falls to parody canvas (existing law).
const DIG_ON = flagOn('dig');
// [Lane F §F2 stock=real] real GODVERSE sleeves in the crates (v2). Preload the record pack at boot so // [Lane F §F2 stock=real] real GODVERSE sleeves in the crates (v2). Preload the record pack at boot so
// the first interior/dig can batch real covers; fail-soft (missing pack → parody canvas). Off under ?noassets. // the first interior/dig can batch real covers; fail-soft (missing pack → parody canvas). Off under ?noassets.
const STOCK_REAL = params.get('stock') === 'real' && !NOASSETS; const STOCK_REAL = params.get('stock') === 'real' && !NOASSETS;
@ -527,7 +533,8 @@ window.PROCITY = { plan, scene, camera, renderer, chunks, lighting, player, skin
// [Lane F R16 — THE FLIP] the flag-intent surface: what SHOULD be on this boot (the gates verify intent vs // [Lane F R16 — THE FLIP] the flag-intent surface: what SHOULD be on this boot (the gates verify intent vs
// reality). Default boot = all four flipped flags true; ?classic=1 = all false + classic true; each `=0` opts out. // reality). Default boot = all four flipped flags true; ?classic=1 = all false + classic true; each `=0` opts out.
flags: { classic: CLASSIC, gigs: GIGS_ON, weather: flagOn('weather'), winmap: flagOn('winmap'), tram: flagOn('tram'), flags: { classic: CLASSIC, gigs: GIGS_ON, weather: flagOn('weather'), winmap: flagOn('winmap'), tram: flagOn('tram'),
game: GAME_ON }, // [R30] the v7 game layer (default-on; ?game=0 / ?classic=1 → off) game: GAME_ON, // [R30] the v7 game layer (default-on; ?game=0 / ?classic=1 → off)
dig: DIG_ON }, // [R31] the dig flip (default-on; ?dig=0 / ?classic=1 → off) — gate reads intent here
THREE, get mode() { return MODE; } }; // [Lane F] bridge + drive hooks THREE, get mode() { return MODE; } }; // [Lane F] bridge + drive hooks
// [Lane B R11 audio] street WebAudio engine — self-unlocking on the first gesture; silent with // [Lane B R11 audio] street WebAudio engine — self-unlocking on the first gesture; silent with
// zero/blocked assets or ?mute=1; ?noassets=1 ⇒ no audio fetches. Exposes window.PROCITY.audio so // zero/blocked assets or ?mute=1; ?noassets=1 ⇒ no audio fetches. Exposes window.PROCITY.audio so