Uh oh!
There was an error while loading. Please reload this page.
test(pm): run the half-state sweeper self-test in CI - #8544
Merged
Conversation
`scripts/pm/check-half-states.mjs` carried a 79-case --self-test that no CI job ran — it executed only when a human or an agent typed it. Since the part-of/closing-keyword guard landed, a PR-scoped BLOCKING check imports the file's H7 predicate, so a break in it now reddens or silently greens every PR in the repo; that guard's own self-test pins only the H7 behaviours it depends on, leaving H1-H6, the seat-sticker parser and the transport classifier with no CI coverage at all. - new `check:pm-half-states` running the self-test only, wired as an unconditional step in lint.yml beside the other pm gates - the live sweep stays out of CI: it is report-only by design (a completed sweep exits 0 on any finding count) and its non-zero exits classify the environment, not the PR - pointed straight at the script, no gate file in between: measured on this tree under the landed module-body masking, it yields exactly one watch hint (the repo slug in its API base), which covers no input path — so the fixture-pollution that forced a separate file for check:pm-dispatch-gates does not apply here Fixes#8528 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018WuTtyckQa1VcXwgd52JpN
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
hotlong
marked this pull request as ready for review
August 13, 2026 18:43
Uh oh!
There was an error while loading. Please reload this page.
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 freeto 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#8528
scripts/pm/check-half-states.mjscarried a 79-case--self-test— the H1 through H7 predicates, the seat-sticker parser, the transport classifier and its measured container classes — that no CI job ran. It executed only when a human or an agent typed it, which makes it a check whose coverage is a function of who remembered. Fourth member of the same family as the dispatch-gates self-test,check:skill-frame-freshnessandcheck:dev-prereqs, and the one with a blocking consumer: since the part-of/closing-keyword guard landed, a PR-scoped blocking check imports this file'sh7PartOfWithClosingKeywordpredicate (andstripMarkdownCodebeneath it), so a break there now reddens — or silently greens — every PR in the repo.What lands
check:pm-half-statesin the rootpackage.json, running the self-test only.lint.yml, beside the other pm gates: noif:, no label read, no paths filter, and thelintjob itself carries none either (verified by parsing the workflow, not by reading the diff).The live sweep stays out of CI deliberately. It reads a shared board over the GitHub API, is report-only by design (a completed sweep exits 0 whether it found 0 or 40 half-states), and its non-zero exits classify the environment — no token, exhausted quota, unreachable host — which is not a verdict about whichever PR happens to run it. The script's own header argues both halves. The self-test is offline: no network, no token, ~0.05s.
The one measured decision: direct entry, no thin gate file
check:pm-dispatch-gatesneeds its own gate file because that tool's self-test fixtures are path strings, which become watch hints and fabricate MATCHED leads across most of the tree. The card asked whether the same applies here rather than copying the answer. Measured on this tree, under the module-body masking that now blanks comments and self-tests before the scan:scripts/pm/dispatch-gates.mjs.github/workflows,packages/plugins,packages/drivers,packages/services)scripts/pm/check-half-states.mjsobjectstack-ai/objectstack)The single hint is the repo slug in the API base (
process.env.PM_SWEEP_REPO ?? …). It is not a repo path, andhintCoverscannot pair it with any repo-relative input. The issue-shaped fixtures and prose specimens all sit inside the masked self-test. So the pollution that forced a separate file next door does not exist here, and the entry is pointed straight at the script — the same shape ascheck:partof-closing-keywordone line down.Verified by derivation rather than by argument, after wiring:
pnpm check:pm-half-states [lint.yml] matched via scripts/pm/check-half-states.mjs;packages/spec,packages/objectql,packages/rest,packages/plugins,.changeset,.claude/agents,.claude/skillsandcontent/docsderive zero half-states leads;Reverse verification
Direction predicted before running: the new gate red, the pre-existing coverage green — because the point of the card is that the pre-existing coverage is bounded to H7.
Ablating
h3QueueAndDispatched(&&to||) from the committed state:Both halves as predicted: the new gate has teeth, and the incidental H7 coverage is blind to H3 — the gap this PR closes is real, not a formality. Restored with
git checkoutfrom the commit; 79/79 green again.Gates
Derived against the actual diff (
node scripts/pm/dispatch-gates.mjs package.json .github/workflows/lint.yml) and run as the union with the dispatch list — all green:check:node-version,check:required-contexts,check:shard-attestation,check:workflow-status-functions,check:nul-bytes,check:filter-alias-parity,check:type-source-resolution,check:changeset-gate-self-tests,check:type-check-coverage,check:type-check-debt(afterturbo run buildover the packages closure, aslint.ymldoes before that step),check:pm-dispatch-gates,check:pm-half-states, pluscheck-changeset-no-major.mjs,check-empty-changeset.mjs,check-shard-attestation.mjs. The re-derivation surfaced no family the dispatch list had missed.No changeset: workflow plus a root-private script entry releases nothing, matching the dispatch-gates wiring PR that shipped the identical surface.
skip-changesetapplied. Thepackages/specgate-to-generator ledger reconciles that package's ownpackage.json, not the root's, so a rootcheck:entry is out of its scope.Generated by Claude Code