Skip to content

skill.zod.ts's two @example blocks pass the tombstoned triggerPhrases and throw when run #11026

Description

@os-elon

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

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions