Skip to content

[finding] check:published-readme-exports prints its NOT read blind spot only as whole-repo scalars — a per-document hand read must re-derive the population outside the gate #10815

Description

@claude

Found while executing #10368, which commissioned a hand read of ONE document's share of check:published-readme-exports' NOT read: population. Filed unassigned, no pm:queue.

The observation

The gate prints the blind spot as two whole-repo scalars, and nothing else:

NOT read: 120 documented `X.y(…)` call(s) on 72 receiver(s) with no type this gate can reach
(free variables, parameters, globals, non-workspace imports). Visibility, not a verdict — see #9870.

#9870 added those two numbers so the green line could not read as coverage of documents. They do that. What they cannot do is answer the question the ruling on #9870's open question 1 then asked of them: which document holds how many, and which sites are they? That is the input to every per-document hand read, including the one #10368 commissioned.

There is no flag, no --json, no per-document breakdown. countUnreadCalls(markdown, readableNames) is exported and returns { calls, receivers } — counts, not the site list — and readableNames is the thing a caller cannot get: analyzeDocument builds its readable map internally (import-bound names, plus #9870's extractLocalBindings derivations) and returns only findings.

What that cost, concretely

To adjudicate the sites in #10368 I had to re-implement analyzeDocument's readable derivation outside the gate — the import-binding walk, splitSpecifier/resolveTypesEntry, then extractLocalBindings filtered to sources that are import-bound — and then re-implement countUnreadCalls' body to return the pairs instead of their cardinality.

That is precisely the failure mode this file's own header refuses elsewhere:

"Published" is private unset AND a non-empty files array AND the file matched by one of its patterns […] That definition is load-bearing for more than one gate now, and two gates deriving it separately would disagree the first time a package's files array changed — silently, each still green. So it is computed HERE and imported, never re-derived.

A hand read whose population silently disagrees with the gate's produces a defect count with the wrong denominator, and nothing anywhere goes red. The only evidence available that my re-derivation was the gate's population is that summing it over all 60 published documents reproduced the printed pair exactly (120 / 72) — a whole-run checksum that catches a systematic drift and would not catch one document's worth.

The population that motivates it, measured

Per-document, derived as above and checksummed against the printed totals (repo at 112a8c6, before #10368's repairs):

 30 call(s) / 17 receiver(s)  packages/runtime/README.md
 10 call(s) /  3 receiver(s)  packages/metadata/README.md
  9 call(s) /  2 receiver(s)  packages/drivers/driver-mongodb/README.md
  8 call(s) /  7 receiver(s)  packages/client-react/README.md
  7 call(s) /  4 receiver(s)  packages/plugins/plugin-auth/README.md
  … 27 more documents, all ≤ 5

⚠️ Note for whoever reads #10368's ruling: it states the runtime README holds 47 sites on 18 receivers. The gate's own population says 30 on 17, and no counting convention I could find in the file reproduces 47/18 (import-bound-only, i.e. pre-#10365: 35/20; raw occurrences with no dedup: 44; whole-file rather than fenced: identical). The document has not been edited since #10226, well before the ruling was written. 47 is, however, exactly the derivedReceivers figure printed one line above on the same green output (47 name(s) built from one) — a whole-repo quantity. A per-document breakdown the gate itself emits is what makes that class of transcription slip impossible.

Scope

Observation. ⛔ Distinct from the three cards already living in this file, and none of them is this:

If it is taken up, the cheap shape is an opt-in reporting flag (--unread-report) that prints what the run already computed per document, changing no verdict and no exit code — the same "visibility, not a verdict" register NOT read: already occupies. ⛔ It must not become a widening of what the gate types: that is #9870's option D, explicitly declined pending a census.

Refs: #9870 / PR #10365 (the widening and the NOT read pair) · #10368 (the hand read that needed the breakdown) · #4690 (zero is a broken scan).


Generated by Claude Code

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions