Lane F R37 (v8 wave 0, 0.1 F-half): THE KERB GATE — poster clearance measured on the PAINT, and the ?verge=0 control fires at exactly 14

New STRICT smoke_kerb. Lane A's corrected selfcheck asks the plan-side question (is the poster's
offset inside vergeBand(e)[0]?) -- right for A's file, but it still reads no number that came from
Lane B, which is the precise failure that made the old gate vacuous. So F asks the runtime question,
of the paint: RAYCAST STRAIGHT DOWN AT EVERY RENDERED POSTER AND CLASSIFY THE TOPMOST GROUND HIT.

Classification is by MATERIAL IDENTITY -- skins.groundMat() is a cached factory, so the road mesh's
material IS the object groundMat('djsim-road') returns. No mesh names, no string matching, nothing
that drifts when B edits ground.js. Topmost rather than first, deliberately: B put the carriageway on
top at junctions (ROAD_Y 0 -> 0.04) so roads run through intersections, and what the player sees
under a poster is the top surface.

Six arms, all green on the final tree:
  subject          14 posters rendered == 14 in plan.posters, every one within 0 m of its planned
                   position, read off the real venue-posters InstancedMesh matrices. Nobody had ever
                   asserted that the poster you see is the poster A placed. Zero posters => FAIL.
  detector ctl A   the centreline of the longest main (main@28 m, 137.5 m) classifies ROAD at y 0.04
  detector ctl B   13 m off it (1 m inboard of the corridor edge) classifies FOOTPATH at y 0.02
  THE RULING       0 of 14 posters stand on road paint -- tally {djsim-footpath: 14}
  THE CONTROL      the same leg under ?verge=0 FAILS at EXACTLY 14 -- tally {djsim-road: 14}.
                   Keyed to B's flag, never to a line number, matching A's discipline.
  classic          13 m off the centreline is still ROAD under ?classic=1 and classic renders 0
                   posters -- Fable's CLASSIC KEEPS ITS PAINT ruling holds.

The two detector controls are the load-bearing part: "0 posters on road" is a sentence about nothing
unless the classifier is shown to say road AND footpath on the same boot.

TWO LANES, TWO INDEPENDENT METHODS, THE SAME NUMBER: A counted 14 plan-side by offset in node over
the plan; F counted 14 paint-side by raycast in the browser over B's geometry. Both flip to 0 on the
default boot.

Also lands Fable's ruling on classic's post-v2 fetch delta (4a7c0f1) in the mechanism. The audio pack
is RATIFIED BASELINE -- v2.1 was v2's final tagged state -- so the allow-list authority moves
v2.0 -> v2.1. Git makes that surgical rather than generous: `git diff v2.0 v2.1 -- web/` is the audio
pack, js/world/audio.js and four wiring edits; zero other assets, zero deletions. So the tag change
admits precisely the five ratified files and nothing else, and the depot GLB names survive in v2.1's
manifest unchanged (verified: same-origin baseline 47 -> 52, exceptions 2 -> 1, control still
discriminating). assets/towns/index.json is NOT baseline and now prints every run as
"EXCEPTION (NOT v2.1 baseline)" with its provenance, so it can never read as covenant.

README: the ?verge=0 row now carries A's corrected band figures rather than the charter headline --
9 m is the synthetic 28 m main only; a real main is 24 m => 7 m, and side@12, 72% of the corpus, is
3 m.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
m3ultra 2026-08-03 17:30:59 +10:00
parent 4a7c0f1295
commit f522021765
2 changed files with 243 additions and 25 deletions

View File

