#!/usr/bin/env python3 """rfx-assert.py — the script that refuses to ship the portfolio page. Runs against templates/page.portfolio.liquid and every snippets/rfx-*.liquid it renders. Exit 0 only when every assertion passes. The page's footer prints this run's counts. Published alongside the page so the gate itself can be read. 2026-09-01.""" import re, sys, json, os, datetime ROOT = os.path.dirname(os.path.abspath(__file__)) TEMPLATE = sys.argv[1] if len(sys.argv) > 1 else os.path.join(ROOT, 'WORK31.liquid') SNIP = os.path.join(ROOT, 'snippets') T = open(TEMPLATE, encoding='utf-8').read() names = sorted(set(re.findall(r"(?:render|include) '(rfx-[a-z-]+)'", T))) S = {} for n in names: p = os.path.join(SNIP, n + '.liquid') assert os.path.exists(p), f'snippet missing on disk: {n}' S[n] = open(p, encoding='utf-8').read() for n, c in list(S.items()): # snippets rendered by snippets for m in set(re.findall(r"render '(rfx-[a-z-]+)'", c)): if m not in S: S[m] = open(os.path.join(SNIP, m + '.liquid'), encoding='utf-8').read() ALL = {'template': T, **S} checks, fails = 0, [] def check(cond, msg): global checks checks += 1 if not cond: fails.append(msg) # 1 size — Shopify caps theme files at 256 KB; 250 KB is the safety line for n, c in ALL.items(): check(len(c.encode('utf-8')) < 250_000, f'{n}: {len(c.encode())} bytes over the 250 KB line') # 2 Liquid tag balance for n, c in ALL.items(): for a, b in [('if','endif'),('for','endfor'),('case','endcase'),('capture','endcapture'),('comment','endcomment'),('unless','endunless'),('raw','endraw')]: oa = len(re.findall(r'\{%-?\s*' + a + r'\b', c)); ob = len(re.findall(r'\{%-?\s*' + b + r'\b', c)) check(oa == ob, f'{n}: {a}={oa} vs {b}={ob}') # 3 HTML container balance (comments stripped first so a tag name in prose cannot trip it) for n, c in ALL.items(): body = re.sub(r'\{%-?\s*comment\s*-?%\}.*?\{%-?\s*endcomment\s*-?%\}', '', c, flags=re.S) for tag in ['section','article','details','table','ul','ol','svg','figure','figcaption']: o = len(re.findall(r'<' + tag + r'[\s>]', body)); cl = len(re.findall(r'', body)) check(o == cl, f'{n}: <{tag}> open={o} close={cl}') # 4 at most one schema block, balanced check(len(re.findall(r'\{%-?\s*schema', T)) == len(re.findall(r'\{%-?\s*endschema', T)) <= 1, 'schema/endschema') # 5 ledger integrity: 9 fields per row, unique ids led = S.get('rfx-ledger-data', T) b = re.search(r'\{%- capture rfx_ledger -%\}\n(.*?)\n\s*\{%- endcapture -%\}', led, re.S) check(b is not None, 'ledger capture not found') rows = [r.strip() for r in b.group(1).split('~~~') if r.strip()] if b else [] ids = [r.split('|')[0] for r in rows] check(len(ids) == len(set(ids)), 'duplicate ledger ids: ' + str(sorted({i for i in ids if ids.count(i) > 1}))) for r in rows: check(r.count('|') == 8, 'ledger row field count: ' + r[:40]) # 6 every literal data-ev resolves to a ledger row refs = set(re.findall(r'data-ev="([a-z0-9-]+)"', ''.join(ALL.values()))) check(not (refs - set(ids)), 'data-ev without a ledger row: ' + str(sorted(refs - set(ids)))) # 7 every v_* variable used is assigned exactly once from the ledger loop used = set(re.findall(r'(v_[a-z0-9_]+)', T)); assigned = set(re.findall(r'assign (v_[a-z0-9_]+) =', T)) check(not (used - assigned), 'v_ used but never assigned: ' + str(sorted(used - assigned))) # 8 no superseded figure hardcoded in body copy outside a prior-value context body = T[T.index('', '54,886 lines'] for k in stale: for m in re.finditer(re.escape(k), body): ctx = body[max(0, m.start() - 140):m.start()] check(any(x in ctx for x in ['', 'previously', 'used to', '~~', 'prior', 'said', 'withdrawn']), f'stale literal {k!r}: …{ctx[-60:]!r}') # 9 renders present once each; the three stack sections sit between the proof and the cap/academy for n in names: check(T.count(f"render '{n}'") + T.count(f"include '{n}'") == 1, f'render/include count for {n}') pi = T.index('id="rfx-proof"') o = [T.index(f"render '{n}'") for n in ['rfx-stack-live', 'rfx-uptime-strip', 'rfx-outcomes']] check(pi < o[0] < o[1] < o[2], 'stack sections out of order') # 10 the two terminals exist exactly once each for k in ['audit --self --no-mercy', 'stack status --all', 'This page is what I built instead.']: check(T.count(k) == 1, f'count != 1: {k}') # 11 SVG geometry of the dependency diagram — computed, never eyeballed svg = S['rfx-stack-live'] boxes = [(m.group(1), *map(float, m.groups()[1:])) for m in re.finditer(r'([^<]+)', svg): x, y, end, txt = float(m.group(1)), float(m.group(2)), bool(m.group(3)), re.sub(r'&[a-z]+;', 'x', m.group(4)) w = len(txt) * 6.3; x0 = x - w if end else x; x1 = x0 + w check(0 <= x0 and x1 <= W, f'SVG label outside viewBox: {txt[:20]}') check(not any((not (x1 <= bx or x0 >= bx+bw or y < by or y-10 > by+bh)) for bx, by, bw, bh in boxes), f'SVG label collides: {txt[:20]}') # 12 every animateMotion path equals an arrow path already drawn arrows = set(re.findall(r']*x1="([\d.]+)" y1="([\d.]+)" x2="([\d.]+)" y2="([\d.]+)"', svg)) arrow_paths = {f'M{a},{b} L{c},{d}' for a, b, c, d in arrows} | set(re.findall(r']*path="([^"]+)"', svg): check(pth in arrow_paths, f'packet path is not an arrow: {pth}') # 13 uptime strip epoch lands on the ledger's stated dates up = S['rfx-uptime-strip']; ep = int(re.search(r'assign up_start = (\d+)', up).group(1)) streak = next(r for r in rows if r.startswith('sop-streak|')); days = int(streak.split('|')[1].replace(',', '')) d0 = datetime.datetime.fromtimestamp(ep, datetime.timezone.utc).date(); d1 = d0 + datetime.timedelta(days=days-1) check(str(d0) in streak and str(d1) in streak, f'uptime epoch {d0}→{d1} not matched in the sop-streak receipt') # 14 no raw Liquid leaks into code specimens (they must be inside raw blocks) code = S.get('rfx-code', '') for pre in re.findall(r']*>(.*?)', code, re.S): check('{{' not in pre and '{%' not in pre, 'Liquid syntax inside a code specimen outside raw') # 15 timeline rows well-formed tl = re.search(r'capture tl_data -%\}(.*?)\{%- endcapture', T, re.S) if tl: for r in [x for x in tl.group(1).split('~') if x.strip()]: check(r.strip().count('|') == 3, 'timeline row: ' + r.strip()[:40]) result = {'assertions': checks, 'failures': len(fails), 'date': datetime.date.today().isoformat(), 'files': list(ALL.keys())} print(json.dumps(result)) for f in fails: print(' - ' + f, file=sys.stderr) sys.exit(1 if fails else 0)