port: audit every kind label, and seven rested on a neighbour's argument

tools/port/audit-kinds reports what each  in authored/ rests on. Nothing
had ever checked them, which is the point -- the disciplines that fail this way
are the ones that never visibly failed.

Seven of fifteen labels, every goto_name_kind, had no  of their own. Four
scored ok on the first run because the audit fell back to the parent's ,
which argues the DESTINATION while the label is about where the NAME came from.
That is the same error I was corrected for the previous iteration, one level
down: crediting a claim with evidence that does not bear on it. Borrowed evidence
is now its own outcome, and all seven carry a why citing HANDOFF Q4's own words
and stating that the port never branches on the field.

The audit refuted itself twice first. It counted only paths, shas and filenames
as citations, so HANDOFF Q1 and PORT-MISSION section 7 read as citing nothing --
four false positives, and an audit that invents defects is worse than none
because its false positives are indistinguishable from its true ones until each
is opened. It also resolved paths against committed refs only, failing on a
citation to the tool being written. Both fixed. It still cannot read a cited page
to confirm it says what the why claims, and prints that every run.

MEASURED and measured both existed; a consumer comparing == measured misses the
other, and a label that fails to match reads as ABSENT rather than wrong.
Normalised.

Refutation attempt on HANDOFF Q2's map of GP_TITLE. The headline survives and is
exactly right: 4 UI states + 2 loading variants + 2 boot splashes = 8 states
shipped twice = the 16 entries the archive holds, confirmed against my export's
entry map. But the row enumerates six of those eight -- entries 10, 11, 13 and 14,
publisher_logo and developer_logos, appear nowhere in it. A reader counting Q2
gets twelve, and this is the row already corrected once for an ordinal-versus-
entry error, which is the mistake four unlisted entries feed. The port is
unaffected; both splashes are exported, named and verified at RMSE 2.17 and 3.05.

Every asserting check passes, audit-kinds included.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N7FiFFFwbvG2uxdcEh8HyF
This commit is contained in:
Sylpheed port agent
2026-08-30 21:51:51 +00:00
parent f1e249a606
commit 7c2a47f8be
5 changed files with 370 additions and 2 deletions

173
tools/port/audit-kinds Executable file
View File