@ -101,7 +101,7 @@ master off:
| `?weather=0` · `?tram=0` · `?winmap=0` | **on** | seeded weather · the tram loop · the parallax interior-window shader | | `?weather=0` · `?tram=0` · `?winmap=0` | **on** | seeded weather · the tram loop · the parallax interior-window shader |
| `?roster=v1` · `?pop=N` | stream | chunk-streamed citizen density is the baseline; `?roster=v1` restores the fixed roster | | `?roster=v1` · `?pop=N` | stream | chunk-streamed citizen density is the baseline; `?roster=v1` restores the fixed roster |
| `?dig=0` · `?stock=real` | dig on | crate-riffle on record bins · real GODVERSE sleeves in the stock | | `?dig=0` · `?stock=real` | dig on | crate-riffle on record bins · real GODVERSE sleeves in the stock |
| `?verge=0` | **off** | reverts the ground to the **pre-kerb-ruling** geometry (bitumen painted to the full corridor). John's v8 ruling made the 9 m band between kerb and shopfront **footpath**; this flag keeps the old geometry available forever as the gate's falsifiability control — the poster-clearance leg is asserted to FAIL under it | | `?verge=0` | **off** | reverts the ground to the **pre-kerb-ruling** geometry (bitumen painted to the full corridor). John's v8 ruling made the band between kerb and shopfront **footpath** — 9 m on the synthetic town's 28 m main, **7 m** on a real 24 m main, and **3 m** on the `side`@12 edge that is 72% of the corpus. The flag stays forever as the gate's falsifiability control: the poster-clearance leg is asserted to FAIL under it, at exactly 14 posters standing on road paint. `?classic=1` forces the ruling off — the covenanted town keeps its paint |
| `?r=N` · `?shadows=0\|1` | auto | streaming radius and the sun-shadow pass. **Auto is load-bearing**: a big town (>120 shops or >200 street edges) gets radius 2 with shadows off. Forcing `?r=3` on the default town measures **307 draws**, i.e. over the 300 gate — these overrides are diagnostics, not supported boots | | `?r=N` · `?shadows=0\|1` | auto | streaming radius and the sun-shadow pass. **Auto is load-bearing**: a big town (>120 shops or >200 street edges) gets radius 2 with shadows off. Forcing `?r=3` on the default town measures **307 draws**, i.e. over the 300 gate — these overrides are diagnostics, not supported boots |
| `?live=1` · `?live=<url>` | **off** | **tier 2** — live stock from the GODVERSE server (sold-in-the-real-shop means gone in the game). Opt-in by design: absent ⇒ byte-identical to tier 1, and the game never asks a question it has no reason to expect an answer to | | `?live=1` · `?live=<url>` | **off** | **tier 2** — live stock from the GODVERSE server (sold-in-the-real-shop means gone in the game). Opt-in by design: absent ⇒ byte-identical to tier 1, and the game never asks a question it has no reason to expect an answer to |
| `?noassets=1` · `?plansrc=osm` · `?mute=1` · `?dbg=1` | off | asset-free (zero network) · OSM plan source · silence · the `window.DBG` capture/soak harness | | `?noassets=1` · `?plansrc=osm` · `?mute=1` · `?dbg=1` | off | asset-free (zero network) · OSM plan source · silence · the `window.DBG` capture/soak harness |

View File

