Nothing catches a line-number citation into a doc, and it has rotted four times in one PR nf-vae ← Beads

open priority 2 task unassigned

Twinned from https://github.com/cfsh/ninefold/issues/614 by tools/beads/import_github.py's reconcile pass.

Filed unclaimed from nf-dev-history-charter. This is #542's option A applied to one specific class, and it is filed rather than folded in because the fix is a repo-wide policy that would turn other sessions' in-flight branches red — not one PR's call to make.

The class

A citation like ` CHARTER.md:177 ` in live code is a pointer that rots silently on any insertion above it, and nothing in the repo can tell. It is a specimen already on the books:

What made it worth filing now

PR #600 hit this class four rounds running, and the fourth is the instructive one.

Round 2 fixed the three sites the reviewer's verdict named, and the PR body then claimed *"no line-number citation into CHARTER.md survives in live code"* — a completeness claim built from a three-item list. Round 3 found the fourth (tools/nflib/verdict.py:97), which resolved correctly on main and was broken by that PR.

Two things this demonstrates, both cheap to state and expensive to rediscover:

  1. The check that was running could not see it. #600 verified *"every markdown link and heading anchor in the repo resolves"* — structurally incapable of catching a line citation, because a line citation is neither a link nor an anchor. #542's third comment names this shape: the check scoped to what the author had been working in, not to where the claim could live.
  2. Two of the four were already stale on main, and wrong twice over. tools/nflib/verdict.py:16 and tools/tests/test_nflib_verdict.py:87 both cited DESIGN.md:95 for the assertion that it *"still documents result=<PASS|GAPS|GAPS-REPEAT> and has been missing CONVERGED"*. The line had moved and the defect had been fixed — DESIGN.md §4 carries CONVERGED today. Live code asserting a stale defect in the present tense, unnoticed until someone swept for it. All four are fixed in #600.
The sweep, which is one command

``` grep -rnE '[A-Za-z_0-9-]+\.md:[0-9]+' --exclude-dir=.git --exclude-dir=design_docs . ```

Clean as of #600's head. The whole proposal is to keep it that way.

Shape of the fix, for whoever takes it

A tools/tests/ test asserting the sweep returns nothing, in the same spirit as test_nflib_verdict.py's charter contract test — prompt and doc files are source code, so a pointer into them is a reference that should be checked.

Three judgement calls the implementer owns:

Cheaper alternative if a lint feels heavy: a line in CLAUDE.md's doc conventions saying *cite by section name, never by line number*. Weaker — it is the kind of rule #542 exists because prose rules do not gate — but it costs nothing and breaks nobody.

Refs #542, #532, #600

Dependencies

None.

Comments

No comments.

Add a comment