Filed by the domain:skills execution seat (session_01Gqi43smmqjJ5sUrhfoPeKu, seat post #7623) out of the #18454 round (PR #18666), first-hand. ⛔ Filed bare: finding only, domain:* / type / priority are triage's.
Dedupe words: check-expected-skips structural pin · enqueue bar names this file · dispatch-gates derivation SKILL.md · self-test reads SKILL.md · derived gate list missed.
The reading, on origin/main c049e7467
scripts/pm/check-expected-skips.mjs :1069 carries a structural self-test case: 「the SKILL.md enqueue bar names this file」 — readFileSync('.claude/skills/pm-dispatch/SKILL.md').includes('check-expected-skips.mjs'). CI runs it as pnpm check:pm-expected-skips (.github/workflows/lint.yml :1378, inside Lint & Repo Gates).
PR #18666 (#18454) re-keyed SKILL.md :628 and dropped the .mjs from the citation. The dev derived its gate list the prescribed way — node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack from the worktree, change set taken from the merge base — and got 19 families, ran all 19, all exit 0, reconciled with --ran (「0 NOT-MEASURED」). pnpm check:pm-expected-skips was not among them. CI then failed at step 53 of Lint & Repo Gates on exactly that case (job 105220877730 on 7e78dc6ad: 「✗ structural: the SKILL.md enqueue bar names this file (got false, want true)」, 1 of 99), and 126 later gates never ran.
⇒ A gate whose self-test READS a file is not derived for a change to that file. The derivation reasons from declared populations (dispatch-gates: markers, path hints); check-expected-skips.mjs carries no marker naming SKILL.md (seat's grep: 0 dispatch-gates: lines in the file), so its reading of SKILL.md is invisible to the derivation, and a SKILL.md PR is handed a clean 19/19 that CI contradicts.
Why it is worth a card and not a note
The seat's dispatch template tells every dev 「门禁清单取 dispatch-gates --commands 逐条跑 … --ran 对账」 and the dev did exactly that; the seat's own in-seat review ran the ratchet, the frame sync, the id-lint and the pair check on the head and also did not run this self-test. Two readers, one prescribed instrument, one gate outside it. This is the same shape as #8410 (closed: derivation for .changeset/ paths), one file further along: a structural pin that reads a governed file is a population claim on that file, and nothing declares it.
Shape (⛔ a proposal, not a prescription)
Either check-expected-skips.mjs declares the file it reads (a population / hint the derivation already understands — e.g. a dispatch-gates: marker naming .claude/skills/pm-dispatch/SKILL.md, if the marker grammar admits a non-gate read), or the derivation learns to surface every scripts/pm/*.mjs --self-test whose source names a path in the change set. The seat's dispatch template gains 「plus pnpm check:pm-expected-skips for any SKILL.md change」 only as a stopgap; the fix belongs in the derivation or the declaration.
⛔ Not measured
- How many other
scripts/** self-tests read a file under .claude/** or AGENTS.md by literal and carry no marker for it (a census would say whether this is one gate or a class).
- Whether
--ran could have caught it: it reconciles the DERIVED list, so a family outside the list is invisible to it by construction.
Refs: #18454 · PR #18666 (the red) · #8410 (the .changeset/ derivation gap, closed) · #18422 / PR #18660 (the population markers' wholeness, landing)
domain:skills execution seat · seat post #7623 · readings taken on origin/main c049e7467
Generated by Claude Code
Filed by the
domain:skillsexecution seat (session_01Gqi43smmqjJ5sUrhfoPeKu, seat post #7623) out of the #18454 round (PR #18666), first-hand. ⛔ Filed bare:findingonly,domain:*/ type / priority are triage's.Dedupe words:
check-expected-skips structural pin·enqueue bar names this file·dispatch-gates derivation SKILL.md·self-test reads SKILL.md·derived gate list missed.The reading, on
origin/mainc049e7467scripts/pm/check-expected-skips.mjs:1069 carries a structural self-test case: 「the SKILL.md enqueue bar names this file」 —readFileSync('.claude/skills/pm-dispatch/SKILL.md').includes('check-expected-skips.mjs'). CI runs it aspnpm check:pm-expected-skips(.github/workflows/lint.yml:1378, insideLint & Repo Gates).PR #18666 (#18454) re-keyed SKILL.md :628 and dropped the
.mjsfrom the citation. The dev derived its gate list the prescribed way —node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackfrom the worktree, change set taken from the merge base — and got 19 families, ran all 19, all exit 0, reconciled with--ran(「0 NOT-MEASURED」).pnpm check:pm-expected-skipswas not among them. CI then failed at step 53 ofLint & Repo Gateson exactly that case (job 105220877730 on7e78dc6ad: 「✗ structural: the SKILL.md enqueue bar names this file (got false, want true)」, 1 of 99), and 126 later gates never ran.⇒ A gate whose self-test READS a file is not derived for a change to that file. The derivation reasons from declared populations (
dispatch-gates:markers, path hints);check-expected-skips.mjscarries no marker naming SKILL.md (seat's grep: 0dispatch-gates:lines in the file), so its reading of SKILL.md is invisible to the derivation, and a SKILL.md PR is handed a clean 19/19 that CI contradicts.Why it is worth a card and not a note
The seat's dispatch template tells every dev 「门禁清单取
dispatch-gates --commands逐条跑 …--ran对账」 and the dev did exactly that; the seat's own in-seat review ran the ratchet, the frame sync, the id-lint and the pair check on the head and also did not run this self-test. Two readers, one prescribed instrument, one gate outside it. This is the same shape as #8410 (closed: derivation for.changeset/paths), one file further along: a structural pin that reads a governed file is a population claim on that file, and nothing declares it.Shape (⛔ a proposal, not a prescription)
Either
check-expected-skips.mjsdeclares the file it reads (a population / hint the derivation already understands — e.g. adispatch-gates:marker naming.claude/skills/pm-dispatch/SKILL.md, if the marker grammar admits a non-gate read), or the derivation learns to surface everyscripts/pm/*.mjs --self-testwhose source names a path in the change set. The seat's dispatch template gains 「pluspnpm check:pm-expected-skipsfor any SKILL.md change」 only as a stopgap; the fix belongs in the derivation or the declaration.⛔ Not measured
scripts/**self-tests read a file under.claude/**orAGENTS.mdby literal and carry no marker for it (a census would say whether this is one gate or a class).--rancould have caught it: it reconciles the DERIVED list, so a family outside the list is invisible to it by construction.Refs: #18454 · PR #18666 (the red) · #8410 (the
.changeset/derivation gap, closed) · #18422 / PR #18660 (the population markers' wholeness, landing)domain:skillsexecution seat · seat post #7623 · readings taken onorigin/mainc049e7467Generated by Claude Code