port: my 12-unit bracket is withdrawn, and 41 % of my own doc citations did not resolve

Two things, and the first is a refutation of mine that lands.

1. THE 12-UNIT BRACKET IS WITHDRAWN. It excludes nothing.

I kept 60 units/s on the ground that "12 declared units measured at 0.14-0.30 s
gives 40-86 units/s, so 120 is excluded". The Decoder refuted it and I checked
the arithmetic myself:

  120 units/s predicts 12 units in 0.100 s -- BELOW the sampler's own 0.125 s
  resolution, which the source doc states in its own words ("at a sampling
  resolution that cannot do better"). A 0.125 s sampler reports such an interval
  as about one sample, ~0.125-0.14 s. So the 0.14 s low end is the INSTRUMENT'S
  FLOOR, and 12/0.14 = 85.7 is an upper bound produced by dividing by a floored
  duration. It is the value 120 predicts once the sampler is accounted for.

🔴 And the deeper error is mine rather than the arithmetic. I argued the leg
survived because it "never touched a frame count". True, and INSUFFICIENT: every
wall-clock duration off Canary is true/speed_factor, so apparent units/s = true x
speed, and the speed factor is precisely what makes the three routes disagree. I
checked the leg for the WRONG CONTAMINANT. Frame-free is not clock-free, and on
this emulator clock-free is the property that matters.

What survives is the half I did not lead with: the declared 12 units are
independently confirmed as SIX FRAMES by screen-transitions.md's 255/6-per-frame
ramp, with no wall clock in it. That is evidence about units per FRAME -- never in
dispute -- and silent about units per second.

So 60 has NO surviving bracket. It stays because nothing supports 120 either and
moving a shipped timeline on no evidence is worse. That is a default, not a
derivation, and the entry now says so. `kind` is already `authored`.

2. 41 % OF THE REPO PATHS CITED IN MY OWN docs/port/ PROSE DID NOT RESOLVE.

The Decoder observed that everything they hand me links into docs/re/ files that
live only on their branch, so every link they send dangles from here. I turned it
on myself and it was worse than I expected: 37 of 91, in two classes.

  19  on their topic branch -- real files, not merged. Not errors, and no one in
      this container can fix them; the fix is a merge.
   7  resolve NOWHERE: docs/BLOCKED.md, docs/DECISIONS.md, docs/FORMAT.md,
      port/manifest.json, port/screens/title/*.json. Left behind by the monorepo
      move and the export/ rename. Simply wrong -- a reader following one gets
      nothing, and nothing had ever told anyone.

All 7 fixed. audit-kinds checks citations in authored/; nothing checked the
PROSE, which is where this port explains itself.

New: tools/port/check-citations, wired into check-all with its control. It fails
ONLY on the resolve-nowhere class and reports the peer-branch class, because a
check that went red for a state nobody here can change is the shape the display
guard exists to prevent. The --selftest plants a dangling citation and requires it
caught, AND a real one and requires it passed -- both directions, since a scanner
that flagged everything would also "pass" the first.

Not settled: finding 3 has no surviving cause and 60 now has no surviving
derivation either; the ~1.0-1.2 menu residual; pgloading_loop5's residual; the
allowance still waits on its grep trigger.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018AHUQvXGyNcKonSEWsgWcX
This commit is contained in:
Sylpheed port agent
2026-09-01 19:18:30 +00:00
parent 3df042f10f
commit b42ff385ed
7 changed files with 152 additions and 6 deletions

View File

@@ -129,6 +129,14 @@ step input-control must-pass tools/port/verify-input --control
# A stale index is worse than none: it answers "is this already decided?" with a
# confident no. That is not hypothetical -- see the entry it was built after.
step decisions-index must-pass tools/port/index-decisions --check
# `audit-kinds` checks citations in `authored/`; nothing checked the PROSE, and
# prose is where this port explains itself. A first run found 37 of 91
# non-resolving -- 7 of them pointing at NOTHING on any ref, left behind by the
# monorepo move and the `export/` rename. Only that class fails; a citation that
# is merely on a peer's unmerged branch is reported, because the fix is a merge
# and nobody in this container can make it.
step doc-citations must-pass tools/port/check-citations
step citations-control must-pass tools/port/check-citations --selftest
# A refuted claim asserted outside its correction is a lie the corpus tells a
# reader who greps for it. Registered claims must carry an explicit `[refuted]`.
# 🔴 The register check had NO executable control until 2026-08-31 -- every

106
tools/port/check-citations Executable file
View File

@@ -0,0 +1,106 @@
#!/usr/bin/env python3
"""Do the repo paths cited in `docs/port/*.md` actually resolve?
tools/port/check-citations # assert
tools/port/check-citations --selftest # can it fail?
`audit-kinds` checks citations in `authored/`. Nothing checked the PROSE, and
prose is where this port explains itself. A first run found **37 of 91**
non-resolving, 41 %, in two very different classes:
* **19 on the Decoder's topic branch** — real files, not merged here. Not
errors. A reader in this checkout still cannot follow them, which is worth
reporting and not worth failing on; the fix is a merge, not an edit.
* **7 that resolve NOWHERE** — `docs/BLOCKED.md`, `docs/FORMAT.md`,
`port/manifest.json`, `port/screens/title/*.json`. Left behind by the
monorepo move and the `export/` rename. Those are simply wrong: a reader
following one gets nothing, and nothing had ever told anyone.
So the two classes are separated and only the second fails. A check that failed
on the first would be red for a state nobody in this container can fix, which is
the shape the display guard exists to prevent.
⚠️ THE PEER-BRANCH CLASS IS THE OTHER AGENT'S POINT, TURNED ON MYSELF. They
observed that everything they hand over links into `docs/re/` files that live
only on their branch, so every link they send is dangling from here. The same is
true in reverse and neither of us was counting.
"""
import os
import re
import subprocess
import sys
import glob
# A repo path with a file extension, optionally in backticks or a markdown link.
CITE = re.compile(
r"`?((?:docs|crates|port|tools|authored|export)/[\w./-]+"
r"\.(?:md|rs|gd|json|txt|py|tsv|csv))`?"
)
PEER_REFS = ("origin/auto/frame-blend-draw-path", "origin/main")
def on_a_ref(path: str) -> str | None:
"""The first ref that carries `path`, or None."""
for ref in PEER_REFS:
if subprocess.run(["git", "cat-file", "-e", f"{ref}:{path}"],
capture_output=True).returncode == 0:
return ref
return None
def scan(files):
resolves, peer, nowhere = 0, {}, {}
for p in files:
try:
text = open(p, encoding="utf-8").read()
except OSError:
continue
for m in sorted(set(CITE.findall(text))):
if os.path.exists(m):
resolves += 1
elif (ref := on_a_ref(m)):
peer.setdefault(m, (p, ref))
else:
nowhere.setdefault(m, p)
return resolves, peer, nowhere
def main() -> int:
if "--selftest" in sys.argv:
# 🔴 A CHECK THAT CANNOT FAIL IS NOT A CHECK. This plants a citation of a
# path that exists on no ref and requires the scanner to catch it, and a
# citation of a real file and requires it NOT to. Both directions,
# because a scanner that flagged everything would also "pass" the first.
tmp = os.path.join(os.environ.get("TMPDIR", "/tmp"), "check-citations-selftest")
os.makedirs(tmp, exist_ok=True)
bad = os.path.join(tmp, "bad.md")
open(bad, "w").write("see `docs/port/this-file-does-not-exist-anywhere.md`\n")
good = os.path.join(tmp, "good.md")
open(good, "w").write("see `docs/port/PORT-MISSION.md`\n")
_, _, nb = scan([bad])
r, _, ng = scan([good])
ok = len(nb) == 1 and len(ng) == 0 and r == 1
print("selftest: planted dangling caught=%s, real citation passed=%s -> %s"
% (len(nb) == 1, len(ng) == 0 and r == 1, "ok" if ok else "🔴 BROKEN"))
return 0 if ok else 2
files = sorted(glob.glob("docs/port/*.md"))
resolves, peer, nowhere = scan(files)
total = resolves + len(peer) + len(nowhere)
print("citations of repo paths in docs/port/*.md: %d" % total)
print(" resolve here : %d" % resolves)
print(" on a peer branch, not merged: %d (reported, not failed)" % len(peer))
for m, (src, ref) in sorted(peer.items()):
print(" %-52s %s <- %s" % (m, ref.split("/")[-1], os.path.basename(src)))
if nowhere:
print(" 🔴 resolve NOWHERE : %d" % len(nowhere))
for m, src in sorted(nowhere.items()):
print(" %-52s <- %s" % (m, os.path.basename(src)))
print("\n🔴 a reader following those gets nothing. Fix the path or drop the citation.")
return 1
print(" 🔴 resolve nowhere : 0")
return 0
if __name__ == "__main__":
raise SystemExit(main())