#!/usr/bin/env bash # Every refuted claim must appear only inside its own correction. # # tools/port/check-claims # # 🔴 WHY THIS IS A CHECK AND NOT AN AUDIT. The Decoder's rule -- *grep the corpus # for the claim, not for the file you were working in* -- found a refuted sentence # still shipping in this port's `manifest.json`, and a withdrawn one still # standing in `DECISIONS.md`. Running that by hand finds the instances present on # the day it is run. It does not stop the next one. # # So: a REGISTER. Each row is a claim this corpus has refuted, plus a marker that # must appear near every occurrence. A hit without its marker fails the run. # # âš ī¸ Two things learned building it, both from the other agent: # # * a "kept for the record" block STILL ASSERTS. Marking the heading superseded # does not mark the sentence a reader lands on, so the marker must sit near # the CLAIM, not at the top of the section. # * naming a refuted claim keeps it greppable, so this check returns its own # corrections as hits -- which is the point. The marker is what distinguishes # "quoted while being refuted" from "still asserted". set -euo pipefail cd "${PROJECT_DIR:-/work}" WINDOW=400 # characters either side of a hit in which the marker must appear fail=0; total_marked=0; scanned=0; peer_hits=0; _peer_probe_done=0 # 🔴 THE MARKER IS AN EXPLICIT SENTINEL, NOT A KEYWORD. # # The first version matched a per-claim keyword -- "refuted", "WITHDRAWN" -- near # the hit. Every one of its four failures was a quotation sitting INSIDE a # correction whose wording happened not to contain the keyword: a table cell # reading "standing, unmarked", a sentence reading "the real count was ten". # # Widening the window or adding synonyms until those passed would have been # tuning a threshold until the answer came out right, which is the failure this # corpus has spent a fortnight cataloguing. So the marker is a TOKEN THE AUTHOR # PLACES: `[refuted]` near any quotation of a registered claim. It cannot be # satisfied by phrasing, and its absence means exactly one thing. # # âš ī¸ The cost is honest: every quotation must be marked by hand, and a new # refuted claim means a new row plus marking its existing quotations. That work # is the check. MARKER='[refuted]' REGISTER=$(cat <<'ROWS' TAIL of the kept stream :: the leading chunk of a voice region duplicates the end of the kept stream, so it can be dropped known too fast :: the boot plays both splashes faster than the game does only thing making the plate :: the plate reappears because of one authored cause no loop-point field has been identified :: nothing anywhere on the disc or in the runtime states where a bank loops AUDIBLY WRONG AT THE SEAM :: replaying the menu bed from sample 0 puts audible fade-out and silence at the loop seam 1 of 3 streams :: the exporter ships one of a voice region's three streams six expected DIFFERS :: six screens are expected to differ from the reference renderer goes against the port :: the JP title capture adjudicates title_jp against this port's rendering the capture turns out to determine it :: the leaf's phase is fixed by the capture rather than being an arbitrary choice COMPOSITED rather than standalone :: the four screens without an opaque-black primitive are drawn composited over another screen structural limit, not an unrun experiment :: EXTRAS cannot be strengthened past n=1 because this archive holds no second destination HANDOFF Q10 says nothing on the disc :: nothing on the disc names which track the menu plays, so the port must choose one 28 % of `S00A`'s frames :: 28 % of S00A's frames and 47 % of ADV's reached the screen, measured by three routes :: DIFFICULTY is identified by three independent routes HANDOFF has not moved in four milestones :: the contract itself is static, rather than static only on the branch this checkout reads ROWS ) [ -n "${CLAIMS_REGISTER+x}" ] && REGISTER="$CLAIMS_REGISTER" # 🔴 A REGISTER THAT PARSES NOTHING REPORTED CLEAN, FOREVER. The scan loop runs # once per row; with no rows it runs zero times, `fail` stays 0, and the script # printed "every refuted claim appears only inside its correction" and exited 0. # That is the stub defect -- prints a result, asserts nothing -- sitting in the # checker whose clean runs both agents lean on. The Decoder found it in their # equivalent the same day; it was here too. _rows=$(printf '%s\n' "$REGISTER" | grep -c '[^[:space:]]' || true) if [ "$_rows" -eq 0 ]; then echo "🔴 the refuted register is EMPTY -- this check would pass everything." >&2 echo " Exit 2: the harness is broken, not the corpus." >&2 exit 2 fi # -------------------------------------------------------------------------- # `--control`: the known negatives, EXECUTED. # # 🔴 Until now this check had NO control machinery at all. Every "planted a # revival, it failed, removed it, it passed" in `DECISIONS.md` was done BY HAND, # once, and never again -- in a repository where two of my own tools carry the # line *"a control that does not execute is not a control"*. It was written # about somebody else's tool. # # Four cases, each driving THIS script as a subprocess and reading its real exit # code rather than reasoning about what it would do: # # clean tree -> 0 # unmarked revival planted -> 1 (the check must catch it) # revival planted MARKED -> 0 (and must not false-positive on it) # register emptied -> 2 (the harness is broken, not the corpus) # # The plant lands in a real scanned directory, because a control that runs # somewhere the tool does not look proves nothing about the tool. if [ "${1:-}" = "--control" ]; then probe="docs/port/.claims-control-probe.md" trap 'rm -f "$probe"' EXIT INT TERM # The PHRASE only: rows now read `phrase :: proposition`, and the case strings # below are colon-delimited, so passing a whole row made the harness parse the # proposition as a field and report its own cases broken. A data-shape change # breaking the harness that guards the data is this iteration's small version # of my rows making the Decoder's parser fail silently. claim=$(printf '%s\n' "$REGISTER" | grep -m1 '[^[:space:]]') claim="${claim%% :: *}" ok=0 run() { CLAIMS_CONTROL=1 "$0" >/dev/null 2>&1; echo $?; } rm -f "$probe" for case in "clean::0" "unmarked:$claim:1" "marked:$claim [refuted]:0"; do IFS=: read -r name body want <<<"$case" if [ -n "$body" ]; then printf '%s\n' "$body" > "$probe"; else rm -f "$probe"; fi got=$(run) if [ "$got" = "$want" ]; then printf ' %-26s exit %s ✅\n' "$name" "$got" else printf ' %-26s exit %s, wanted %s 🔴\n' "$name" "$got" "$want"; ok=1 fi done rm -f "$probe" # 🔴 FIFTH CASE: the same text OUTSIDE the scanned root must give 0. # # Without it, "the plant is inside a scanned directory" is a property I # verified BY HAND, once -- which is the exact pattern I had just finished # criticising in this tool one iteration earlier. The pair is what asserts the # boundary is real: identical text, exit 1 inside and 0 outside. Either half # alone is consistent with the tool scanning everything, or nothing. # # The Decoder added this to theirs after I raised the boundary; the reason it # was worth adding is that their property held *because they had reasoned it*, # not because anything asserted it. Mine was in the same state. outside="${TMPDIR:-/tmp}/claims-control-outside.md" printf '%s\n' "$claim" > "$outside" got=$(run) rm -f "$outside" if [ "$got" = "0" ]; then printf ' %-26s exit 0 ✅\n' "same text outside root" else printf ' %-26s exit %s, wanted 0 🔴\n' "same text outside root" "$got"; ok=1; fi got=$(CLAIMS_REGISTER="" "$0" >/dev/null 2>&1; echo $?) if [ "$got" = "2" ]; then printf ' %-26s exit 2 ✅\n' "empty register" else printf ' %-26s exit %s, wanted 2 🔴\n' "empty register" "$got"; ok=1; fi # Sixth case: a tree with nothing to scan. It used to die in the withdrawal # hook and exit 1 -- "a refuted claim is still being asserted" -- for a wrong # directory. Liveness and diagnosis are both asserted here. _empty="${TMPDIR:-/tmp}/claims-liveness-root"; mkdir -p "$_empty" got=$(cd "$_empty" && PROJECT_DIR="$_empty" "$OLDPWD/$0" >/dev/null 2>&1; echo $?) if [ "$got" = "2" ]; then printf ' %-26s exit 2 ✅\n' "nothing to scan" else printf ' %-26s exit %s, wanted 2 🔴\n' "nothing to scan" "$got"; ok=1; fi echo [ $ok -eq 0 ] && echo "the register check fails when it must, and says so distinctly" \ || echo "🔴 the control machinery itself is broken" exit $ok fi # ─── THE WITHDRAWAL-TIME HOOK ──────────────────────────────────────────────── # The register enforces claims it KNOWS ABOUT; knowing about them was manual, and # that is how ~8 claims were withdrawn this session and 0 registered. A sweep # cannot fix it -- by the time you sweep, the withdrawal is already unpublished. # The hook fires where the withdrawal is WRITTEN. # # A correction in DECISIONS.md has a shape: a heading carrying WITHDRAWN / # CORRECTION / "refuted". A section like that containing no registered phrase is # a death argued and never indexed. # # âš ī¸ The register is passed in the ENVIRONMENT, not inlined. The first version # pasted the rows into this file's own heredoc -- which made every phrase an # unmarked quotation, and the checker flagged its own source. A tool that # violates the rule it enforces by being written is worth a comment. # # 🟡 REPORTED, NOT ASSERTED: not every correction retires a CLAIM -- some fix a # number, a scope, a wrong floor -- and forcing a row for those would push rows # in to silence the check, the failure this file exists to prevent. # # âš ī¸ AND IT WILL ALWAYS OVER-REPORT ON WELL-WRITTEN CORRECTIONS. The detection is # "does this section contain a registered phrase", which requires the correction # to QUOTE the dead claim. A good correction paraphrases it away: the JP heading # now reads "does NOT go against the port", which does not contain the registered # "goes against the port" [refuted] and is flagged despite being registered. # # The Decoder's resolution is the right one and costs the correction nothing: # **the register entry is the verbatim home of the dead phrase; prose paraphrases # freely.** They are different documents, so the phrase always has one exact # place to live without any correction having to carry it. What follows for this # hook is that its candidate list mixes "never registered" with "registered and # paraphrased", and it cannot separate them -- so the list is a prompt to check, # never a defect count. echo echo "withdrawal-time hook -- correction sections that registered nothing:" # 🔴 PREFLIGHT. Run from the wrong directory this used to die inside the # withdrawal hook with a FileNotFoundError and exit **1** -- which in this # script's own vocabulary means "a refuted claim is still being asserted". A real # failure with a fabricated diagnosis, the same shape as my control anchoring at # the wrong document. The roots it needs are named here and their absence is a # HARNESS fault with its own code. for _root in docs docs/port authored tools/port; do [ -d "$_root" ] || { echo "🔴 \`$_root\` is not here -- this check cannot scan anything." >&2 echo " Exit 2: wrong directory or a bad checkout, not a dirty corpus." >&2 exit 2 } done [ -f docs/port/DECISIONS.md ] || { echo "🔴 docs/port/DECISIONS.md is missing -- the withdrawal hook has nothing" >&2 echo " to read. Exit 2: the harness is broken, not the corpus." >&2 exit 2 } REG="$REGISTER" python3 - <<'HOOK' import os, re reg = [r.strip() for r in os.environ["REG"].split("\n") if r.strip()] doc = open("docs/port/DECISIONS.md").read() heads = [(m.start(), m.group(0)) for m in re.finditer(r"(?m)^##+ .*$", doc)] flagged = 0 for i, (pos, head) in enumerate(heads): # 🔴 THE FIRST REGEX MATCHED HEADINGS *ABOUT* CORRECTIONS, NOT HEADINGS # MAKING THEM -- "withdraw" caught "rather than withdrawing", "refuted" # caught a section discussing the register itself. 33 candidates was a # measurement of the regex. Narrowed to headings that RETIRE something: # a leading WITHDRAWN/CORRECTION/Refuted, or an explicit "is withdrawn". if not re.search(r"^#+\s*(?:[^A-Za-z]*\s*)?(WITHDRAWN|CORRECTION|Refuted)\b" r"|\bis withdrawn\b|\bnow refuted\b", head): continue end = heads[i + 1][0] if i + 1 < len(heads) else len(doc) if not any(c in doc[pos:end] for c in reg): flagged += 1 print(" candidate: %s" % head[:92].lstrip("# ")) print(" none -- every correction section names a registered claim" if not flagged else " %d correction section(s) argue a withdrawal the register does not carry" % flagged) HOOK while IFS= read -r claim; do # 🔴 ROWS CARRY A PROPOSITION NOW, `phrase :: what it asserted`. # # They were bare phrases, and that had two costs. A phrase is not a claim: # `1 of 3 streams` [refuted] is dead here and a LIVE warning in the Decoder's # corpus, and the bare row cannot say which proposition it killed -- so a peer # hit was unadjudicable even in principle. And the bareness made THEIR parser # fail silently: a reader looking for a quoted string in each row found none, # built an empty claim list, and reported a clean table. My data shape made # their instrument lie. # # The phrase is still the search key; the proposition is for whoever has to # judge a hit, here or in another corpus. proposition="${claim#* :: }" claim="${claim%% :: *}" [ -z "$claim" ] && continue hits=0; bad=0; marked=0 while IFS= read -r loc; do [ -z "$loc" ] && continue f=${loc%%:*} hits=$((hits+1)) out=$(python3 - "$f" "$claim" "$MARKER" "$WINDOW" <<'PY' import sys f, claim, marker, w = sys.argv[1], sys.argv[2], sys.argv[3], int(sys.argv[4]) s = open(f, encoding="utf-8", errors="ignore").read() # 🔴 THE REGISTER BLOCK IS ITS OWN VERBATIM HOME, and is excised before # scanning rather than relying on marker proximity. The rows used to be bare # phrases that happened to sit within the marker window of the file header; # adding a proposition to each pushed them out of it, and the check began # reporting its own register as twelve unmarked assertions. Widening the window # would have been tuning a constant to make a failure go away. Excising exactly # the heredoc -- and nothing else in this file -- keeps every other occurrence # in `check-claims` under the same rule as any other file, which matters because # the comments here quote dead phrases constantly. if f.endswith("check-claims"): a = s.find("REGISTER=$(cat <<'ROWS'") b = s.find("\nROWS", a) if a >= 0 else -1 if a >= 0 and b > a: s = s[:a] + (" " * (b - a)) + s[b:] i = n = 0 low, claim_low = s.lower(), claim.lower() while True: i = low.find(claim_low, i) if i < 0: break if marker.lower() not in low[max(0, i-w):i+w+len(claim)]: print(" unmarked in %s at char %d" % (f, i)) sys.exit(1) n += 1 i += len(claim) # Every suppression, counted. A checker that can discard an occurrence in silence # reports the same clean run whether or not a live assertion is hiding among the # marked ones, and its zero is unfalsifiable. Reached from the loud end here and # from the quiet end by the Decoder on the same day: their marker language was # vouching for 8 of 8 mentions, so their 0 was going to be 0 either way. print(n) sys.exit(0) PY ) && marked=$((marked + out)) || { printf '%s\n' "$out"; bad=$((bad+1)); } # 🔴 CASE-INSENSITIVE since 2026-08-30, and the reason is a live miss. The # register held "no loop-point field has been identified" [refuted]; `BLOCKED.md` # it capitalised at the start of a sentence, and the check reported clean while # a refuted claim stood unmarked in the file whose whole job is to say what is # still open. The Decoder found the same class the same day from the other end # -- their register missed a revival that kept the claim and changed the second # clause. A register matching EXACT wording does not protect the documents that # rewrite most, and a capital letter is the cheapest rewrite there is. done < <(grep -ril -- "$claim" docs/port/ crates/ port/ tools/ authored/ 2>/dev/null || true) # 🔴 PEER-OWNED ROOTS ARE SCANNED FROM THE REF, NOT THE TREE. # # `docs/re/`, `docs/game/` and `docs/agents/` are written by the Decoder. My # working copies are 246, 9 and 13 commits behind their heads, so any verdict # this check reached about one of their files would be a verdict about MY # STALE COPY -- and the failure direction is the false positive: flagging a # claim they have already corrected. That is exactly what they did to me by # hand, reading my `BLOCKED.md` 234 commits behind. # # Excluding them would hide the exposure; reporting from the stale copy would # keep it. So the scan reads the newest blob on any ref. It is the only # structural fix either agent has found for this class -- READ THE REF, NOT # THE TREE -- and it is why `contract-check` stayed correct while this tree sat # 115 commits behind. # # âš ī¸ Measured before building: 33 files match a registered claim today and # ZERO are in a peer-owned root. The exposure is latent, not active. Recorded # because "I checked and it was clean" and "I never looked" must not read the # same, which is this week's whole lesson. _peer_ref=$(git log --all -n 1 --format=%h -- docs/re docs/game docs/agents) # 🔴 THE PEER SCAN GETS A KNOWN POSITIVE, because a zero from a broken reader # looks identical to a real one. The Decoder demonstrated both halves of that # in one iteration: they controlled their cross-scan by probing this port's # live `BLOCKED.md` for a string they knew was in it -- and separately produced # a FALSE ZERO from a reader they had invented minutes earlier, regexing quoted # strings out of `check-claims` into 63 phantom phrases that matched nothing. # # This scan found six hits today, so it is demonstrably live NOW. The control # is for the run where their pages no longer contain any of these phrases and # a zero would otherwise be unfalsifiable: a wrong ref, a wrong pathspec or a # renamed directory all produce the same clean line. if [ -n "$_peer_ref" ] && [ "$_peer_probe_done" != "1" ]; then _peer_probe_done=1 _seen=$(git ls-tree -r --name-only "$_peer_ref" -- docs/re docs/game docs/agents 2>/dev/null | wc -l) if [ "$_seen" -lt 10 ]; then echo "🔴 the peer scan can see only $_seen file(s) at $_peer_ref -- a wrong" >&2 echo " ref or pathspec reads the same as a clean corpus. Exit 2." >&2 exit 2 fi printf ' peer scan reads %s file(s) at %s -- the reader is live\n' "$_seen" "$_peer_ref" fi if [ -n "$_peer_ref" ]; then while IFS= read -r loc; do [ -z "$loc" ] && continue # 🔴 REPORTED, NOT COUNTED AS A FAILURE -- corrected before shipping. # # The first version put these in `bad`, which failed the run. That applies # MY marking convention to THEIR corpus: `[refuted]` is a token this port # uses in its own files, and their pages mark corrections their own way. # Of the six hits, three are in their `METHOD.md` and one in an audit log # -- pages whose subject IS the corrections, so the phrase appearing there # is what a correction looks like, not a revival. # # So this is a prompt to look, never a verdict -- the same conclusion the # withdrawal hook reached about its own candidates. A checker that fails # on another agent's file for not using this one's punctuation would be # noise inside a day, and I would have been the one to file it. printf ' â„šī¸ a peer-owned file at their head contains it: %s (%s)\n' \ "${loc#*:}" "$_peer_ref" peer_hits=$((peer_hits+1)) done < <(git grep -ril -- "$claim" "$_peer_ref" -- docs/re docs/game docs/agents 2>/dev/null || true) fi scanned=$((scanned + hits)) if [ "$bad" -eq 0 ]; then printf ' %-42s %d file(s), %d occurrence(s) suppressed\n' "$claim" "$hits" "$marked" [ -n "$proposition" ] && [ "$proposition" != "$claim" ] \ && printf ' it asserted: %s\n' "$proposition" total_marked=$((total_marked + marked)) else printf ' %-42s 🔴 %d file(s) assert it unmarked\n' "$claim" "$bad"; fail=1 fi done <<< "$REGISTER" # 🔴 LIVENESS. A register full of claims and a tree with nothing in it reports # clean: the grep matches no files, every row scores 0, and the run passes having # READ NOTHING. Wrong directory, renamed docs, a bad checkout -- all produce a # green line. The Decoder's rule for the family: a control that only compares two # things cannot tell you the comparison is happening. if [ "$scanned" -eq 0 ]; then echo "🔴 no file anywhere contains any registered claim -- this check READ" >&2 echo " NOTHING. Exit 2: the harness is broken, not the corpus." >&2 exit 2 fi echo if [ "$peer_hits" -gt 0 ]; then printf ' %d occurrence(s) sit in PEER-OWNED files, read at their branch head\n' "$peer_hits" echo " rather than from this stale tree. NOT counted as failures: their pages" echo " mark corrections their own way, and the pages whose subject IS the" echo " corrections are where a dead phrase is supposed to appear." echo echo " 🔴 AND A PEER HIT IS UNADJUDICABLE FROM THE PHRASE ALONE. This register" echo " indexes PHRASES, not PROPOSITIONS. Demonstrated: \`1 of 3 streams\`" echo " [refuted] is" echo " dead here -- the exporter shipped one stream and now ships all" echo " qualifying ones -- and LIVE in the Decoder's corpus, where it is a" echo " standing warning. Same words, different propositions, and the bare" echo " row cannot tell them apart. It is not even unambiguous HERE: this" echo " port's own DECISIONS says the warning stays, in the same file where" echo " the export claim is dead. The marker separates them locally because" echo " the context is mine. Nothing separates them across corpora." echo fi printf ' %d occurrence(s) were SUPPRESSED by a neighbouring `%s`.\n' "$total_marked" "$MARKER" echo " That number is the size of what this check chose not to look at. A" echo " detector that can discard a candidate without saying how many has an" echo " unfalsifiable clean run -- its zero reads the same whether or not a live" echo " assertion is hiding among the marked ones." echo [ $fail -eq 0 ] && echo "every refuted claim appears only inside its correction" \ || echo "🔴 a refuted claim is still being asserted" exit $fail