PROCITY/tools/qa/r39_transmission.py
m3ultra d14cf7fa6e Lane F R41 §41.6: 18 gates green — the deny-list, the wardrobe switch, and no byte-hash goldens
qa.sh --strict: 18 passed · 0 failed · 0 warn · 0 skipped. selfcheck 157,647/157,647,
fingerprint 0x5f76e76 unmoved. No tag — John's playtest session rules the epoch.

THE FIVE ASKS. [C] wardrobe wired via exported WARDROBE_BASE + stockBaseFor(shop), preloaded
inside the existing STOCK_REAL gate: ON under ?stock=real (52 pack items, 69 garment ids on
rendered meshes, 1 atlas, exactly 2 requests) and CHEAPER (59->55 draws, 111->100 textures);
OFF is what ships by default, A/B'd against a reverted control tree — default arm identical
on every counter (160 URLs same hash, 131/18,018 street, 59/28,505 interior). [D] three gates
wired (r41_shots.py writes to TMPDIR so gate runs never rewrite committed shots). [E]
clips_verify wired — 46 clips / 6 groups / 3,498,124 B.

[B's bookmark finding] CONFIRMED AND WIDER: street_noon, shopfront_detail, crossroads_busy
AND market_square all give 3 distinct hashes across 3 boots; only night_neon is stable.
RULING: no gate pins a screenshot byte-hash on any bookmark — everything R41 asserts is a
counter. Filed to B: one await document.fonts.ready in buildings.js.

[C's drawSweep] CONFIRMED INDEPENDENTLY with F's own sweep (never calls C's): GLB-on worst
123 @ dept/auto. The phantom control (one stale room left in scene) reads 197 — +74 on every
reading — decomposing R39/R40's '188' as 116 real + ~72 phantom.

NEW GATES, controls demonstrated. r41_denylist.mjs (ruling 3): 738 files / 197.3 MiB scanned
by path AND bytes, 7 banned names, 0 hits; the control plants a banned manifest row every run
-> RED on 2 names -> removed -> GREEN. r41_integration.py: wardrobe both arms · interior <=350
on both instruments · ?noassets=1 zero across six fetch classes over a 3-shop walk (control
fetches 5/6) · ?clips=0 142 URLs and ?classic=1 125 URLs with zero R41 cargo.

BUDGETS. Street: noon 282 · NIGHT 291/120,093 — margin 9, INTACT · classic 269 byte-exact ·
?clips=0 NIGHT 291, delta 0. No lane spent a street draw. Interior: true pre-R41 116, R41 123
@ dept/auto, margin 227; over 33 real shops worst 110; pub 49 quiet / 77 gig night.

FILED BACK: flags_check's _enter_record_shop went RED on 8 smokes because §41.4's bins put
every one of the first six record-shop counters inside 2.6 m — widened to the whole open set,
verified not a game defect. smoke_djdance read _actions[0] and D's per-instance clip swapping
made the mixer multi-action, so a healthy dancer was called a stall — now follows the clip by
name. D's r41_shots.py browse arm is deterministically red here (re-enters the winner after a
~3 s/candidate scan, by which time the occupant has left) — wired WARN-level with the reason
at the call site, fix handed to D. F's own r39_transmission.py had an unmeasured 30 s goto
default that flaked once under a full strict run; pinned to 90 s.

11 proof frames in docs/shots/laneF_r41/ with sidecars: street_postures (5 rigs, 3 clips
playing) against its ?clips=0 control (1 clip) · street_lean · browse_interior · pub_furnished
+ the honest kit before/after pair · record_dj_booth · opshop_wardrobe on/off · credits_panel
with ODbL on screen. Every humanoid frame carries its R10 human-sized line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-07 18:11:58 +10:00

298 lines
17 KiB
Python

#!/usr/bin/env python3
"""PROCITY Lane F — R39 §39.5 gate E: THE TRANSMISSION PRE-PASS, measured on both sides.
Lane E stripped `transmissionFactor: 1` from three GLBs (`bookshelf` shipped, `longbench` +
`streetlight` unwired) because three.js runs a **transmission pre-pass** when any material in the
scene has `transmission > 0` — `renderTransmissionPass()` renders the whole opaque list a second
time, so every opaque draw is issued twice. Lane C measured `opshop`/hall 191 -> 104 by zeroing it.
**That measurement is the falsifiable arm and this tool runs it.** Two port-isolated no-store roots,
identical inode-for-inode EXCEPT one file:
· TREATMENT — the shipped tree (E's stripped bookshelf)
· CONTROL — the same tree with `transmissionFactor: 1` REINSERTED into that one material,
fabricated here (JSON chunk rewritten, BIN copied through byte for byte)
…both driven through `interior_test.html`'s own `drawSweep` — the >=350-draw law's own instrument —
with `?localdepot=1` so the GLB comes off the served root and the swap is the only variable.
The fabricated glass GLB doubles as the validator's control asset: `--validator` points
`pipeline/validate_manifest.py` at a root containing it and asserts the R39 HARD FAIL fires.
Run: tools/.venv/bin/python tools/qa/r39_transmission.py [--validator] [--json OUT]
"""
import sys, os, json, time, socket, struct, shutil, subprocess, pathlib, tempfile
ROOT = pathlib.Path(__file__).resolve().parent.parent.parent
PORT_TREAT = int(os.environ.get('PROCITY_R39_PORT', '8741'))
PORT_CTRL = PORT_TREAT + 1
BOOKSHELF = 'procity_fit_bookshelf_01.glb'
MATERIAL = 'mtl_10218_Bookshelves_v1'
fails, notes = [], []
def FAIL(m): fails.append(m); print(f" \033[31m✗ FAIL\033[0m {m}")
def OK(m): print(f" \033[32m✓\033[0m {m}")
def head(m): print(f"\n\033[1m{m}\033[0m")
# ── GLB surgery (the same shape as pipeline/strip_transmission.py, run in reverse) ────────────────
def glb_chunks(data):
assert data[:4] == b'glTF', 'not a GLB'
off, out = 12, []
while off < len(data):
ln, ty = struct.unpack_from('<II', data, off); off += 8
out.append((ty, data[off:off + ln])); off += ln
return out
def glb_json(path):
for ty, payload in glb_chunks(pathlib.Path(path).read_bytes()):
if ty == 0x4E4F534A:
return json.loads(payload.decode('utf-8'))
raise AssertionError('no JSON chunk')
def transmissive_materials(path):
"""[(material name, factor)] for every material with transmissionFactor > 0."""
j = glb_json(path)
hits = []
for m in j.get('materials', []):
t = (m.get('extensions') or {}).get('KHR_materials_transmission')
if t and float(t.get('transmissionFactor', 0)) > 0:
hits.append((m.get('name'), float(t['transmissionFactor'])))
return hits
def make_glass(src, dst, material=None, factor=1.0):
"""Write `dst` = `src` with KHR_materials_transmission reinserted. BIN copied through unchanged;
the function returns (sha1_bin_src, sha1_bin_dst) so the caller can prove only JSON moved."""
import hashlib
data = pathlib.Path(src).read_bytes()
chunks = glb_chunks(data)
j = None; binp = b''
for ty, payload in chunks:
if ty == 0x4E4F534A: j = json.loads(payload.decode('utf-8'))
elif ty == 0x004E4942: binp = payload
touched = []
for m in j.get('materials', []):
if material and m.get('name') != material: continue
m.setdefault('extensions', {})['KHR_materials_transmission'] = {'transmissionFactor': factor}
touched.append(m.get('name'))
if material: break
used = j.setdefault('extensionsUsed', [])
if 'KHR_materials_transmission' not in used: used.append('KHR_materials_transmission')
jb = json.dumps(j, separators=(',', ':')).encode('utf-8')
jb += b' ' * ((4 - len(jb) % 4) % 4)
bb = binp + b'\x00' * ((4 - len(binp) % 4) % 4)
total = 12 + 8 + len(jb) + (8 + len(bb) if binp else 0)
out = bytearray(b'glTF' + struct.pack('<II', 2, total))
out += struct.pack('<II', len(jb), 0x4E4F534A) + jb
if binp: out += struct.pack('<II', len(bb), 0x004E4942) + bb
pathlib.Path(dst).write_bytes(bytes(out))
return touched, hashlib.sha1(binp).hexdigest(), hashlib.sha1(bb).hexdigest()
# ── servers ──────────────────────────────────────────────────────────────────────────────────────
def port_up(port):
with socket.socket() as s:
s.settimeout(0.4); return s.connect_ex(('127.0.0.1', port)) == 0
NOSTORE = r'''
import sys, http.server, functools
class H(http.server.SimpleHTTPRequestHandler):
def end_headers(self):
self.send_header('Cache-Control', 'no-store, no-cache, must-revalidate')
self.send_header('Pragma', 'no-cache')
super().end_headers()
def log_message(self, *a): pass
http.server.HTTPServer(('127.0.0.1', int(sys.argv[1])),
functools.partial(H, directory=sys.argv[2])).serve_forever()
'''
def serve(root, port):
proc = subprocess.Popen([sys.executable, '-c', NOSTORE, str(port), str(root)],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
for _ in range(80):
if port_up(port): return proc
time.sleep(0.1)
proc.terminate(); raise SystemExit(f'could not serve {root} on :{port}')
def mirror_except(src, path_parts, replacement):
"""A temp mirror of `src` in which every entry is a SYMLINK to the original except the single
file at `path_parts`, which is a copy of `replacement`. Only the directories on that path are
real; everything else is the same inode, so the one file is the only variable."""
dst = pathlib.Path(tempfile.mkdtemp(prefix='procity-r39-mirror-'))
def walk(s, d, parts):
d.mkdir(parents=True, exist_ok=True)
for e in pathlib.Path(s).iterdir():
if parts and e.name == parts[0]:
if len(parts) == 1: shutil.copy2(replacement, d / e.name)
else: walk(e, d / e.name, parts[1:])
else:
(d / e.name).symlink_to(e)
walk(src, dst, list(path_parts))
return dst
def glass_root(glb_name=BOOKSHELF, material=MATERIAL):
"""web/ mirrored symlink-for-symlink EXCEPT assets/models/<glb_name>, which is the fabricated
glass copy. Every other byte the browser sees is the same inode."""
d = pathlib.Path(tempfile.mkdtemp(prefix='procity-r39-glass-'))
src = ROOT / 'web'
for e in src.iterdir():
if e.name != 'assets': (d / e.name).symlink_to(e)
a = d / 'assets'; a.mkdir()
for e in (src / 'assets').iterdir():
if e.name != 'models': (a / e.name).symlink_to(e)
m = a / 'models'; m.mkdir()
for e in (src / 'assets' / 'models').iterdir():
if e.name != glb_name: (m / e.name).symlink_to(e)
touched, s0, s1 = make_glass(src / 'assets' / 'models' / glb_name, m / glb_name, material)
return d, touched, s0, s1
# ── the sweep ────────────────────────────────────────────────────────────────────────────────────
def sweep(pg, host, glb):
# [Lane F R41 §41.6] EXPLICIT NAVIGATION TIMEOUT. `goto` waits for `load` — every subresource —
# and inherits Playwright's 30 s default, which is not a measured number for this page. It tripped
# once inside a full `qa.sh --strict` run (four browser gates back to back on a loaded box) and
# turned an infrastructure hiccup into a RED gate with a stack trace where an assertion should be.
# Measured on this tree: the page reaches `load` in **0.4 s over 27 requests**, three runs out of
# three, and the gate passes standalone every time. 90 s is therefore ~200x the real cost and
# cannot mask a genuine regression — anything approaching it is a different bug entirely.
pg.goto(f'{host}/interior_test.html?localdepot=1', timeout=90000)
pg.wait_for_function('() => !!window.PROCITY_C', timeout=30000)
pg.wait_for_timeout(600)
return pg.evaluate('(glb) => window.PROCITY_C.drawSweep({ glb })', glb)
def main():
from playwright.sync_api import sync_playwright
want_validator = '--validator' in sys.argv
out_json = None
if '--json' in sys.argv: out_json = sys.argv[sys.argv.index('--json') + 1]
result = {}
head('GATE R39 §39.5-E: THE TRANSMISSION PRE-PASS — the shipped tree vs a fabricated glass control')
shipped = ROOT / 'web' / 'assets' / 'models' / BOOKSHELF
hits = transmissive_materials(shipped)
if hits: FAIL(f'the SHIPPED {BOOKSHELF} still carries transmission: {hits}')
else: OK(f'shipped {BOOKSHELF}: 0 transmissive materials (E\'s strip is in the served tree)')
gdir, touched, sha_src, sha_dst = glass_root()
result['glassMaterials'] = touched
if touched == [MATERIAL] and sha_src == sha_dst:
OK(f'control asset fabricated: {touched[0]} transmissionFactor 1 · BIN sha1 IDENTICAL ({sha_src[:12]}…) — only the JSON chunk moved')
else:
FAIL(f'control asset fabrication wrong: touched={touched} binSha {sha_src[:12]} vs {sha_dst[:12]}')
gh = transmissive_materials(gdir / 'assets' / 'models' / BOOKSHELF)
if gh: OK(f'control asset re-scans DIRTY, as intended: {gh}')
else: FAIL('control asset did not take the transmission flag — the control is vacuous')
# ── the validator's hard fail, proven to FIRE (E's gate) ──────────────────────────────────────
if want_validator:
head('the validator control — pipeline/validate_manifest.py must HARD FAIL on the glass asset')
# validate_manifest.py reads pipeline/_normalized/<file> (NOT web/assets/models/), so the
# control asset has to land THERE or the gate is being pointed at a file it never opens.
# My own first cut patched web/assets/models/ and the control reported "did not fire" — the
# harness bug, not E's gate. Recorded because it is exactly the species this round is about.
vroot = mirror_except(ROOT, ('pipeline', '_normalized', BOOKSHELF),
gdir / 'assets' / 'models' / BOOKSHELF)
r = subprocess.run([sys.executable, 'pipeline/validate_manifest.py'],
cwd=str(vroot), capture_output=True, text=True)
blob = r.stdout + r.stderr
result['validator'] = {'rc': r.returncode, 'mentions': 'transmissionFactor' in blob or 'transmission' in blob.lower()}
if r.returncode != 0 and 'transmission' in blob.lower():
line = next((l for l in blob.splitlines() if 'transmission' in l.lower()), '')
OK(f'validator HARD FAILS on the glass asset (rc {r.returncode}): {line.strip()[:150]}')
else:
FAIL(f'validator did NOT fail on a transmissive GLB (rc {r.returncode}) — E\'s gate is vacuous')
r2 = subprocess.run([sys.executable, 'pipeline/validate_manifest.py'],
cwd=str(ROOT), capture_output=True, text=True)
if r2.returncode == 0: OK('validator PASSES on the shipped tree (the positive control — the gate is not simply always-red)')
else: FAIL(f'validator red on the shipped tree: {(r2.stdout + r2.stderr)[-300:]}')
# ...and the gate's OWN blind spot, measured rather than assumed: check_transmission()
# returns silently when pipeline/_normalized/<file> is absent, so a depot-only GLB is never
# parsed. Demonstrated by deleting the local copy and re-running with the glass file live.
vroot2 = mirror_except(ROOT, ('pipeline', '_normalized', BOOKSHELF), gdir / 'assets' / 'models' / BOOKSHELF)
(vroot2 / 'pipeline' / '_normalized' / BOOKSHELF).unlink()
r3 = subprocess.run([sys.executable, 'pipeline/validate_manifest.py'],
cwd=str(vroot2), capture_output=True, text=True)
result['validatorDepotOnly'] = {'rc': r3.returncode}
if r3.returncode == 0:
notes.append('validate_manifest.py check_transmission() SKIPS any GLB with no local '
'pipeline/_normalized copy — a depot-only transmissive asset passes silently. '
'(web/assets/models/, which ?localdepot=1 actually serves, is never scanned either.)')
print(f" \033[33mnote\033[0m the validator's own blind spot, demonstrated: with the local "
f"_normalized copy removed the same glass asset passes (rc {r3.returncode}) — the check is "
f"local-file-only. Ask filed to Lane E.")
shutil.rmtree(vroot2, ignore_errors=True)
shutil.rmtree(vroot, ignore_errors=True)
if '--no-sweep' in sys.argv:
shutil.rmtree(gdir, ignore_errors=True)
print()
if fails: print(f"\033[31m{len(fails)} FAIL\033[0m"); return 1
print("\033[32mvalidator arm GREEN\033[0m"); return 0
# ── the sweep, both roots ─────────────────────────────────────────────────────────────────────
head('the interior draw sweep — 12 types x 7 archetypes, GLB off and on, on both roots')
p_t = serve(ROOT / 'web', PORT_TREAT)
p_c = serve(gdir, PORT_CTRL)
try:
with sync_playwright() as p:
b = p.chromium.launch()
pg = b.new_page(viewport={'width': 1280, 'height': 720})
errs = []
pg.on('console', lambda m: errs.append(m.text) if m.type == 'error' else None)
for name, port in (('treatment', PORT_TREAT), ('control_glass', PORT_CTRL)):
host = f'http://127.0.0.1:{port}'
off = sweep(pg, host, False)
on = sweep(pg, host, True)
result[name] = {'glbOff': off, 'glbOn': on}
print(f" {name:14s} GLB-off worst {off['worst']:4d} ({off['worstAt']}) "
f"GLB-on worst {on['worst']:4d} ({on['worstAt']})")
b.close()
finally:
p_t.terminate(); p_c.terminate(); shutil.rmtree(gdir, ignore_errors=True)
t_on = result['treatment']['glbOn']; c_on = result['control_glass']['glbOn']
t_off = result['treatment']['glbOff']; c_off = result['control_glass']['glbOff']
delta = c_on['worst'] - t_on['worst']
result['summary'] = {'glbOnWorst': t_on['worst'], 'glbOnWorstAt': t_on['worstAt'],
'glassWorst': c_on['worst'], 'glassWorstAt': c_on['worstAt'],
'saved': delta, 'law': t_on['law'],
'marginTreatment': t_on['law'] - t_on['worst'],
'marginGlass': c_on['law'] - c_on['worst'],
'glbOffWorst': t_off['worst'], 'glbOffWorstAt': t_off['worstAt']}
head('the verdict')
print(f" GLB-on worst room · with E's fix: {t_on['worst']} ({t_on['worstAt']}) "
f"· with transmission restored: {c_on['worst']} ({c_on['worstAt']}) saved {delta}")
print(f" GLB-off worst room · {t_off['worst']} ({t_off['worstAt']}) vs {c_off['worst']} ({c_off['worstAt']}) "
f"(a GLB-off room loads no GLB, so this pair MUST be equal — it is the control's own control)")
if delta > 0: OK(f"the pre-pass is real and E's fix took it out: {c_on['worst']} -> {t_on['worst']} draws (-{delta}, -{100*delta/max(1,c_on['worst']):.0f}%)")
else: FAIL(f"the sweep did NOT drop with transmission stripped (delta {delta}) — E's fix is not reaching the served tree")
if t_off['worst'] == c_off['worst']: OK(f"GLB-off is identical on both roots ({t_off['worst']}) — the delta above is the GLB and nothing else")
else: FAIL(f"GLB-off differs between roots ({t_off['worst']} vs {c_off['worst']}) — the two roots are not otherwise identical")
if t_on['worst'] <= t_on['law']: OK(f"the >=350 law holds with {t_on['law'] - t_on['worst']} draws of margin (was {c_on['law'] - c_on['worst']} with the glass bookshelf)")
else: FAIL(f"the shipped tree BREACHES the {t_on['law']}-draw interior law at {t_on['worst']}")
per = [(k, c_on['perType'].get(k, 0), t_on['perType'].get(k, 0)) for k in t_on['perType']]
print('\n per type (GLB-on worst archetype): glass -> fixed')
for k, c, t in sorted(per, key=lambda r: -(r[1] - r[2])):
print(f" {k:10s} {c:4d} -> {t:4d} {t - c:+d}")
if out_json: pathlib.Path(out_json).write_text(json.dumps(result, indent=1))
print()
if fails:
print(f"\033[31m{len(fails)} FAIL\033[0m"); return 1
print("\033[32mR39 §39.5-E GREEN\033[0m"); return 0
if __name__ == '__main__':
sys.exit(main())