feat(skill-quality): enforce the invocation-mode rubric fleet-wide - #3021
Conversation
Executes course lane 8's enforcement deliverable (#2968). - Adds explicit `disable-model-invocation: false` to the 17 skills that omitted the key. All sat in the rubric's default class and the absent-key default is already `false`, so this is a normalization, not a behavior change. The fleet is now 220 top-level skills, 0 missing the key. - Adds check 24 to `check-skill.sh`: a marketplace plugin skill missing the key FAILs, anywhere else it WARNs (a consumer's own skill is informed by this fleet's convention, not broken by it), and a non-boolean value FAILs everywhere. Class attribution stays hand-verified — only a `setup` skill's `true` is decidable by a static scan — so every other `true` emits a note rather than a warning nothing could clear. - Points `playbooks:skill-authoring` at the rubric for the authoring-time decision, and records the landed state in the rubric doc. - Adds first eval suites for `knowledge:book-distill` and `wizard:generate`, which the changed-skills gate requires once their SKILL.md changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4
|
Claude finished @kyle-sexton's task in 2m 43s —— View job Claude's review
SummaryThis is a clean, well-scoped enforcement PR. I traced the core logic (new check 24 in
Finding (posted inline)Stale check-count in the plugin manifest description — Note: I could not execute the test suite or |
|
Claude finished @kyle-sexton's task in 59s —— View job Security review
No security issues found. This PR has no security-relevant surface:
Per the skip gate in |
|
Last security-reviewed head: |
Check 24 fails a plugin-tree skill with no explicit `disable-model-invocation`, which is exactly what the changed-skills gate fixtures are. The evals-ratchet pass case failed for the new reason rather than its own, so all three fixtures now carry the key and each case again isolates the concern it was written for. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4
|
Claude finished @kyle-sexton's task in 53s —— View job Security review
No security issues found. Last security-reviewed head was
This satisfies the skip gate (no security-relevant surface introduced by the delta). The prior review of the full PR diff (metadata normalization across 17 skills, the new |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: adf2ce71b1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Claude has reviewed this PR 3 times. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
|
Claude finished @kyle-sexton's task in 2m 6s —— View job Code review (
|
Check 24 stripped quotes and deleted all whitespace before comparing, so a quoted `"false"` — a YAML string, not the boolean the key takes — reported PASS, and a scalar broken by an internal space was spliced back into a passing boolean. Both shipped malformed invocation metadata while the gate called it clean. The value is now validated as the bare scalar: only leading and trailing whitespace is trimmed, a quoted form fails with a message naming the quoting, and the trailing `# comment` that records a `true`'s exception class still parses (skill_frontmatter::field already strips it). Three regression tests cover the quoted form, the internal space, and the annotated boolean. Also syncs the stale check count in the skill-quality manifest description (twenty-three -> twenty-four) and regenerates the catalog it feeds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4
|
Claude finished @kyle-sexton's task in 2m 5s —— View job Code review (
|
|
Claude finished @kyle-sexton's task in 56s —— View job Security review
No security issues found. Last security-reviewed head was
No |
Closes #2969 ## Summary The one re-grade flip from course lane 8 (#2910). The ADR 0005-bounded fleet grade found `planning:questionnaire` was the single `disable-model-invocation: true` skill matching none of the rubric's three exception classes — no side effects beyond writing a Markdown document, not a setup skill, not maintainer-only — and no rationale for the `true` existed in the skill body or the planning CHANGELOG. ## Fix - **Re-checked for a latent rationale before flipping**, as the issue requires. The candidate was a trigger collision with `planning:interview` (both plausibly firing on "I need to ask…"-shaped requests). **There is none**: the two split on *who holds the knowledge*, and each description already routes to the other on that axis — `questionnaire` says to run `/planning:interview` when the user can answer themselves, while `interview`'s phrases ("ask me questions first", "what do you need to know") are about interrogating the user and `questionnaire`'s name a third-party holder. So the flip proceeds rather than being recorded as a new exception class. - **`disable-model-invocation: false`** on `plugins/planning/skills/questionnaire/SKILL.md`. - **Restored trigger phrases.** planning 0.30.1 deliberately left this skill's `Use when:` phrases unoptimized because a hidden skill's description is never matched against user text. Now that it is model-invoked, the description carries three phrases a user would actually type ("I don't know, that's the client's call", "send this to someone else to answer", "write up questions for our security team") beside the ones it already had. Every existing phrase is preserved verbatim (`check-skill.sh` confirms: "all 3 base-ref trigger phrase(s) preserved"). - **New eval case** (`model-routes-third-party-decision-here`) pinning what the flip actually enables: a natural-language request with no slash command routing here rather than to `/planning:interview`, on the who-holds-the-knowledge axis, then interviewing the send only. - **Rubric doc updated** — the fleet-grade row now reads FLIPPED, and a new paragraph records the latent-rationale re-check, the two costs of the hidden mode that surfaced, and the post-flip counts (162 `false` / 58 `true`, leaving 9 non-setup `true` skills, all class-attributed). - **Version bump** `planning` 0.30.7 → 0.31.0 with the matching CHANGELOG entry. ### A second cost the re-check surfaced `questionnaire`'s own description advertises a hand-off "when an interview branch defers to a person-arbiter", and the original changelog entry noted "the interview-side pull-out reference lands separately". It never landed — and while the skill was `true`, the invocation-reach invariant made it unreachable from `interview` anyway, so the advertised hand-off could not have worked. The flip unblocks it; **wiring the interview-side pointer is deliberately out of scope here** (it is its own deliverable, not part of #2969's acceptance criteria). ## Verification - `bash scripts/check-changed-skills.sh origin/main` — 1 skill checked, **0 failed**; reports `invocation mode: model-invoked (fleet default)` and all 3 base-ref trigger phrases preserved. (One pre-existing WARN: the skill has no Gotchas surface — present before this change, untouched by it.) - `bash scripts/check-changed-skills.test.sh` — PASS=13 FAIL=0. - Fleet recount confirms the doc's figures: 162 `false` / 58 `true` across 220 top-level skills. - `check-jsonschema` + `check-evals-quality.sh` on the eval suite — ok / PASS, 0 warnings. - `bash scripts/validate-plugins.sh` — all manifests + catalog validated; `generate-catalog.mjs --check` and `generate-cheatsheet.mjs --check` in sync. - `bash scripts/check-changelog-parity.sh --check` / `--check-bump origin/main` / `--check-order` — all green. - `npx markdownlint-cli2` on all changed markdown — 0 issues; `typos` clean. ## Related - Refs #2910 (lane 8 specification), `docs/upstream/aihero-course.md` lane 8 rows - Refs #2968 / PR #3021 (the sibling enforcement item; check 24 now gates the explicit key this skill carries) 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4 --- _Generated by [Claude Code](https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Closes #2968
Summary
Executes course lane 8's enforcement deliverable (#2910; rubric locked 2026-08-17): every skill in the fleet now states its invocation mode explicitly,
skill-quality:checkenforces that, andplaybooks:skill-authoringroutes the authoring-time decision to the rubric. The locked decisions are not relitigated here — this is their enforcement.Fix
disable-model-invocation: false— exactly the list the issue names (code-tidying:batch-simplify,education:explain,education:quiz-me,event-storming:methodology,event-storming:simulation,github:advise,github:audit,knowledge:book-distill,machine-health:audit,naming:name-it-better,plugin-quality:audit,repo-fleet-hygiene:audit,repo-hygiene:clean,toolchain:check,toolchain:lint,visualization:visualize,wizard:generate), all in the rubric's default class. The absent-key default is alreadyfalse, so this is a no-behavior-change normalization. Fleet after it: 220 top-level skills, 161false/ 59true/ 0 missing the key.check-skill.shcheck 24 — explicit invocation mode. Severity is scoped by tree: a marketplace plugin skill (plugins/*/skills/*) missing the key FAILs; anywhere else it WARNs, because the absent-key default already behaves asfalseand a consumer's own skill should be informed by this fleet's convention rather than broken by it. A non-boolean value FAILs everywhere. Class attribution is not machine-checkable — only asetupskill'strueis decidable by a static scan (class (ii), the PLUGIN-PHILOSOPHY setup contract) — so every othertrueemits a note pointing at the rubric rather than a warning no scan could clear.falsereports the default; a missing key outsideplugins/warns without failing; the same omission insideplugins/*/skills/*fails; a non-boolean fails; a non-setuptrueis noted, not warned; asetupskill'strueis attributed to class (ii).playbooks:skill-authoringgains an authoring-time pointer todocs/conventions/invocation-mode/README.md(points, never restates) in its Skill-tool composition section.knowledge:book-distill(6 cases) andwizard:generate(5 cases) — the changed-skills gate requires evals for any skill whose SKILL.md changes, and these were the only two of the 17 without a suite. Cases are grounded in each skill's own contract (read-one-write-one interleave, untrusted source text, path-traversal slugification, EPUB package-document path, copyright caution; repo-first scoping, names-only.envreads, the human-approval gate beforechmod +x, the off-limits library above theSTAGESmarker,ghabsence degrading rather than failing).skill-qualityminor for the new check; the rest patch).Verification
bash scripts/check-changed-skills.sh origin/main— 19 skills checked, 0 failed.bash plugins/skill-quality/scripts/check-skill.test.sh— 93 assertions pass; the failing set is byte-identical to the origin/main baseline (21 pre-existing container failures from mawk's missing ERE intervals, skill-quality: check-skill.sh fresh-eyes scanner breaks under mawk — ERE interval expressions unsupported #3005 — CI runs gawk). Diffed baseline-vs-head failure lists to confirm no new failure.161 false/59 true).bash scripts/validate-plugins.sh— all manifests + catalog validated;generate-catalog.mjs --checkandgenerate-cheatsheet.mjs --checkin sync.bash scripts/check-changelog-parity.sh --check/--check-bump origin/main/--check-order— all green (83 changelogs).check-jsonschema+check-evals-quality.shon both new suites — ok / PASS with 0 warnings;scripts/check-orphaned-fixtures.sh --check— no orphans.npx markdownlint-cli2on all 35 changed markdown files — 0 issues;shellcheckandshfmt -dclean on both changed shell scripts;typosclean.Related
docs/upstream/aihero-course.mdlane 8 rowsplanning:questionnairetofalse)🤖 Generated with Claude Code
https://claude.ai/code/session_01QbfCrj3X9FfGL7VRZYmrn4
Generated by Claude Code