Nothing gates a factual claim in prose: 6 of 8 findings on a docs PR were unmeasured assertions nf-agt5 ← Beads

open priority 2 task unassigned

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

Filed unclaimed and unlabelled from ninefold-a at the close of design-001 pieces 6–11. Backlog, for a future triage round.

Sibling to #481 and deliberately separate. #481 is about replies to the reviewer — what we say we did. This is about the durable text itself: CLAUDE.md, design docs, and code comments, which are read long after the reply is forgotten and are the only thing a cold-start session has.

The gap

presubmit.py gates three lanes — dotnet, python, shellcheck — and every one of them gates code. Nothing anywhere checks a factual claim in prose. A sentence asserting something false about the repo compiles, passes, merges, and then becomes what the next session believes.

Measured on one PR (#532, a *docs* PR), across five reviewer rounds:

| finding | the claim | reality | |---|---|---| | F1 | "trivial launchers … carry set -Eeuo pipefail and an ERR trap" | zero of three did | | F2 | "mergeable in any order" | true of conflicts, false of content | | F6 | "Docs only — no code, no probes, no behaviour" | three shell scripts and a behaviour change | | F7 | launcher line counts (8) (16) (34) | 9 / 25 / 35 — *the same PR's later commits moved them* | | F9 | "§4:365 already contains the counter-argument" | head 365 is an unrelated paragraph; the amendment shifted the body +68 lines |

Six of the eight findings on that PR were prose asserting something unmeasured. The code in it was fine throughout.

It is not isolated to one PR. Two more from the same chunk, both retracted in place:

Why it is worse than the equivalent code defect
  1. It propagates by being believed. F1 is the sharp case: a forward-looking false guarantee does not merely mislead, it suppresses the work. The next session that wonders whether the launchers are hardened reads CLAUDE.md, sees the guarantee, and stops looking. The claim causes its own permanence.
  2. The reviewer is currently the only detector, and it is advisory. Every one of the eight was caught by ninefold-reviewer, none by a gate and none by me. A PR merged without a review round keeps all of them.
  3. CLAUDE.md is load-bearing for cold starts. Its own "Regenerating this from a cold start" section says a new session should be able to read it and pick up the same momentum. Everything false in it is inherited.
Shape of a fix

Ordered by cost. None is obviously right, which is why this is filed rather than built.

The through-line, for whoever triages this

I wrote all eight. The common factor is not carelessness about facts — it is that I write the summary from what I intended and the code from what I checked. The summary is then the artefact with the longest half-life and the least verification. That asymmetry is the thing worth fixing, and it is structural rather than personal: any author writing prose about their own change has already decided what it says.

Same shape as #389 — the UI gate existed, nothing ran it, and main rotted unnoticed. Here the standard exists (CLAUDE.md is held to "real industry standards" by its own first paragraph); nothing checks it.

Related: #481 (reply claims), #450 (nothing verifies the verifier), #484 (prose-to-code ratio), #539 (diff before pushing — the code-side sibling).

Dependencies

None.

Comments

No comments.

Add a comment