fix(pm): split check-widening-tells' file count and let its CLI be told the board - #17278
Merged
Merged
Conversation
…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
This was referenced Sep 10, 2026
os-bill
marked this pull request as ready for review
September 10, 2026 02:43
os-bill
deleted the
claude/issue-17112-widening-tells-coverage-honesty
branch
September 10, 2026 03:07
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 landtogether because #17112's remedy applied alone would have mislabelled #17217's population.
Premise re-verification first — both cards measured on current
origin/mainBoth were filed before
0e45ee8cf(#17216) landed; #17112 was measured onf87fdf359. Re-measuredon
origin/main0780e88481(0e45ee8cfconfirmed an ancestor, exit 0; controlc3ead5524alsoexit 0). Every leg still holds — nothing about either card is stale.
0780e88481packages/spec/**surfaceCovers(ALL, 'packages/services/service-analytics/src/index.ts')1 changed file(s) read, no widening tell…EXIT 0✗ T4 … EXIT=4✗ T4 …:143EXIT 4grep -c -- '--repo'grep -c -- '--declaration'(control: the grep speaks)PM_SWEEP_REPO/GITHUB_REPOSITORYhitsmain()'s only judge callwideningRefusal({ declaration, files })reposet to objectuireposetrepodefaulted (what the CLI does)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 elementREGISTRATION_ROWactually matches. Thatwas 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
After
The count is split, never deleted —
judgedis the only number exit 0 is evidence about, and everyother 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 globcovers it, the file kind declares no contract),
other-repo,unmatched. The listing is capped at tenper 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:
and the same diff on the default board no longer reads as a confident clean:
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:
resolveSweepRepois imported fromcheck-half-states.mjs—PM_SWEEP_REPO, elseGITHUB_REPOSITORY, else this repo. The precedence is the one thing that could drift into a secondconvention, so it is not retyped.
THIS_REPOis nowDEFAULT_SWEEP_REPO(byte-identical value,equality pinned in
--self-test).--repoflag.check-clause2-carriers.mjsdeliberately refuses a positional board andpoints 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.
--repois refused withPM_SWEEP_REPOnamed, so aseat reaching for it is answered rather than ignored. A malformed board is refused too, never
silently replaced by the default.
THIS_REPO;check-clause2-carrierspasses its ownrepoand is untouched. No existing caller changes meaning.⛔ What this deliberately does NOT do
row is still inert for a run whose board is this repo.
its absence is not one either — false negatives are the cost the [Decision] Clause-② — is it directional? Two seats read the same sentence oppositely, and the enqueue gate hangs on the answer #16349 ruling accepted" — is still
printed on every clean verdict, and
--self-testpins that it is.pass is a new refusal class on the enqueue path — [Decision] Clause-② — is it directional? Two seats read the same sentence oppositely, and the enqueue gate hangs on the answer #16349's chain to rule on, and both filings put it
outside themselves. [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 measured the enqueue gate itself as sound (
pairWidening(pair, repo)threads the board correctly); that path is untouched.
Verification
--self-test: 218 cases pass (173 before; +45 in two new batteries, floors pinned at 23 and 22, theroster 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 exitcode), and every leg restored with
git checkout HEAD -- PATHthen verified bygit diff HEADemptyAND
git hash-objectequal to the HEAD blob949e94fd— ⛔ never by an exit code. Each leg carried atrap … EXIT INT TERMwith absolute paths.--self-testN changed file(s) readsentence backrepo: board.repofrom the judge callresolveSweepRepo(env)→resolveSweepRepo({})inmain()Leg C exists because leg B alone would not have proved that
mainthreads its environment — and a casethat 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." Pluspnpm check:pm-clause2-carriers(theimporting 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.mdwas checked and is not edited: it namesthis 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), sonothing 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-configover the whole tree from oneeslint.config.mjs(CI's run, not this PR'sdebt). Count:
--format jsonreports 1 file linted, 0 errors, 0 warnings. Invariance: that confignever enables type-aware linting for any file — its own header says so, and
grep -cE 'project\s*:'returns 0 against a control of 8
parserOptionshits — so this diff cannot move the verdict onany file it does not touch.
turbo ls --affectedis no evidence here in either direction: the changesits in the private repo-root package, which is not in the turbo graph at all.
No package
testortypecheckis owed: the diff touches no package source, only a private root-packagescript, and
git grepfinds no*.test.tsnaming this file.Changeset — derived, not inherited
skip-changeset. Measured over all 82package.jsonfiles in the tree: 12 private, 70 published,all 70 declaring
files[], and zerofiles[]entry mentioningscripts— against a positivecontrol of 70/70 mentioning
dist, so the scan speaks. The changed file lives in the repo-rootpackage, 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/maincopy and by this branch's:So my own
Clause-②measurement agrees with the declaredno— but on the grounds the claimcomment actually gives (
scripts/pm/**is on no declared surface; it sits in no published package'sfiles[]; the gate judges more and claims less), and ⛔ not on that exit 0, which this very PRshows 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:
refusedandincompletepaths. Only the boardprovenance line was added there; the file listing was kept to the clean path, where the count-reads-as-
coverage failure actually lives. Carrier: this file's next author — no PR or person is otherwise
waiting on it.
pass. That is a new refusal class on the enqueue path, i.e. a ruling on [Decision] Clause-② — is it directional? Two seats read the same sentence oppositely, and the enqueue gate hangs on the answer #16349's chain, and the triage
seat marked it ⛔ 非裁定. Left to that chain's owner; the loud NOT-MEASURED line is the non-ruling half
of it. Carrier: whoever owns [Decision] Clause-② — is it directional? Two seats read the same sentence oppositely, and the enqueue gate hangs on the answer #16349's chain.
Generated by Claude Code