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>
This commit is contained in:
parent
d96cbde004
commit
50385c0f08
@ -23,6 +23,7 @@ Click **START** to lock the mouse. Then:
|
||||
| **W A S D** + mouse | walk / look (first person) |
|
||||
| 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** (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) |
|
||||
| walk out the door / **Esc** | leave the shop (Esc also frees the mouse anywhere) |
|
||||
| **M** | 2D town map (street only) |
|
||||
|
||||
@ -24,7 +24,10 @@ except ImportError:
|
||||
"tools/.venv/bin/pip install playwright && tools/.venv/bin/python -m playwright install chromium")
|
||||
|
||||
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}'
|
||||
SEED = 20261990
|
||||
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']:
|
||||
FAIL(f"a flipped/opt-in flag leaked into ?classic (winmap/dig): {state}")
|
||||
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']:
|
||||
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)')
|
||||
@ -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:,}")
|
||||
else:
|
||||
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]}")
|
||||
else: OK('0 console errors on the default boot')
|
||||
finally:
|
||||
|
||||
@ -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.
|
||||
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
|
||||
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}'
|
||||
SEED = 20261990
|
||||
if '--seed' in sys.argv:
|
||||
|
||||
@ -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
|
||||
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
|
||||
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}'
|
||||
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
|
||||
|
||||
@ -31,10 +31,10 @@
|
||||
<div id="pc-start">
|
||||
<h1>PROCITY</h1>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<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
|
||||
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 §F2] ?dig=1 enables Lane C's crate-riffle inside record interiors (v2). Off ⇒ byte-identical to v1.
|
||||
const DIG_ON = params.has('dig') && params.get('dig') !== '0';
|
||||
// [Lane F R31 — THE DIG FLIP] The crate-riffle is DEFAULT-ON: `?dig=0` opts out, `?classic=1` forces it off
|
||||
// — 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
|
||||
// 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;
|
||||
@ -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
|
||||
// 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'),
|
||||
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
|
||||
// [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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user