@ -148,18 +148,28 @@ def plansrc_landed(p):
# plus same-origin" would have been green straight through it. Same-origin is NOT a free pass here; # plus same-origin" would have been green straight through it. Same-origin is NOT a free pass here;
# `/models/peds/` is enumerated by the v2.0 tree, which contains exactly the covenanted 21 files. # `/models/peds/` is enumerated by the v2.0 tree, which contains exactly the covenanted 21 files.
# #
# POST-v2.0 ADDITIONS (Tier P) — measured, named, dated, and NOT silently swallowed. Booting the # THE BASELINE TAG IS `v2.1`, AND THAT IS FABLE'S R37 RULING, NOT A CONVENIENCE. F measured classic's
# actual v2.0 tree and diffing its fetch surface against today's ?classic=1 gives a delta of exactly # live fetch surface against the actual `v2.0` tree and found a delta of +6 files: five audio and
# +3 files, all shipped years of rounds ago and never ruled on: # `assets/towns/index.json`. Fable ruled (ROUND37_INSTRUCTIONS, 4a7c0f1): the covenant preserves "the
# /assets/audio/* R11 audio engine (f7dd44f, Lane B round-11) # exact v2 town", and **v2.1 was v2's final tagged state**, so the audio pack shipped inside v2 exactly
# /assets/towns/index.json R20/R21 town selector (078245f, 4b01449) # as the furniture GLBs did — RATIFIED BASELINE. Git makes that ruling exact rather than generous:
# They are allowed here so the suite is not permanently yellow over shipped behaviour, and PRINTED # `git diff v2.0 v2.1 -- web/` is the audio pack, `js/world/audio.js`, and four wiring edits. **Zero
# every run so the delta can never go invisible. Fable's to ratify or retire — not F's to improvise. # other assets, zero deletions.** So moving the authority from v2.0 to v2.1 admits precisely the
V2_TAG = 'v2.0' # ratified audio and nothing else, and the depot GLB names survive in v2.1's manifest unchanged.
#
# `assets/towns/index.json` is **NOT baseline** — it is v4 selector machinery (R20/R21). Fable ruled it
# carried as a NAMED, PRINTED EXCEPTION: no geometry, no identity, no seeded draw, so not the R36
# species and not gettable in a floor round. It is labelled EXCEPTION, never baseline, so a reader of
# this log can never mistake the two. "Should classic show the town selector at all?" is on the v8 debt
# ledger for R38+.
V2_TAG = 'v2.1'
DEPOT_HOSTS = ('digalot.fyi',) DEPOT_HOSTS = ('digalot.fyi',)
POST_V2_PREFIXES = ( # (prefix, label) — carried, NOT baseline. Printed on every run, tagged EXCEPTION in the output.
('/assets/audio/', 'R11 audio engine (f7dd44f)'), POST_V2_EXCEPTIONS = (
('/assets/towns/index.json', 'R20/R21 town selector (078245f, 4b01449)'), ('/assets/towns/index.json',
'v4 town-selector machinery (078245f R20, 4b01449 R21) — NOT v2 baseline; carried by Fable\'s '
'R37 ruling as a named exception (no geometry, no identity, no seeded draw). Debt ledger R38+: '
'should ?classic=1 show the town selector at all?'),
) )
# The core that must ALL be observed, or the observer is not looking at a live boot (anti-vacuous): # The core that must ALL be observed, or the observer is not looking at a live boot (anti-vacuous):
# the four v2-era depot street GLBs + the covenanted ped fleet's shared clips. # the four v2-era depot street GLBs + the covenanted ped fleet's shared clips.
@ -199,9 +209,9 @@ def _classify_fetch(url, host, paths, depot):
return 'ok', 'code (same-origin module/document)' return 'ok', 'code (same-origin module/document)'
if path == '/favicon.ico': if path == '/favicon.ico':
return 'ignored', 'browser noise' return 'ignored', 'browser noise'
for pre, why in POST_V2_PREFIXES: for pre, why in POST_V2_EXCEPTIONS:
if path.startswith(pre): if path.startswith(pre):
return 'ok', f'POST-v2.0 addition, allowed + unratified{why}' return 'ok', f'CARRIED EXCEPTION (not {V2_TAG} baseline){why}'
if path in paths: if path in paths:
return 'ok', f'same-origin asset present in the {V2_TAG} tree' return 'ok', f'same-origin asset present in the {V2_TAG} tree'
return 'violation', f'same-origin asset NOT in the {V2_TAG} tree' return 'violation', f'same-origin asset NOT in the {V2_TAG} tree'
@ -362,17 +372,16 @@ def classic_regression(p):
depot_n = len(tiers.get(f'depot asset named in the {V2_TAG} manifest', [])) depot_n = len(tiers.get(f'depot asset named in the {V2_TAG} manifest', []))
v2_n = len(tiers.get(f'same-origin asset present in the {V2_TAG} tree', [])) v2_n = len(tiers.get(f'same-origin asset present in the {V2_TAG} tree', []))
code_n = len(tiers.get('code (same-origin module/document)', [])) code_n = len(tiers.get('code (same-origin module/document)', []))
OK(f"classic fetch surface CLEAN against the {V2_TAG} tag — {len(observed)} network " exc_n = sum(len(v) for k, v in tiers.items() if k.startswith('CARRIED EXCEPTION'))
f"requests, 0 outside the baseline ({code_n} code modules · {v2_n} same-origin assets " OK(f"classic fetch surface CLEAN against the {V2_TAG} tag ({V2_TAG} = v2's final tagged "
f"present at {V2_TAG} · {depot_n} depot assets named in the {V2_TAG} manifest, incl. the " f"state, Fable's R37 ruling) — {len(observed)} network requests, 0 outside the baseline "
f"four v2-era street GLBs, which are BASELINE and must never be 'fixed' away)") f"({code_n} code modules · {v2_n} same-origin assets present at {V2_TAG} · {depot_n} depot "
f"assets named in the {V2_TAG} manifest, incl. the four v2-era street GLBs, which are "
f"BASELINE and must never be 'fixed' away · {exc_n} carried exception(s), listed below)")
for tier, urls in sorted(tiers.items()): for tier, urls in sorted(tiers.items()):
if tier.startswith('POST-v2.0'): if tier.startswith('CARRIED EXCEPTION'):
WARN_ONCE = f"classic carries a POST-{V2_TAG} fetch delta: {len(urls)} file(s) — " \ print(f" \033[33m·\033[0m EXCEPTION (NOT {V2_TAG} baseline): "
f"{sorted({u.split('/')[-1] for u in urls})}{tier.split('')[-1]}. " \ f"{sorted({u.split('/')[-1] for u in urls})}{tier.split('', 1)[-1]}")
f"Allowed here so the suite is not permanently yellow over shipped " \
f"behaviour; UNRATIFIED. Fable's to bless or retire."
print(f" \033[33m·\033[0m {WARN_ONCE}")
# ── THE CONTROL, demonstrated in-run: two fabricated fetches must both go RED ── # ── THE CONTROL, demonstrated in-run: two fabricated fetches must both go RED ──
# (a) the R36 breach replayed exactly — a same-origin ped GLB added after v2.0. An # (a) the R36 breach replayed exactly — a same-origin ped GLB added after v2.0. An
@ -1072,6 +1081,214 @@ def smoke_tram(p):
finally: finally:
b.close() b.close()
# ── [R37 item 0.1, F half] THE KERB GATE — poster clearance, measured on the PAINT ────────────────
# John's ruling: the band between kerb and shopfront is FOOTPATH. Lane A corrected its plan-side
# selfcheck (e4d7762) and pinned the pre-ruling failure at exactly 14 posters on the default boot;
# Lane B narrowed the road quad and extended the merged footGeos class inward (47db478) and shipped
# `?verge=0`, which reverts to the pre-ruling geometry permanently.
#
# A's gate is PLAN-SIDE: it asks whether a poster's offset is inside `vergeBand(e)[0]`. That is the
# right question for A's file, but it still never reads a number that came from B — which is the
# exact failure mode ("the gate and its subject were the same function agreeing with itself") that
# made the old one vacuous. So F's gate asks the RUNTIME question instead, and asks it of the paint:
#
# RAYCAST STRAIGHT DOWN AT EVERY POSTER AND SEE WHAT SURFACE IS ACTUALLY UNDER IT.
#
# The topmost ground hit is classified by MATERIAL IDENTITY — `skins.groundMat()` is a cached
# factory, so the road mesh's material IS the object `groundMat('djsim-road')` returns; no string
# matching, no mesh names, nothing that drifts when B edits. Topmost (not first-by-edge) is
# deliberate: B put the carriageway ON TOP at junctions (ROAD_Y 0 → 0.04) so roads run through
# intersections, and what a player sees under a poster is the top surface.
_KERB_JS = r"""
() => {
const P = window.PROCITY, T = P.THREE, skins = P.skins;
// the four merged ground classes, identified by the cached material instance itself
const CLASSES = ['djsim-road', 'djsim-footpath', 'grass', 'brickpave'];
const matOf = new Map(CLASSES.map(n => [skins.groundMat(n), n]));
const meshes = [];
P.scene.traverse(o => { if (o.isMesh && matOf.has(o.material)) meshes.push(o); });
const classify = (x, z) => {
const rc = new T.Raycaster(new T.Vector3(x, 40, z), new T.Vector3(0, -1, 0), 0, 200);
const hits = rc.intersectObjects(meshes, false);
if (!hits.length) return { cls: 'none', y: null };
let top = hits[0];
for (const h of hits) if (h.point.y > top.point.y) top = h;
return { cls: matOf.get(top.object.material), y: +top.point.y.toFixed(3) };
};
// the rendered posters: read the real InstancedMesh matrices, not the plan array
const rendered = [];
const m4 = new T.Matrix4(), v3 = new T.Vector3();
P.scene.traverse(o => {
if (o.isInstancedMesh && o.name === 'venue-posters') {
for (let i = 0; i < o.count; i++) {
o.getMatrixAt(i, m4); v3.setFromMatrixPosition(m4); o.localToWorld(v3);
rendered.push([+v3.x.toFixed(3), +v3.z.toFixed(3)]);
}
}
});
const planned = (P.plan.posters || []).map(q => [+q.x.toFixed(3), +q.z.toFixed(3)]);
// rendered planned agreement (licenses using plan ids for the per-poster report)
let matched = 0, worstDelta = 0;
for (const r of rendered) {
let bd = 1e18;
for (const q of planned) { const d = Math.hypot(r[0] - q[0], r[1] - q[1]); if (d < bd) bd = d; }
if (bd <= 0.01) matched++;
if (bd > worstDelta) worstDelta = bd;
}
// the clearance measurement
const per = rendered.map(([x, z]) => ({ x, z, ...classify(x, z) }));
const onRoad = per.filter(q => q.cls === 'djsim-road');
// DETECTOR CONTROLS: the classifier must be able to SAY 'road' and to SAY 'footpath' on this
// boot, or "0 posters on road" is a sentence about nothing. Sample the centreline of the
// longest main edge (must be road) and a point just outboard of its kerb (must be footpath).
const nodes = new Map(P.plan.streets.nodes.map(n => [n.id, n]));
let best = null, bestL = -1;
for (const e of P.plan.streets.edges) {
if (e.kind !== 'main') continue;
const a = nodes.get(e.a), b = nodes.get(e.b); if (!a || !b) continue;
const L = Math.hypot(b.x - a.x, b.z - a.z);
if (L > bestL) { bestL = L; best = { e, a, b }; }
}
let centre = null, band = null, outboard = null, edgeInfo = null;
if (best) {
const { e, a, b } = best;
const mx = (a.x + b.x) / 2, mz = (a.z + b.z) / 2;
const dx = (b.x - a.x) / bestL, dz = (b.z - a.z) / bestL;
const px = -dz, pz = dx; // perpendicular
centre = { at: [+mx.toFixed(2), +mz.toFixed(2)], ...classify(mx, mz) };
const inner = (P.plan.__vb || null); // not published; derive from the edge
const half = e.width / 2;
// 1 m inboard of the corridor edge under the RULING this is footpath, pre-ruling it is road
const ox = mx + px * (half - 1), oz = mz + pz * (half - 1);
outboard = { at: [+ox.toFixed(2), +oz.toFixed(2)], offset: +(half - 1).toFixed(2), ...classify(ox, oz) };
edgeInfo = { kind: e.kind, width: e.width, len: +bestL.toFixed(1) };
}
const tally = {};
for (const q of per) tally[q.cls] = (tally[q.cls] || 0) + 1;
return { posters: rendered.length, planPosters: planned.length, matched, worstDelta: +worstDelta.toFixed(4),
groundMeshes: meshes.length, tally, onRoad: onRoad.length,
onRoadSample: onRoad.slice(0, 4).map(q => ({ x: q.x, z: q.z, y: q.y })),
centre, outboard, edgeInfo };
}
"""
def _kerb_measure(p, query, label):
b, pg, errs = new_page(p)
try:
boot(pg, query)
pg.evaluate("() => window.DBG.setSegment(2)")
pg.wait_for_timeout(400)
r = pg.evaluate(_KERB_JS)
r['errs'] = errs
r['label'] = label
return r
finally:
b.close()
def smoke_kerb(p):
"""[R37 item 0.1, Lane F half] THE KERB IS FOOTPATH — the runtime gate, and its control.
Measured on the PAINT, not on the plan: raycast straight down at every rendered poster and
classify the topmost ground hit by the cached `skins.groundMat()` material instance itself.
Lane A's corrected selfcheck asks the plan-side question and pins the pre-ruling failure at
exactly 14; this asks whether the player is looking at bitumen under the poster, which is a
number that comes from Lane B's geometry and from nowhere else.
Arms:
1. SUBJECT posters exist on the default boot, and the RENDERED InstancedMesh matrices agree
with `plan.posters` to 1 cm (nobody had ever asserted that the poster you see is the poster
A placed). Zero posters FAIL, never a skip.
2. DETECTOR CONTROLS the classifier must be able to return 'road' AND 'footpath' on this
boot: the centreline of the longest main edge must classify as road, and a point 1 m inboard
of the corridor edge must classify as footpath. Without this pair, "0 posters on road" could
be true because the detector never says road.
3. THE RULING 0 posters stand on road paint on the default boot.
4. THE CONTROL the SAME leg under `?verge=0` must FAIL, at exactly 14 (Lane A's pinned
pre-ruling count, and B's flag reverts to byte-identical pre-ruling vertices). Keyed to the
FLAG, not to a line number, exactly as A keyed its own control.
5. CLASSIC KEEPS ITS PAINT (Fable's mid-round ruling) — under `?classic=1` the same outboard
sample must still classify as ROAD, i.e. the covenanted town's render did not move."""
head('SMOKE: the kerb (R37 0.1 — poster clearance measured on the paint · ?verge=0 is the control)')
d = _kerb_measure(p, '', 'default')
v = _kerb_measure(p, 'verge=0', '?verge=0')
# ── arm 1: the subject, and rendered == planned ───────────────────────────────────────────
if not d['posters']:
FAIL('kerb: ZERO rendered posters on the default boot — the gate has no subject and FAILS '
'(it does not skip). Expected the gig layer default-on since R16.')
return
if d['posters'] == d['planPosters'] and d['matched'] == d['posters']:
OK(f"subject: {d['posters']} posters rendered == {d['planPosters']} in plan.posters, every one "
f"within {d['worstDelta']} m of its planned position (the poster you see IS the poster A placed)")
else:
FAIL(f"kerb: rendered posters do not match the plan — {d['posters']} rendered / "
f"{d['planPosters']} planned / {d['matched']} matched, worst delta {d['worstDelta']} m")
# ── arm 2: the detector can say both words ────────────────────────────────────────────────
c, o, ei = d.get('centre'), d.get('outboard'), d.get('edgeInfo')
if not c or not o:
FAIL('kerb: no main edge to calibrate the surface detector against')
else:
if c['cls'] == 'djsim-road':
OK(f"detector control A: the centreline of the longest main ({ei['kind']}@{ei['width']} m, "
f"{ei['len']} m) classifies as ROAD at y={c['y']} — the detector can see bitumen")
else:
FAIL(f"detector control A: a main-edge CENTRELINE classifies as '{c['cls']}', not road — "
f"the surface detector is not measuring what it thinks ({c})")
if o['cls'] == 'djsim-footpath':
OK(f"detector control B: {o['offset']} m off that centreline (1 m inboard of the corridor "
f"edge) classifies as FOOTPATH at y={o['y']} — THE RULING IS IN THE PAINT")
else:
FAIL(f"detector control B: {o['offset']} m off the main centreline classifies as "
f"'{o['cls']}', expected footpath — the kerb ruling is not in the geometry ({o})")
# ── arm 3: the ruling ─────────────────────────────────────────────────────────────────────
if d['onRoad'] == 0:
OK(f"THE RULING HOLDS: 0 of {d['posters']} posters stand on road paint on the default boot "
f"(surface tally {d['tally']})")
else:
FAIL(f"KERB RULING BREACHED: {d['onRoad']} of {d['posters']} posters stand on road paint on the "
f"default boot — {d['onRoadSample']} (tally {d['tally']})")
# ── arm 4: THE CONTROL — the same leg, under ?verge=0, must go red at exactly 14 ───────────
if v.get('posters') != d['posters']:
FAIL(f"kerb control: ?verge=0 changed the POSTER population ({v.get('posters')} vs {d['posters']}) "
f"— it is a render flag and must not touch the plan; the control is not comparable")
elif v['onRoad'] == 0:
FAIL('kerb CONTROL FAILED: ?verge=0 reverts to the pre-ruling street and the clearance leg '
'still passes there — the leg is blind to where the road is painted, which is the exact '
'vacuous species this item was opened to retire')
elif v['onRoad'] == 14:
OK(f"CONTROL: the same leg FAILS under ?verge=0 at EXACTLY 14 posters on road paint — Lane A's "
f"pinned pre-ruling count, reproduced at runtime off Lane B's geometry (tally {v['tally']})")
else:
WARN(f"kerb control goes red under ?verge=0 as required, but at {v['onRoad']} posters, not the "
f"pinned 14 (A: selfcheck, plan-side; F: raycast, paint-side). Both are non-zero so the leg "
f"is falsifiable; the count needs reconciling — sample {v['onRoadSample']}, tally {v['tally']}")
# ── arm 5: CLASSIC KEEPS ITS PAINT (Fable's mid-round ruling) ─────────────────────────────
cl = _kerb_measure(p, 'classic=1', '?classic=1')
co = cl.get('outboard')
if not co:
FAIL('kerb/classic: no main edge to sample')
elif co['cls'] == 'djsim-road':
OK(f"CLASSIC KEEPS ITS PAINT: {co['offset']} m off the main centreline is still ROAD under "
f"?classic=1 (footpath on the default boot at the same point) — the covenanted render did "
f"not move on a render-side ruling")
else:
FAIL(f"?classic=1 ADOPTED the kerb ruling: {co['offset']} m off the centreline classifies as "
f"'{co['cls']}', expected road. Fable ruled classic is FENCED, not amended ({co})")
if cl['posters']:
FAIL(f"?classic=1 rendered {cl['posters']} posters — the gig layer leaked into the covenant")
for r in (d, v, cl):
if r.get('errs'):
FAIL(f"kerb/{r['label']}: {len(r['errs'])} console error(s); first: {r['errs'][0][:140]}")
def smoke_audio(p): def smoke_audio(p):
"""R11 audio house-law (Lane F): silent-and-happy, nothing plays pre-gesture, ?mute=1 silences, """R11 audio house-law (Lane F): silent-and-happy, nothing plays pre-gesture, ?mute=1 silences,
?noassets=1 fetches zero audio, and interior beds play + release AudioNodes across enter/exit. ?noassets=1 fetches zero audio, and interior beds play + release AudioNodes across enter/exit.
@ -3223,7 +3440,8 @@ def main():
smoke_booktoy(p) # STRICT (r9) — book/toy real stock smoke_booktoy(p) # STRICT (r9) — book/toy real stock
smoke_presence(p) # new (warn) — interior presence (browsers) smoke_presence(p) # new (warn) — interior presence (browsers)
smoke_shelfbuy(p) # new (warn) — buy-anywhere (book/toy shelves) smoke_shelfbuy(p) # new (warn) — buy-anywhere (book/toy shelves)
smoke_tram(p) # new (warn) — tram (auto-skips if not landed) smoke_tram(p) # [R37 0.2] REBUILT STRICT — runs where it runs, genuinely absent where fenced
smoke_kerb(p) # [R37 0.1] THE KERB IS FOOTPATH — poster clearance on the paint + the ?verge=0 control
smoke_audio(p) # R11 — audio house-law (silent-happy · pre-gesture · mute · noassets · leak) smoke_audio(p) # R11 — audio house-law (silent-happy · pre-gesture · mute · noassets · leak)
smoke_gigs(p) # R12/13 — the district gig layer (schedule · band · crowd · budget · cover · noassets) smoke_gigs(p) # R12/13 — the district gig layer (schedule · band · crowd · budget · cover · noassets)
smoke_continuity(p) # R15 — identity continuity (the ped you followed is in the crowd · settled tris) smoke_continuity(p) # R15 — identity continuity (the ped you followed is in the crowd · settled tris)