Skip to content

fix(pm): declare check-role-word's skills root for dispatch-gates derivation - #10114

Merged
os-warren merged 1 commit into
mainfrom
claude/issue-10107-role-word-skills-hint
Aug 20, 2026
Merged

fix(pm): declare check-role-word's skills root for dispatch-gates derivation#10114
os-warren merged 1 commit into
mainfrom
claude/issue-10107-role-word-skills-hint

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes#10107

scripts/check-role-word.mjs walks ROOTS = ['content/docs', 'skills'], but
scripts/pm/dispatch-gates.mjs builds a gate's watch hints from the path
literals in its own source, and a literal only "looks pathy" when it carries a
separator. content/docs has one; the bare word skills does not, so no hint
was ever built for it. A card touching only the skills tree derived the content
half, scored this gate silent, and the dev who ran the derived union locally
never saw it. PR #10038 (a skills-only docs fix) paid one repair round for
exactly that: a green local union, then role-word count grew 2 to 3 in CI.

What changed

One provenance-only constant in the gate's own source, in the subtree spelling
dispatch-gates compares in, plus the pins that keep it honest:

  • scripts/check-role-word.mjsROOT_DIR_WATCH_HINTS = ['skills/**'], with
    a docblock stating that nothing in the gate reads it and why the glob form
    must never appear in ROOTS (walk() sits behind existsSync, so the glob
    spelling there would skip the root in silence). Four self-test cases pin the
    coupling derived from ROOTS on both sides, so renaming or widening a
    root cannot leave the declaration describing the old population.
  • scripts/pm/dispatch-gates.mjs — self-test only: 334 cases to 341, added,
    none weakened. Positive pins read the real gate (not a fixture), so what is
    pinned is that the tree still HAS the declaration; negative pins hold the
    boundary the declaration must not buy.

The extractor and hintCovers are untouched. That refusal of bare
single-segment literals is deliberate and measured (it was priced at +139084
fabricated gate/file pairs), and widening it would reintroduce the fabricated
leads it exists to refuse. Scanning behaviour is unchanged — the gate reads the
same 216 files and reaches the same verdicts.

Measured, at 4fb58de

Before, node scripts/pm/dispatch-gates.mjs --residue skills/objectstack-platform/SKILL.md:

 - pnpm check:role-word [lint.yml] names: content/docs, scripts/role-word-baseline.json

