Uh oh!
There was an error while loading. Please reload this page.
docs(spec): align the skill.tools docblock with ADR-0109's authoring model - #10669
Conversation
…model The `SkillSchema.tools` docblock told authors that tools "should also be registered as first-class metadata (type: 'tool') unless they are dynamically materialised at runtime" — the shape ADR-0109 explicitly rejected, with the exemption inverted: it treated the materialised path as the exception when ADR-0109 makes it, together with the platform registry, the rule. The sibling docblock over `stack.zod.ts`'s `tools` already stated the correct model, so the package shipped two contradictory answers to the same question. The text now mirrors the resolution universe `validate-ai-tool-references` implements: a `tool` record is never required, the default third-party path declares none, and a name resolves against `stack.tools[]` names, the `PLATFORM_PROVIDED_TOOL_NAMES` registry, or the materialised `action_<name>` family. It also records that `stack.tools` is the optional Phase-2 refinement layer with no runtime reader until that phase lands. Prose only — no schema shape, no `.describe()` text, no code path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B4h3medzvhB9rpfoja9jcw
Measured after a real DTS build: property-level comments inside the
`z.object({ ... })` literal do NOT survive into `dist/*.d.ts` (the emitted
declaration is a bare `tools: z.ZodArray<z.ZodString>;`). The text ships instead
through `@objectstack/spec`'s `files` list, which publishes `src/**/*.zod.ts`,
so the docblock travels in the npm tarball as source.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B4h3medzvhB9rpfoja9jcw📓 Docs Drift CheckThis PR changes 1 package(s): 1 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin c5da28b3b8e19d139d8e27e6489996bc9ac48ed8 && git checkout c5da28b3b8e19d139d8e27e6489996bc9ac48ed8
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 7bf3fb78cd17a7846c11c651f57dd77f9a998430 9259145cb80c68eeefdf5ff3ad19d90406cbc581 && git checkout -B drift-repro 7bf3fb78cd17a7846c11c651f57dd77f9a998430 && git merge --no-ff 9259145cb80c68eeefdf5ff3ad19d90406cbc581
node scripts/docs-audit/affected-docs.mjs --json 7bf3fb78cd17a7846c11c651f57dd77f9a998430
|
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Fixes#10356
The
SkillSchema.toolsdocblock inpackages/spec/src/ai/skill.zod.tsrecommended the exact shape ADR-0109 rejected, in the highest-traffic place an AI author reads while writingskill.tools[]:Two defects in one sentence. It advises authoring a
toolrecord per exposed tool — ADR-0109's second rejected alternative, "a required tool record per exposed action", whose cost the ADR states precisely: "a second authoring step, a second namespace to keep consistent, and a second surface for AI authors to hallucinate into — for zero added capability." And it inverts the exemption, treating the materialised path as the exception when ADR-0109 makes it — together with the platform registry — the rule.It was also actively misleading: per ADR-0109 Decision 4, a
stack.toolsrecord is the Phase-2 refinement layer with no runtime reader until that phase lands, so a reader who followed the advice authored inert metadata and believed it did something. Meanwhile the sibling docblock overstack.zod.ts'stoolsalready stated the correct model — the package shipped two contradictory answers to the same question.The change
Prose only. The replacement mirrors the resolution universe
@objectstack/lint'svalidate-ai-tool-referencesactually implements (its header states the same ladder), rather than restating the ADR from memory:toolrecord is never required, and the default third-party path declares none;stack.tools[]names ∪PLATFORM_PROVIDED_TOOL_NAMES∪ the materialisedaction_<name>family;action_<name>half is qualified as the validator qualifies it —ai.exposed+ai.descriptionon a headless action type (ADR-0011), the follow-up item that keeps the rule from blessing references the agent could never call;stack.toolsis named as the optional Phase-2 refinement layer with no runtime reader, so a record authored today is inert.Scope
Strictly the one docblock. Every changed line is a comment line — verified mechanically, not by eye:
No schema shape, no
.describe()text, no code path, and no authorable-surface movement —pnpm --filter @objectstack/spec check:generatedreports all 14 generated artifacts up to date,check:authorable-surfaceamong them.stack.zod.tsis read-only reference here (held by another in-flight card) andToolSchema.outputSchemais untouched — a tracked ADR-0049 item the issue explicitly excludes.One correction worth flagging
The changeset first claimed this text reaches consumers through the generated
.d.ts. A real DTS build disproved it: property-level comments inside thez.object({ … })literal are dropped from the emitted declarations (the built chunk carries a baretools: z.ZodArray<z.ZodString>;). It ships instead through@objectstack/spec'sfileslist, which publishessrc/**/*.zod.ts— the docblock travels in the npm tarball as source. The changeset now states the measured fact; graded patch.Verification — gate union pinned to
9259145cb(the final commit)pnpm --filter @objectstack/spec test— 416 test files, 11097 tests passed, andpnpm --filter @objectstack/spec typecheckclean (check:test-typecheck: OK), both via the shared verify lock.Gate families re-derived against the actual diff with
node scripts/pm/dispatch-gates.mjs(which reads the change set from the merge base itself) — 19 families, all green:check:changeset-gate-self-tests·check:cross-package-test-inputs(+ theci.ymlscript form) ·check:doc-formula-expressions· speccheck:empty-state/check:liveness/check:strictness-ledger/check:variant-docs/check:generated·check:merge-driver·check:objectui-changeset·check:slot-lookup·check:spec-parsed-alias·check:test-source-alias·check:type-source-resolution·check-adr-0087-registration·check-changeset-no-major·check-empty-changeset·check-affected-docs·check-nul-bytes.One declared narrowing:
node scripts/check-dev-prereqs.mjsexits 1 with✗ The workspace is not built — 1 unmet precondition, listing 65 of 67 packages with nodist/on disk. That is an environment precondition needing a fullpnpm build, not a property of this diff — it counted 67 before I built@objectstack/specand@objectstack/formulaand 65 after, exactly the two, and would fail identically on a cleanorigin/maincheckout in this container. CI builds the workspace and runs it for real. Two other reds resolved to the same cause and are green above once the dependency was built:check:doc-formula-expressions(missing@objectstack/formula/dist) andcheck:generated'sapi-surface"stale" verdict — the generator refuses to write a baseline from an unbuiltdist, and after the buildgen:api-surfaceregenerated to a no-op.Related: #10355 — same ai-docs family (different surface: that one is docs, this one is spec source). No shared files.
Generated by Claude Code