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>