After, same command:

 - pnpm check:role-word [lint.yml] names: content/docs, scripts/role-word-baseline.json, skills/**

And the derivation over that same skills path goes from

Local gates for this card (paste into the dispatch prompt):
- pnpm check:pm-governed-merges [lint.yml] matched via skills/objectstack-platform/SKILL.md ⇢ gate source 'skills/**'
1 matched above · 35 undetermined · 79 silent

to

Local gates for this card (paste into the dispatch prompt):
- pnpm check:pm-governed-merges [lint.yml] matched via skills/objectstack-platform/SKILL.md ⇢ gate source 'skills/**'
- pnpm check:role-word [lint.yml] matched via skills/objectstack-platform/SKILL.md ⇢ gate source 'skills/**'
2 matched above · 35 undetermined · 78 silent

Hint extraction on the gate itself, ["content/docs","scripts/role-word-baseline.json"]
to ["content/docs","scripts/role-word-baseline.json","skills/**"] — one hint
gained, none lost, and .claude/skills/pm-dispatch/SKILL.md stays false
(that tree is not in ROOTS, so the gate must not be named for a card editing it).

Reverse verification

Predicted in writing first, then measured. Ablation: the declaration emptied to
[] rather than deleted, because the self-test references the constant and a
deletion would red as a ReferenceError crash instead of as named failures.
Predicted direction: reddening. All six predictions held exactly:

legpredictedmeasured
hints on the gateback to 2, skills/** gone["content/docs","scripts/role-word-baseline.json"]
--residue role-word namesloses the third namenames: content/docs, scripts/role-word-baseline.json
derivation over a skills pathmatched 2 to 1, silent 78 to 791 matched above · 35 undetermined · 79 silent
dispatch-gates self-testexactly 1 of 341 fails✗ the role-word ratchet reaches the published skills catalog it declares / ✗ dispatch-gates self-test: 1 of 341 case(s) failed. exit 1
check-role-word self-testexactly 2 failthe ROOT-coverage case and the skills case, check-role-word --self-test: 2 failure(s). exit 1
rebuild needed?no — both tools readFileSync the gate's SOURCE, no exports/dist in the path, so no stale build can mask either legconfirmed, no build step exists here

Restored with git checkout HEAD -- scripts/check-role-word.mjs; git status --short and git diff HEAD --stat both empty afterwards, and both self-tests
re-run green (341 cases, exit 0).

Gates, at 4fb58de

Union derived by node scripts/pm/dispatch-gates.mjs from the real diff (no
hand-written path list), all four run, each quoting its own verdict line:

  • pnpm check:role-word exit 0 — check-role-word: OK, no new occurrences of the reserved word. / Scanned: 216 .md/.mdx file(s) read across 2 root(s) — content/docs 180, skills 36.
  • pnpm check:pm-dispatch-gates exit 0 — ✓ dispatch-gates self-test: 341 cases pass.
  • pnpm check:cross-package-test-inputs exit 0 — OK: 12 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob.
  • node scripts/check-cross-package-test-inputs.mjs (the ci.yml half) exit 0 — same verdict line
  • node scripts/check-nul-bytes.mjs exit 0 — check-nul-bytes: OK (scanned 6369 text file(s) ... no raw ASCII control bytes).

Exit codes captured by redirecting to a file before any pipe, never through
tail.

No changeset: scripts/** only, nothing published changes.


Generated by Claude Code

…ivation
check-role-word walks ROOTS = ['content/docs', 'skills'], but dispatch-gates
builds its watch hints from path literals carrying a separator, so the bare
word `skills` produced no hint at all: a skills-only card derived the content
half and scored this gate `silent`. PR #10038 paid one repair round for it —
a green local union, then `role-word count grew 2 to 3` in CI.
Adds the provenance-only subtree declaration (`skills/**`) in the gate's own
source, the same pattern root-file populations use, with the coupling to ROOTS
pinned in both self-tests. The extractor and hintCovers are untouched: that
refusal of bare single-segment literals is measured and deliberate.
No scanning behaviour changes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AeA3nU1B5Q2pgxqxgUrexd
@os-warrenos-warren added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 20, 2026 — with Claude
@os-warren
os-warren marked this pull request as ready for review August 20, 2026 04:56
@os-warren
os-warren added this pull request to the merge queueAug 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 32333808972 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (3/3) — 失败步骤: Run this shard's tests

    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mdrops the subscription rather than delivering it wi
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mdrops the subscription rather than delivering it wi
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mre-arms with its headers when the CryptoProvider re
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mre-arms with its headers when the CryptoProvider re
    �[41m�[1m FAIL �[22m�[49m src/dev-plugin-security-enforcement-warning.test.ts�[2m > �[22m[#10036] the "nothing is enforced" warning must fire when SecurityPlugin.start() bailed�[2m > �[22mbail #1 (no �[41m�[1m FAIL �[22m�[49m src/dev-plugin-security-enforcement-warning.test.ts�[2m > �[22m[#10036] the "nothing is enforced" warning must fire when SecurityPlugin.start() bailed�[2m > �[22mbail #2 (eng
    �[41m�[1m FAIL �[22m�[49m src/dev-plugin-security-enforcement-warning.test.ts�[2m > �[22m[#10036] the "nothing is enforced" warning must fire when SecurityPlugin.start() bailed�[2m > �[22mdoes not fir
    

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 17 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Aug 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 32333758325 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (3/3) — 失败步骤: Run this shard's tests

    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mdrops the subscription rather than delivering it wi
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mdrops the subscription rather than delivering it wi
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mre-arms with its headers when the CryptoProvider re
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mre-arms with its headers when the CryptoProvider re
    �[41m�[1m FAIL �[22m�[49m src/dev-plugin-security-enforcement-warning.test.ts�[2m > �[22m[#10036] the "nothing is enforced" warning must fire when SecurityPlugin.start() bailed�[2m > �[22mbail #1 (no �[41m�[1m FAIL �[22m�[49m src/dev-plugin-security-enforcement-warning.test.ts�[2m > �[22m[#10036] the "nothing is enforced" warning must fire when SecurityPlugin.start() bailed�[2m > �[22mbail #2 (eng
    

历史信号:

  • ⚠️本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 19 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 32334242692 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (3/3) — 失败步骤: Run this shard's tests

    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mdrops the subscription rather than delivering it wi
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mdrops the subscription rather than delivering it wi
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mre-arms with its headers when the CryptoProvider re
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mre-arms with its headers when the CryptoProvider re
    �[41m�[1m FAIL �[22m�[49m src/dev-plugin-security-enforcement-warning.test.ts�[2m > �[22m[#10036] the "nothing is enforced" warning must fire when SecurityPlugin.start() bailed�[2m > �[22mbail #1 (no �[41m�[1m FAIL �[22m�[49m src/dev-plugin-security-enforcement-warning.test.ts�[2m > �[22m[#10036] the "nothing is enforced" warning must fire when SecurityPlugin.start() bailed�[2m > �[22mbail #2 (eng
    

历史信号:

  • ⚠️本 PR 过去 24h 已在队列失败 2 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 23 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@os-warren
os-warren added this pull request to the merge queueAug 20, 2026
@github-merge-queue
github-merge-queueBot removed this pull request from the merge queue due to failed status checks Aug 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 32335241395 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (3/3) — 失败步骤: Run this shard's tests

    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mdrops the subscription rather than delivering it wi
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mdrops the subscription rather than delivering it wi
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mre-arms with its headers when the CryptoProvider re
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mre-arms with its headers when the CryptoProvider re
    �[41m�[1m FAIL �[22m�[49m src/dev-plugin-security-enforcement-warning.test.ts�[2m [ src/dev-plugin-security-enforcement-warning.test.ts ]�[22m
    

历史信号:

  • ⚠️本 PR 过去 24h 已在队列失败 3 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 33 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 32335486523 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (3/3) — 失败步骤: Run this shard's tests

    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mdrops the subscription rather than delivering it wi
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mdrops the subscription rather than delivering it wi
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mre-arms with its headers when the CryptoProvider re
    �[90mstdout�[2m | src/webhook-secret-at-rest.test.ts�[2m > �[22m�[2mfail-closed and re-arm, extended to headers (#7986 × #7799/#8022)�[2m > �[22m�[2mre-arms with its headers when the CryptoProvider re
    �[41m�[1m FAIL �[22m�[49m src/dev-plugin-security-enforcement-warning.test.ts�[2m > �[22m[#10036] the "nothing is enforced" warning must fire when SecurityPlugin.start() bailed�[2m > �[22mbail #1 (no �[41m�[1m FAIL �[22m�[49m src/dev-plugin-security-enforcement-warning.test.ts�[2m > �[22m[#10036] the "nothing is enforced" warning must fire when SecurityPlugin.start() bailed�[2m > �[22mbail #2 (eng
    �[41m�[1m FAIL �[22m�[49m src/dev-plugin-security-enforcement-warning.test.ts�[2m > �[22m[#10036] the "nothing is enforced" warning must fire when SecurityPlugin.start() bailed�[2m > �[22mdoes not fir
    

历史信号:

  • ⚠️本 PR 过去 24h 已在队列失败 4 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 35 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/mskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-warren@claude