port: build the withdrawal-time hook, and violate the rule it enforces while writing it

They ended with 'it needs a hook at withdrawal time, not a sweep'. Expressible,
because a correction here has a shape: a heading carrying WITHDRAWN / CORRECTION /
refuted. A correction section containing no registered phrase is a death argued
and never indexed. check-claims now reports them, and the first run names more
than my 'four of eight' -- the shortfall runs back through earlier work.

Reported, not asserted, deliberately: not every correction retires a claim, and
forcing rows for those would push rows in to silence the check.

Two failures while building it. The first version pasted the register rows into
its own heredoc, so every registered phrase became an unmarked quotation and
check-claims flagged its own source -- a tool violating the rule it enforces by
being written. Fixed by passing the register through the environment.

And writing up the previous catch re-introduced three unmarked quotations:
describing a refuted claim quotes it, so every correction is a new occurrence
needing the token. The cost is recursive, which the header implies but does not
say out loud.

What the hook does not do: it fires when a correction is written, so it closes the
gap between arguing and indexing, not between believing and arguing. Nothing here
would have caught me copying their 'structural' claim into my record.

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 19:27:52 +00:00
parent f32d9e8f7d
commit 6ffd9baca9
2 changed files with 76 additions and 2 deletions

View File

@@ -57,6 +57,43 @@ structural limit, not an unrun experiment
ROWS
)
# ─── 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.
echo
echo "withdrawal-time hook -- correction sections that registered nothing:"
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):
if not re.search(r"WITHDRAWN|CORRECTION|refuted|withdraw", head, re.I):
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
[ -z "$claim" ] && continue
hits=0; bad=0