@@ -0,0 +1,173 @@
#!/usr/bin/env python3
"""What does each `kind` label in `authored/` actually REST on?
Every authored entry carries a `kind` -- `measured`, `authored`, `name match,
not measured` -- and a `why`. The label is the load-bearing part: `measured`
means the port is repeating something observed off the running game, and a
reader downstream will treat it as fact.
Nothing has ever checked them. That is the point: **a discipline that has never
visibly failed is the one nothing directs attention at.** The Decoder reached
this from the input side -- Ⓐ and Ⓑ were delivery-confirmed because they had
once broken, so the d-pad never was -- and on the same day a `measured` label of
mine turned out to rest on a single entry that may have been measuring history.
So this checks what is checkable about a label, and is explicit that the rest is
not:
citations resolvable references in the `why` -- a `docs/` path that exists on
some ref, a commit sha that resolves, a capture filename
BARE a label whose `why` cites nothing a reader could go and open
DANGLING a citation that does not resolve anywhere in the repository
🔴 What it CANNOT do is read the cited page and confirm it says what the `why`
claims. A label with three resolvable citations can still be wrong. This narrows
"which labels rest on nothing" from unknown to a list; it does not audit meaning.
"""
import json, glob, os, re, subprocess, sys
REFS = None
def known_paths():
"""Every path in the repo, across ALL refs -- docs/re/ lives on a branch.
Checked against the working tree as well: a file added this iteration is not
in any ref yet, and reporting a citation to it as unresolvable would make the
audit fail every time it is itself referenced.
"""
global REFS
if REFS is None:
out = subprocess.run(["git", "rev-list", "--all", "--objects"],
capture_output=True, text=True).stdout
REFS = {l.split(" ", 1)[1] for l in out.splitlines() if " " in l}
return REFS
HANDOFF_TEXT = None
def handoff():
"""The live HANDOFF, so a cited Q number is checked against the real table."""
global HANDOFF_TEXT
if HANDOFF_TEXT is None:
sha = subprocess.run(["git", "log", "--all", "--format=%h", "--",
"docs/port/HANDOFF.md"], capture_output=True,
text=True).stdout.split()[0]
HANDOFF_TEXT = subprocess.run(["git", "show", f"{sha}:docs/port/HANDOFF.md"],
capture_output=True, text=True).stdout
return HANDOFF_TEXT
def sha_ok(s):
r = subprocess.run(["git", "cat-file", "-e", s + "^{commit}"], capture_output=True)
return r.returncode == 0
def text_of(why):
if isinstance(why, str):
return why
if isinstance(why, list):
return " ".join(str(x) for x in why)
return ""
def citations(t):
"""References a reader could actually follow."""
out = []
for p in re.findall(r"\b(?:docs|crates|port|tools|authored)/[\w./-]+\w", t):
out.append(("path", p.rstrip(".,")))
for s in re.findall(r"\b([0-9a-f]{7,40})\b", t):
out.append(("sha", s))
for p in re.findall(r"\b([\w-]+\.(?:png|txt|tsv|wav))\b", t):
out.append(("file", p))
# The corpus cites two things that are not paths and are still followable:
# a HANDOFF question number, and a MISSION section. Leaving these out made
# the first run report four labels as resting on nothing when they rest on
# the two documents the mission names -- an audit inventing defects is worse
# than no audit, because its false positives are indistinguishable from its
# true ones until each is opened.
for q in re.findall(r"HANDOFF Q(\d+)", t):
out.append(("handoff", "Q" + q))
for m in re.findall(r"(PORT-MISSION|MISSION)[ ]section[ ](\d+)", t):
out.append(("mission", m[1]))
for r in re.findall(r"MODDING rule (\d+)", t):
out.append(("modding", r))
return out
def walk(o, f, path, out):
if isinstance(o, dict):
for k, v in o.items():
if (k == "kind" or k.endswith("_kind")) and isinstance(v, str):
stem = "" if k == "kind" else k[: -len("_kind")]
own = o.get((stem + "_why") if stem else "why")
# 🔴 An earlier version fell back to the parent's `why` when a
# label had none of its own, and reported the result as `ok`.
# That credits a label with evidence for a DIFFERENT claim:
# every `goto_name_kind` scored on a sibling `why` about the
# DESTINATION, while the label is about where the NAME came
# from. Borrowed evidence is now its own outcome, because a
# label resting on a neighbour's argument is exactly the case
# this audit exists to surface.
out.append((f, path + "/" + k, v, text_of(own),
own is None and bool(text_of(o.get("why")))))
walk(v, f, path + "/" + k, out)
elif isinstance(o, list):
for x in o:
walk(x, f, path, out)
def main():
rows = []
for f in sorted(glob.glob("authored/*.json")):
walk(json.load(open(f)), f, "", rows)
paths = known_paths()
bare = dangling = 0
kinds = {}
print(f" {len(rows)} kind label(s) in authored/\n")
for f, where, kind, why, borrowed in rows:
kinds.setdefault(kind, 0)
kinds[kind] += 1
cites = citations(why)
bad = []
for typ, c in cites:
if typ == "handoff":
if not re.search(rf"\|\s*{c}\s*\|", handoff()):
bad.append(f"HANDOFF {c} (no such row)")
elif typ == "path" and c not in paths and not os.path.exists(c):
bad.append(c)
elif typ == "sha" and not sha_ok(c):
bad.append(c)
mark = "ok "
if not cites and borrowed:
mark, bare = "🔴 BORROW", bare + 1
elif not cites:
mark, bare = "🔴 BARE", bare + 1
elif bad:
mark, dangling = "🔴 DANGL", dangling + 1
print(f" {mark} {kind:<24} {f.split('/')[-1]}{where}")
if not cites and borrowed:
print(" no `why` of its own; a sibling `why` argues a"
" DIFFERENT claim")
elif not cites:
print(f" cites nothing openable -- {len(why)} chars of prose")
elif bad:
print(f" unresolvable: {', '.join(sorted(set(bad))[:4])}")
else:
print(f" {len(cites)} citation(s), all resolve")
print()
# Casing is checked because a consumer comparing == "measured" silently
# misses "MEASURED", and a label that fails to match reads as absent.
variants = [k for k in kinds if k.lower() == "measured"]
if len(variants) > 1:
print(f" ⚠️ {len(variants)} spellings of the same label: {variants}")
print(" A consumer comparing == 'measured' misses the others, and a")
print(" label that fails to match reads as ABSENT, not as wrong.\n")
print(f" {bare} bare or borrowed, {dangling} dangling, {len(rows) - bare - dangling} with resolving citations")
print(" 🔴 A resolving citation is not a verified label. Nothing here reads")
print(" the cited page to confirm it says what the `why` claims.")
return 1 if (bare or dangling) else 0
sys.exit(main())

View File

@@ -45,6 +45,10 @@ step format-validator must-pass "$BIN" check
step contract-values must-pass tools/port/contract-check
step contract-control must-pass tools/port/contract-check --control
step modding-rules must-pass tools/port/check-modding
# Every `kind` in authored/ is a claim about where a value came from, and until
# 2026-08-30 nothing checked what any of them rested on -- seven were resting on
# a sibling `why` that argued a different claim.
step authored-kinds must-pass tools/port/audit-kinds
step capture-controls must-pass tools/port/check-capture-controls
step menu-audio must-pass env OUT="$OUT/audio" tools/port/verify-menu-audio
# A stale index is worse than none: it answers "is this already decided?" with a