Skip to content

fix(pm): split check-widening-tells' file count and let its CLI be told the board - #17278

Merged
os-bill merged 1 commit into
mainfrom
claude/issue-17112-widening-tells-coverage-honesty
Sep 10, 2026
Merged

fix(pm): split check-widening-tells' file count and let its CLI be told the board#17278
os-bill merged 1 commit into
mainfrom
claude/issue-17112-widening-tells-coverage-honesty

Conversation

@os-bill

@os-bill os-bill commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Fixes #17112
Fixes #17217

Clause-②: no

Both cards are one defect wearing two faces, on one file and one output line
scripts/pm/check-widening-tells.mjs, the sentence it prints when it finds nothing. They land
together because #17112's remedy applied alone would have mislabelled #17217's population.

Premise re-verification first — both cards measured on current origin/main

Both were filed before 0e45ee8cf (#17216) landed; #17112 was measured on f87fdf359. Re-measured
on origin/main 0780e88481 (0e45ee8cf confirmed an ancestor, exit 0; control c3ead5524 also
exit 0). Every leg still holds — nothing about either card is stale.

reading card re-measured on 0780e88481
declared surface rows 7, six inside packages/spec/** 7, same rows, same repos
surfaceCovers(ALL, 'packages/services/service-analytics/src/index.ts') false false
controls: error-code-ledger / dispatcher-vocabulary true / true true / true
the exit-0 line on an unexaminable file 1 changed file(s) read, no widening tell… EXIT 0 reproduced verbatim, EXIT 0
positive control (a row on a declared registry surface) ✗ T4 … EXIT=4 ✗ T4 …:143 EXIT 4
grep -c -- '--repo' 0 0
grep -c -- '--declaration' (control: the grep speaks) 6 6
PM_SWEEP_REPO / GITHUB_REPOSITORY hits 0 / 0 0 / 0
main()'s only judge call wideningRefusal({ declaration, files }) same, line 1153
leg 1 — control diff, repo set to objectui refused refused (T1 …objectql.zod.ts:23)
leg 2 — real (removal-only) diff, repo set clean clean
leg 3 — control diff, repo defaulted (what the CLI does) clean clean

One correction to the record, in this PR's favour and not the cards': my first attempt at #17112's
positive control did not fire, because I shaped the added ledger row as an object literal
({ code: 'X', status: 418 }) rather than the bare element REGISTRATION_ROW actually matches. That
was my fixture, not the tool — with the shape the registry really uses ('WORKFLOW_STEP_FAILED',)
the control fires at exit 4, exactly as filed.

Before / after — the success line

Judged against a diff adding a published type export to packages/services/service-analytics/src/index.ts:

Before

✓ check-widening-tells: 1 changed file(s) read, no widening tell on any declared surface.
  ⚠️ A tell is not a proof and its absence is not one either — …
EXIT=0

After

✓ check-widening-tells: 1 changed file(s) — 0 judged against a declared surface (no widening tell),
  1 NOT MEASURED. ⛔ NOTHING on this diff was examined for widening tells, so this exit 0 is
  evidence about no surface at all.
  board: this run judges objectstack-ai/objectstack (source: default — set PM_SWEEP_REPO to judge another repo).
  ⛔ NOT MEASURED is not a clean reading — no tell could have fired on these files whatever they contain:
    no declared surface covers it (1):
      packages/services/service-analytics/src/index.ts
  ⚠️ A tell is not a proof and its absence is not one either — false negatives are the cost the #16349 ruling accepted.
EXIT=0

The count is split, never deletedjudged is the only number exit 0 is evidence about, and every
other file is named under the reason it could not be examined. Five states, each a different fact:
judged, deleted (a deletion adds nothing — a measurement, not a gap), not-contract-source (a glob
covers it, the file kind declares no contract), other-repo, unmatched. The listing is capped at ten
per bucket and says how many it did not list, so a 300-file diff cannot drown the verdict.

Before / after — the CLI surface

Before: no invocation could reach the declared objectstack-ai/objectui packages/types/src/zod/**
row. After, the board is a resolved input, stated in the verdict:

$ PM_SWEEP_REPO=objectstack-ai/objectui node scripts/pm/check-widening-tells.mjs \
    --declaration no --diff /tmp/objectui-adds-a-key.diff
✗ T1 packages/types/src/zod/objectql.zod.ts:23 — a new key on a Zod object schema — …
check-widening-tells: a widening tell with `Clause-②: no` — … 1 tell(s): …objectql.zod.ts:23
  board: this run judges objectstack-ai/objectui (source: PM_SWEEP_REPO).
EXIT=4

and the same diff on the default board no longer reads as a confident clean:

    a declared surface covers it, but for objectstack-ai/objectui —
    re-run with PM_SWEEP_REPO=objectstack-ai/objectui (1):
      packages/types/src/zod/objectql.zod.ts

That distinction is precisely why the two cards could not land apart: under #17112's remedy alone this
file would have printed under "no declared surface covers it", which is false about it.

Three deliberate choices:

  • resolveSweepRepo is imported from check-half-states.mjsPM_SWEEP_REPO, else
    GITHUB_REPOSITORY, else this repo. The precedence is the one thing that could drift into a second
    convention, so it is not retyped. THIS_REPO is now DEFAULT_SWEEP_REPO (byte-identical value,
    equality pinned in --self-test).
  • ⛔ No --repo flag. check-clause2-carriers.mjs deliberately refuses a positional board and
    points at the variable; two entry points in one directory disagreeing about this would be its own
    trap, which [finding] check-widening-tells' CLI cannot be told the repo, so its declared objectui mirror row is unreachable — every objectui diff reads clean, including one that DOES add a key to packages/types/src/zod/** #17217 names in its own filing. --repo is refused with PM_SWEEP_REPO named, so a
    seat reaching for it is answered rather than ignored. A malformed board is refused too, never
    silently replaced by the default.
  • ⛔ The default is unchanged. Every exported function still defaults to THIS_REPO;
    check-clause2-carriers passes its own repo and is untouched. No existing caller changes meaning.

⛔ What this deliberately does NOT do

Verification

--self-test: 218 cases pass (173 before; +45 in two new batteries, floors pinned at 23 and 22, the
roster floor raised 14 → 16). Sibling check:pm-clause2-carriers: 319 cases pass.

Ablation — three legs, each mutation proven on disk, each restore proven by state. Anchor and
injected occurrence counts were grep -c-ed before and after every mutation (⛔ never an editor's exit
code), and every leg restored with git checkout HEAD -- PATH then verified by git diff HEAD empty
AND git hash-object equal to the HEAD blob 949e94fd
— ⛔ never by an exit code. Each leg carried a
trap … EXIT INT TERM with absolute paths.

leg mutation --self-test assertions that fired
A · #17112 put the conflating N changed file(s) read sentence back EXIT 1 (3 of 218 failed) the word that carried the defect is gone; what WAS judged is stated; that clean reading says the file WAS judged
B · #17217 drop repo: board.repo from the judge call EXIT 1 (3 of 218 failed) THE FINDING: a key added to the objectui mirror is REFUSED through the CLI; …navigable; GITHUB_REPOSITORY is honoured
C · #17217 resolveSweepRepo(env)resolveSweepRepo({}) in main() EXIT 1 (5 of 218 failed) the four above plus a malformed board is refused, never replaced by the default

Leg C exists because leg B alone would not have proved that main threads its environment — and a case
that tested the judge instead of the CLI is exactly the shape that let #17217 sit green through 150
passing self-test cases.

Gates. Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack
(the tool takes the change set from the merge base itself): 32 commands, all EXIT 0, reconciled with
--ran"32 derived, 32 run, 0 NOT-MEASURED, 0 UNRUN." Plus pnpm check:pm-clause2-carriers (the
importing sibling, owed under the tool-script rule and outside the derived families) — EXIT 0.

Governed? node scripts/pm/check-governed-merges.mjs --test scripts/pm/check-widening-tells.mjs
EXIT 0, "NOT governed — ordinary queue landing applies to a PR with exactly this file list."
.claude/skills/pm-dispatch/references/contract-review.md was checked and is not edited: it names
this script as the judge of widening tells but documents no invocation of it (the invocation it
documents is check-clause2-carriers.mjs --pair, unchanged, and the default board is unchanged), so
nothing in it becomes false. Editing it would have made the whole PR governed for no gain.

Lint — a declared narrowing, with its three readings. Population: this repo runs pnpm lint =
eslint . --no-inline-config over the whole tree from one eslint.config.mjs (CI's run, not this PR's
debt). Count: --format json reports 1 file linted, 0 errors, 0 warnings. Invariance: that config
never enables type-aware linting for any file — its own header says so, and grep -cE 'project\s*:'
returns 0 against a control of 8 parserOptions hits — so this diff cannot move the verdict on
any file it does not touch. ⚠️ turbo ls --affected is no evidence here in either direction: the change
sits in the private repo-root package, which is not in the turbo graph at all.

No package test or typecheck is owed: the diff touches no package source, only a private root-package
script, and git grep finds no *.test.ts naming this file.

Changeset — derived, not inherited

skip-changeset. Measured over all 82 package.json files in the tree: 12 private, 70 published,
all 70 declaring files[], and zero files[] entry mentioning scripts — against a positive
control of 70/70 mentioning dist, so the scan speaks. The changed file lives in the repo-root
package, which is private: true. Nothing in this diff is shipped by any released package.

⭐ This PR is its own demonstration

The same diff, judged by the gate's origin/main copy and by this branch's:

old  ✓ check-widening-tells: 1 changed file(s) read, no widening tell on any declared surface.   EXIT=0
new  ✓ check-widening-tells: 1 changed file(s) — 0 judged against a declared surface,
       1 NOT MEASURED. ⛔ NOTHING on this diff was examined for widening tells …               EXIT=0

So my own Clause-② measurement agrees with the declared no — but on the grounds the claim
comment actually gives (scripts/pm/** is on no declared surface; it sits in no published package's
files[]; the gate judges more and claims less), and ⛔ not on that exit 0, which this very PR
shows is NOT MEASURED rather than clean. The old line would have read as corroboration. That is the
finding, printed about itself.

验收备注

Noted while reading, ⛔ not filed and ⛔ not fixed here:


Generated by Claude Code

…ld the board

The success line counted every changed file as "read" and set that count
beside a qualified negative, so exit 0 read as coverage for surfaces the
instrument cannot see: six of the seven declared rows sit in packages/spec,
and a published symbol anywhere else is invisible by construction.

The count is now split — `judged` is the only number exit 0 is evidence
about, and every other file is named under the reason it could not be
examined. The scoping is untouched, the #16349 honesty caveat is still
printed, and no verdict or exit code moves.

The second half is the same output line: main() never passed a repo, so the
declared objectui mirror row was unreachable through the documented CLI and
an objectui diff could only come back clean — including one that really adds
a key to packages/types/src/zod/**. The board is now resolved by
resolveSweepRepo (PM_SWEEP_REPO, else GITHUB_REPOSITORY, else this repo),
imported from the sibling rather than reinvented, stated in the verdict, and
`--repo` is refused with the variable named so two entry points cannot
disagree. Fixing the count alone would have filed the mirror under "no
declared surface covers it", which is false about it — hence one pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH
@os-bill os-bill added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 10, 2026 — with Claude
@os-bill
os-bill marked this pull request as ready for review September 10, 2026 02:43
@os-bill
os-bill added this pull request to the merge queue Sep 10, 2026
Merged via the queue into main with commit 7804f29 Sep 10, 2026
36 checks passed
@os-bill
os-bill deleted the claude/issue-17112-widening-tells-coverage-honesty branch September 10, 2026 03:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/l skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants