You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Filed by the domain:devx dev working #8110 (PR pending). Out of scope there: that card's file surface is the one lint.yml step for check:skill-frame-freshness, and its dispatch ruled explicitly that other family members are reported, not fixed, in that PR.
The finding
#8110 asked whether other gates share its split shape. The criterion it fixed is narrow and deliberately not "any check:* script containing &&":
a gate whose scan half cannot run in CI, and whose CI-safe --self-test half is therefore also absent from CI.
Surveyed mechanically (method below). Exactly one other gate qualifies: check:dev-prereqs.
Both halves measured on a clean worktree at 7cfe7ad, before any build:
half
reading
--self-test
exit 0 in 0.12s, 16 cases, on a checkout with nonode_modules and nothing built — "every verdict reachable, exclusions and freshness coverage pinned"
the scan
exit 1 — "The workspace is not built ... 67 of 67 workspace packages declare an entry point under dist/ that is not on disk"
That is the same asymmetry as #8110, for the same reason. The scan asks "is this workspace BUILT and is the one staleness-lying artifact CURRENT", which is a precondition for pnpm dev on a human's long-lived tree. In a CI job that has not built, it is a hard false red about a precondition CI does not have; in a job that just built, it is a tautological green. So it correctly stays out — and takes the self-test half with it.
The self-test half has neither property. It is hermetic (temp fixtures, no network, no workspace state — proven by the 0.12s green above on an unbuilt tree with no dependencies installed) and it is the thing that would notice check-dev-prereqs.mjs losing a verdict path.
Why it is worth a card rather than a note
Identical failure mode to the one #8110 measured: the gate keeps sitting in the gate list reading as coverage. check:dev-prereqs's exposure is arguably worse than the skill-frame one, because its scan half does run on every pnpm dev (the dev chain invokes scripts/check-dev-prereqs.mjs directly with node, without the self-test — that is documented in the script header as a deliberate hot-path saving). So the scan is exercised constantly by humans while the self-test that keeps it honest is exercised by nobody unless someone types pnpm check:dev-prereqs by hand.
Suggested shape
One lint.yml step, node scripts/check-dev-prereqs.mjs --self-test, in the same job and with the same "self-test half only, never the scan" naming as the #8110 step, so the deliberate omission reads as a decision. Precedent for the shape already exists twice in that file: the changeset-family self-tests (#6509, "the SELF-TEST halves only — the real scans stay in pr-automation.yml") and #8110's step.
How the survey was run (so the negative half is reviewable)
All 62 root check:* scripts enumerated from package.json, cross-referenced against every file in .github/workflows/with YAML comment lines stripped first — that step matters: matching raw text puts check:platform-checklist in the "wired" column because lint.yml mentions it only in a comment explaining why it is not wired.
Widened once beyond check:*: every scripts/**/*.mjs mentioning --self-test (63 files), same cross-reference. It surfaced no further candidates — the extras it named are a shared library (scripts/adr-anchors.mjs, imported by gates that do run), PM-loop tooling with no gate role (scripts/pm/check-half-states.mjs, scripts/pm/dispatch-gates.mjs), and scripts/setup-git-hooks.mjs, which runs in CI via the prepare lifecycle.
Considered and rejected: check:platform-checklist
It fails the criterion's first clause. Its scan is a static JSON-structure check over docs/qa/platform-checklist/ that would run in CI perfectly well; it is out by an explicit maintainer policy decision recorded in lint.yml ("the checklist is a QA ledger, not a code gate; keeping it out of the per-PR path means an unrelated PR is never blocked by checklist drift"). Its self-test half is therefore excluded on purpose, not as collateral damage — a different fact, and not this family's.
Also rejected: check:skill-frame-sync
Runs in CI whole, at lint.yml:1082, and is --self-test && scan — the counter-example that shows && is not the family marker.
Filed by the
domain:devxdev working #8110 (PR pending). Out of scope there: that card's file surface is the onelint.ymlstep forcheck:skill-frame-freshness, and its dispatch ruled explicitly that other family members are reported, not fixed, in that PR.The finding
#8110 asked whether other gates share its split shape. The criterion it fixed is narrow and deliberately not "any
check:*script containing&&":Surveyed mechanically (method below). Exactly one other gate qualifies:
check:dev-prereqs.Both halves measured on a clean worktree at
7cfe7ad, before any build:--self-testnode_modulesand nothing built — "every verdict reachable, exclusions and freshness coverage pinned"That is the same asymmetry as #8110, for the same reason. The scan asks "is this workspace BUILT and is the one staleness-lying artifact CURRENT", which is a precondition for
pnpm devon a human's long-lived tree. In a CI job that has not built, it is a hard false red about a precondition CI does not have; in a job that just built, it is a tautological green. So it correctly stays out — and takes the self-test half with it.The self-test half has neither property. It is hermetic (temp fixtures, no network, no workspace state — proven by the 0.12s green above on an unbuilt tree with no dependencies installed) and it is the thing that would notice
check-dev-prereqs.mjslosing a verdict path.Why it is worth a card rather than a note
Identical failure mode to the one #8110 measured: the gate keeps sitting in the gate list reading as coverage.
check:dev-prereqs's exposure is arguably worse than the skill-frame one, because its scan half does run on everypnpm dev(thedevchain invokesscripts/check-dev-prereqs.mjsdirectly withnode, without the self-test — that is documented in the script header as a deliberate hot-path saving). So the scan is exercised constantly by humans while the self-test that keeps it honest is exercised by nobody unless someone typespnpm check:dev-prereqsby hand.Suggested shape
One
lint.ymlstep,node scripts/check-dev-prereqs.mjs --self-test, in the same job and with the same "self-test half only, never the scan" naming as the #8110 step, so the deliberate omission reads as a decision. Precedent for the shape already exists twice in that file: the changeset-family self-tests (#6509, "the SELF-TEST halves only — the real scans stay in pr-automation.yml") and #8110's step.How the survey was run (so the negative half is reviewable)
check:*scripts enumerated frompackage.json, cross-referenced against every file in.github/workflows/with YAML comment lines stripped first — that step matters: matching raw text putscheck:platform-checklistin the "wired" column becauselint.ymlmentions it only in a comment explaining why it is not wired.check:skill-frame-freshness(check:skill-frame-freshness --self-testruns nowhere in CI, so a broken fixture is invisible until a human runs the gate #8110),check:dev-prereqs(this card),check:platform-checklist.check:*: everyscripts/**/*.mjsmentioning--self-test(63 files), same cross-reference. It surfaced no further candidates — the extras it named are a shared library (scripts/adr-anchors.mjs, imported by gates that do run), PM-loop tooling with no gate role (scripts/pm/check-half-states.mjs,scripts/pm/dispatch-gates.mjs), andscripts/setup-git-hooks.mjs, which runs in CI via thepreparelifecycle.Considered and rejected:
check:platform-checklistIt fails the criterion's first clause. Its scan is a static JSON-structure check over
docs/qa/platform-checklist/that would run in CI perfectly well; it is out by an explicit maintainer policy decision recorded inlint.yml("the checklist is a QA ledger, not a code gate; keeping it out of the per-PR path means an unrelated PR is never blocked by checklist drift"). Its self-test half is therefore excluded on purpose, not as collateral damage — a different fact, and not this family's.Also rejected:
check:skill-frame-syncRuns in CI whole, at
lint.yml:1082, and is--self-test && scan— the counter-example that shows&&is not the family marker.Generated by Claude Code
Related: #8110