Skip to content

[finding] check:published-readme-exports has a FOURTH no-population state one level below targets — every import resolves, no name binds, both halves check nothing, exit 0 #10417

Description

@os-zhuang

Observation only — no gate is red. Found while implementing #9911 (which adds the refusal for targets.size === 0). This is a different stage of the same axis, one level deeper, and #9911's refusal correctly does not cover it — so it is recorded here rather than folded in.

The axis, after #9911

#9911 makes the population axis three staged refusals:

published documents → import statements → workspace type entries

targets.size === 0 is now refused. But targets.size >= 1 only says a type entry was reached — it does not say a name was bound. The two halves consume bindings, not entries, so there is a fourth state below the third:

every import resolves to a workspace member, no import binds a name, so symbolChecks === 0 and callChecks === 0 — both halves check nothing, and the run exits 0.

Measured

Fixture: one published package, one published document, one import that resolves to a real workspace member with a built type entry, binding no names.

importtype{}from'@fixture/alpha';widget.render();widget.explode();

Run against the gate with #9911's refusal already in place:

EXIT=0
✓ check:published-readme-exports — 1 published document(s) across 1 workspace package(s); 1 import statement(s), 1 workspace type entr(ies).
Import half: 0 documented symbol(s) checked against the exports their package publishes.
Call-site half: 0 documented `X.y(…)` call(s) checked, on 0 import-bound name(s) and 0 name(s) built from one.
NOT read: 2 documented `X.y(…)` call(s) on 1 receiver(s) with no type this gate can reach

1 workspace type entr(ies) — a real population by the stage-3 test — with both halves at zero. Stage 3 is behaving correctly here: there genuinely is a resolved target. The vacuity has simply moved one level down, from entries reached to names bound.

Why it matters, and why it is filed rather than fixed

Same argument as #9911 and #4690: a green over a population of nothing is worthless, and this is that shape with one more step. The plausible causes are the ones a gate should catch loudly — parseImportClause losing a clause shape, or a change to extractImports' statement matcher that keeps finding statements while dropping their bindings. Note that importStatements and targets both stay non-zero through such a regression, so neither existing refusal sees it.

⚠️It is not obviously safe to refuse, which is exactly why this is an observation and not a build:

  • The honest condition is a whole-run one (measured.symbolChecks === 0 && measured.callChecks === 0), and unlike the three stages above it, it can only be evaluated afteranalyzeDocument has run over every document — so it does not slot into the staged populationRefusal the way the first three do.
  • A tree whose published READMEs legitimately document only side-effect or type-only imports would newly go red, and this gate is merge-blocking with a baseline its own file refuses as an author remedy. On the real tree today there is enormous headroom (313 documented symbol(s) checked), but the headroom is not the argument — the false-red cost is.
  • The NOT read pair is not usable as the test: it is the complement of what was checked, so it goes up in a vacuous run, not to zero (measured in finding: check:published-readme-exports greens when documents and imports exist but NOTHING resolves to a workspace member — the one no-population shape it does not refuse #9911: NOT read: 3 against 0 … checked).

So it wants a judgement, not an automatic build — same reasoning that kept #9911 out of #9767.

Related: #9911 (stage 3, the refusal this sits below), #10367 (a third distinct defect in the same file), #4690 (the class), #10057 and #9089 (the same vacuous-pass family elsewhere).

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