fix(spec): tombstone agent.tools instead of deleting it — unbreak main - #3904
Merged
Conversation
#3894 follow-up) #3894 removed `agent.tools` and `AIToolSchema` outright, which broke `pnpm --filter @objectstack/spec build` on main: the authorable-surface ratchet (ADR-0104 / #3733) fails when an authorable key disappears, because none of these schemas is `.strict()` — Zod silently STRIPS an unknown key, so an author who keeps writing `tools:` gets a clean parse and an agent that reaches none of the tools they listed. That is the silent-capability-loss shape #3820 exists to eliminate, restored one layer down. The gate was right; my removal was wrong. (It slipped CI because Build Core restored a turbo cache entry for the spec build; the failure reproduces on any cold build of main.) The removal stands — ADR-0064 needs the second, unscoped tool slot gone. What changes is HOW it is removed: - `agent.tools` is now `retiredKey()`, so authoring it throws with the fix in the message (use `skills`; a platform tool by name, or `action_<name>` for your own AI-exposed Action; `os migrate meta`). This supersedes #3894's "remains a silent no-op rather than a parse error" — loud is correct, and is what the ratchet requires. - A D2 conversion `agent-tools-to-skills` + its D3 chain step, so the removal reaches spec-changes.json, the upgrade guide and the `spec_changes` MCP tool. Unlike the protocol-17 renames beside it this has NO lossless target: each entry must become a reference inside a skill, which is a human decision. So it drops the dead key (the runtime stopped reading it in cloud#910, so it already contributes nothing) and emits one notice per agent marking where capability must be re-declared. - The three `ai/AITool:*` baseline lines are deleted deliberately — the one case the ratchet sanctions in-PR. They were authorable only as the element shape of `agent.tools`; with the parent tombstoned nothing reaches them, so they cannot vanish silently: the parent speaks first, with a prescription. Keeping a schema alive purely to hold three unreachable lines would be the dead contract surface this issue is about. Agent tests now pin the rejection and its message rather than the strip semantics they asserted before. Verified: spec build OK, spec 6823 tests, lint 540, cli 761, full workspace build, doc-authoring guard, check:docs, check:api-surface, check:skill-refs, check:skill-examples (197), eslint — all green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BHjroNkLkajskKbJaidko4
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 104 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-zhuang
marked this pull request as ready for review
July 28, 2026 17:02
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
mainis currently red and this fixes it.pnpm --filter @objectstack/spec buildfails on a cold build ofmain:#3894 (mine) removed
agent.toolsandAIToolSchemaoutright. The authorable-surface ratchet (ADR-0104 / #3733) rejects that, and it is right: none of these schemas is.strict(), so Zod silently STRIPS an unknown key — an author who keeps writingtools:would get a clean parse and an agent that reaches none of the tools they listed. That is precisely the silent-capability-loss shape #3820 exists to eliminate, reintroduced one layer down by the PR meant to eliminate it.It slipped CI because Build Core restored a turbo cache entry for the spec build; the failure reproduces on any cold build.
The removal stands — the method changes
ADR-0064 still needs the second, unscoped tool slot gone. Three changes make that removal honest:
1.
agent.toolsis tombstoned, not deleted.retiredKey()makes itz.never(), so authoring it throws with the fix in the message:This supersedes #3894's changeset line claiming the key "remains a silent no-op rather than a parse error". Loud is correct, and it is what this repo's ratchet requires.
2. A D2 conversion + D3 chain step.
agent-tools-to-skillsjoinsCONVERSIONS_BY_MAJOR[17]and step 17'sconversionIds, so the removal reachesspec-changes.json, the upgrade guide, and thespec_changesMCP tool. Unlike the protocol-17 renames beside it, this one has no lossless target — each entry must become a reference inside a skill, which is a human decision about which skill. So it drops the dead key (the runtime stopped reading it in objectstack-ai/cloud#910, so it already contributes nothing at load) and emits one notice per agent marking where capability has to be re-declared, rather than guessing a destination.3. The three
ai/AITool:*baseline lines are deleted deliberately — the one case the ratchet sanctions in-PR. Those keys were authorable only as the element shape ofagent.tools; with the parent tombstoned nothing reaches them, so they cannot vanish silently — the parent speaks first, with a prescription. KeepingAIToolSchemaalive purely to hold three unreachable lines would be exactly the dead contract surface this issue is about.Agent tests now pin the rejection and its message rather than the strip semantics they previously asserted.
Verification
pnpm --filter @objectstack/spec build✅ (was the failure) · spec 262 files / 6823 tests · lint 37 / 540 · cli 72 / 761 · full workspacepnpm build· doc-authoring guard (213 files) ·check:docs(250) ·check:api-surfaceunchanged ·check:skill-refs(9) ·check:skill-examples(197) ·eslint— all green.Refs #3894 · #3820 · ADR-0104 · ADR-0064 · ADR-0087
🤖 Generated with Claude Code
https://claude.ai/code/session_01BHjroNkLkajskKbJaidko4
Generated by Claude Code