Sub-issue of #10924 (No gate type-checks TSDoc @example blocks in packages/spec/src) — this is a live instance of exactly the class that card is about, so the gate it proposes cannot land green until this is repaired. Found while retiring the agent CLI generator (#10359, PR #11028); out of that card's file surface, so untouched there.
The finding
packages/spec/src/ai/skill.zod.ts carries two @example blocks — one on SkillSchema (~line 250) and one on defineSkill (~line 436). Both pass triggerPhrases:
constskill=defineSkill({name: 'case_management',label: 'Case Management',description: 'Handles support case lifecycle',instructions: 'Use these tools to create, update, and resolve support cases.',tools: ['create_case','update_case','resolve_case','query_cases'],triggerPhrases: ['create a case','open a ticket','resolve issue'],// ← rejects on parse});triggerPhrases was removed in @objectstack/spec 17.0.0 (#3896 audit close-out) and is a retiredKey() tombstone in the same file, ~120 lines below the first example. defineSkill calls SkillSchema.parse(), so the documented example throws. Measured at origin/main @ f334d662e, against the built packages/spec/dist:
$ node -e "const {defineSkill}=require('./packages/spec/dist/index.js'); …the block above…"
THREW: [
{
"expected": "never",
"code": "invalid_type",
"path": [ "triggerPhrases" ]
The second block (defineSkill, ~line 436) is the same defect with order_management / place an order, and additionally pairs triggerPhrases with triggerConditions — which is the one the tombstone's own prescription says to write.
Why it matters more than a doc nit
SkillSchema's tombstone text is unusually careful — it explains that a rename to triggerConditions would be the wrong instrument because the prescription is a SPLIT (routing intent → triggerConditions, natural language → description/instructions), and cites that as "this campaign's own fix signposting the way back into the failure mode it exists to kill". The @example blocks above it do precisely that: they hand the next author — human or AI, reading the docblock in an IDE or through MCP introspection — a copyable block whose first move is the retired key.
It does not reach the generated reference page: content/docs/references/ai/skill.mdx renders the triggerPhrases row correctly as [REMOVED] with the full prescription, and carries neither example. So the blast radius is the source docblock channel (ADR-0033), which is exactly the channel #10924 reports nothing compiles.
Scope
packages/spec/src/ai/skill.zod.ts only — rewrite both blocks against the current schema (and note tools is required with no default, so a minimal example must include it). Touching a .describe()/TSDoc on a spec schema means the regeneration discipline applies: pnpm --filter @objectstack/spec build && pnpm --filter @objectstack/spec check:generated before pushing.
Re-check command
git grep -n "triggerPhrases" origin/main -- packages/spec/src/ai/skill.zod.ts
Lines that are @example content are the finding; the retiredKey( declaration and the guidance prose around it are correct and must stay.
Generated by Claude Code
Sub-issue of #10924 (No gate type-checks TSDoc
@exampleblocks inpackages/spec/src) — this is a live instance of exactly the class that card is about, so the gate it proposes cannot land green until this is repaired. Found while retiring theagentCLI generator (#10359, PR #11028); out of that card's file surface, so untouched there.The finding
packages/spec/src/ai/skill.zod.tscarries two@exampleblocks — one onSkillSchema(~line 250) and one ondefineSkill(~line 436). Both passtriggerPhrases:triggerPhraseswas removed in@objectstack/spec17.0.0 (#3896 audit close-out) and is aretiredKey()tombstone in the same file, ~120 lines below the first example.defineSkillcallsSkillSchema.parse(), so the documented example throws. Measured atorigin/main@f334d662e, against the builtpackages/spec/dist:The second block (
defineSkill, ~line 436) is the same defect withorder_management/place an order, and additionally pairstriggerPhraseswithtriggerConditions— which is the one the tombstone's own prescription says to write.Why it matters more than a doc nit
SkillSchema's tombstone text is unusually careful — it explains that a rename totriggerConditionswould be the wrong instrument because the prescription is a SPLIT (routing intent →triggerConditions, natural language →description/instructions), and cites that as "this campaign's own fix signposting the way back into the failure mode it exists to kill". The@exampleblocks above it do precisely that: they hand the next author — human or AI, reading the docblock in an IDE or through MCP introspection — a copyable block whose first move is the retired key.It does not reach the generated reference page:
content/docs/references/ai/skill.mdxrenders thetriggerPhrasesrow correctly as[REMOVED]with the full prescription, and carries neither example. So the blast radius is the source docblock channel (ADR-0033), which is exactly the channel #10924 reports nothing compiles.Scope
packages/spec/src/ai/skill.zod.tsonly — rewrite both blocks against the current schema (and notetoolsis required with no default, so a minimal example must include it). Touching a.describe()/TSDoc on a spec schema means the regeneration discipline applies:pnpm --filter @objectstack/spec build && pnpm --filter @objectstack/spec check:generatedbefore pushing.Re-check command
git grep -n "triggerPhrases" origin/main -- packages/spec/src/ai/skill.zod.tsLines that are
@examplecontent are the finding; theretiredKey(declaration and the guidance prose around it are correct and must stay.Generated by Claude Code