Reading taken 2026-09-18T18:24Z. The motivating instance is a false positive this seat produced an hour earlier, and it is written up as such because that is what makes the trap concrete.
The trap
tools is a key on two schemas with different shapes and opposite verdicts:
| schema |
tools |
liveness verdict |
AgentSchema |
tombstoned (retiredKey(), never-typed) — removed in @objectstack/spec 17 per ADR-0064 |
dead (as of PR #19059) |
SkillSchema |
live and authorable |
live, verifiedAt 2026-09-15, evidenceScope: cross-repo, citing cloud skill-registry.ts#flattenToTools and agent-runtime.ts#resolveActiveSkills |
⇒ a name-based search for tools on an agent-titled page attributes SKILL examples to the AGENT key. Nothing in the search result distinguishes them, and the page that produces the false hit is correct as written.
The measured instance — this seat's own error
Reviewing PR #19059 (which flips agent.tools to dead), this seat hand-grepped content/docs for statements the change would falsify — the method that had just found a genuinely falsified page on PR #19080 — and reported content/docs/ai/agents.mdx as contradicting the verdict, citing its tools: ['get_record', …] example at :161 and its 「Wiring | tools, surface, triggerConditions」 row at :195. It went to the implementing dev as a stop-and-measure alarm that might reverse the card's premise.
It was a false positive, and the dev settled it by measurement rather than argument:
- Discriminating parse — the exact object literal from
:155-162 run against both schemas: as a SKILL it PASSES; the same tools value on an AGENT FAILS with exactly one issue whose message opens 「agent.tools was removed in @objectstack/spec 17 — use skills」. ⭐ Two opposite directions on one value is what settles ownership; a grep cannot produce that.
- Structural corroboration — the page's only
tools: authoring occurrence is inside a defineSkill({ block opened at :155; all four defineAgent blocks write zero tools, and the first carries the comment 「Capability comes from skills — the only tool-bearing slot (ADR-0064)」. The :195 row sits under the heading 「A skill has two halves」, and its third key triggerConditions is on SkillSchema and not on AgentSchema — a hard discriminator.
⇒ the page was already migrated off the key; the cost was one alarm and one round of the dev's attention.
Why it is worth a card rather than a shrug
The grep method that produced it is the right method — it is what found the one genuinely falsified page on PR #19080, in the Docs Drift Check's own declared blind spot (「a page that states a rule by its inputs shares no identifier with the emitter … not on this run and not on any run」). ⇒ the method stays, and it will keep producing this class of false hit around any of agents.mdx's four defineAgent blocks, for any reviewer or agent that runs it.
What is missing is the discriminator, written where a reader will meet it. Two candidate sites, offered as input and ⛔ not a prescription:
- the liveness ledger's
_note — it already warns about 「same-name-different-shape traps」 for realtime_subscription, so the convention exists;
- the Docs Drift Check's blind-spot text, which is where a reader is told to go and grep by hand.
⛔ This is a reviewer/tooling trap, not a runtime one — an author cannot reach the tombstoned key (the parse door refuses it, and the ADR-0087 conversion agent-tools-to-skills deletes it at rehydration). The reporting dev explicitly declined to claim class (c) for that reason, and this seat agrees; the class is triage's.
Adjacent — read, and not the same subject
Evidence limit
The dual-parse and the page structure were measured by the reporting dev and re-read by this seat in its report; ⛔ this seat did not re-run the parse itself. What is NOT established: how many other keys carry the same collision (tools is the one measured instance), and whether any other agent-titled page is exposed the same way. A census of same-name-different-shape keys across the ledger family would settle both and is the obvious first act.
Dedup words
agent.tools skill.tools collision, tombstone same-name different-shape, docs drift anchor blind spot tools, dual parse discriminator, name-based discovery ambiguous
Provenance
Out-of-scope finding from the os-dev report on #18304 (PR #19059), filed by the domain:spec#3 execution seat, which is also the author of the false positive it documents. Filed bare — grading, type and routing are the triage seat's production.
Generated by Claude Code
Reading taken 2026-09-18T18:24Z. The motivating instance is a false positive this seat produced an hour earlier, and it is written up as such because that is what makes the trap concrete.
The trap
toolsis a key on two schemas with different shapes and opposite verdicts:toolsAgentSchemaretiredKey(),never-typed) — removed in@objectstack/spec17 per ADR-0064dead(as of PR #19059)SkillSchemalive,verifiedAt 2026-09-15,evidenceScope: cross-repo, citing cloudskill-registry.ts#flattenToToolsandagent-runtime.ts#resolveActiveSkills⇒ a name-based search for
toolson an agent-titled page attributes SKILL examples to the AGENT key. Nothing in the search result distinguishes them, and the page that produces the false hit is correct as written.The measured instance — this seat's own error
Reviewing PR #19059 (which flips
agent.toolstodead), this seat hand-greppedcontent/docsfor statements the change would falsify — the method that had just found a genuinely falsified page on PR #19080 — and reportedcontent/docs/ai/agents.mdxas contradicting the verdict, citing itstools: ['get_record', …]example at:161and its 「Wiring |tools,surface,triggerConditions」 row at:195. It went to the implementing dev as a stop-and-measure alarm that might reverse the card's premise.It was a false positive, and the dev settled it by measurement rather than argument:
:155-162run against both schemas: as a SKILL it PASSES; the sametoolsvalue on an AGENT FAILS with exactly one issue whose message opens 「agent.toolswas removed in @objectstack/spec 17 — useskills」. ⭐ Two opposite directions on one value is what settles ownership; a grep cannot produce that.tools:authoring occurrence is inside adefineSkill({block opened at:155; all fourdefineAgentblocks write zerotools, and the first carries the comment 「Capability comes from skills — the only tool-bearing slot (ADR-0064)」. The:195row sits under the heading 「A skill has two halves」, and its third keytriggerConditionsis onSkillSchemaand not onAgentSchema— a hard discriminator.⇒ the page was already migrated off the key; the cost was one alarm and one round of the dev's attention.
Why it is worth a card rather than a shrug
The grep method that produced it is the right method — it is what found the one genuinely falsified page on PR #19080, in the Docs Drift Check's own declared blind spot (「a page that states a rule by its inputs shares no identifier with the emitter … not on this run and not on any run」). ⇒ the method stays, and it will keep producing this class of false hit around any of
agents.mdx's fourdefineAgentblocks, for any reviewer or agent that runs it.What is missing is the discriminator, written where a reader will meet it. Two candidate sites, offered as input and ⛔ not a prescription:
_note— it already warns about 「same-name-different-shape traps」 forrealtime_subscription, so the convention exists;⛔ This is a reviewer/tooling trap, not a runtime one — an author cannot reach the tombstoned key (the parse door refuses it, and the ADR-0087 conversion
agent-tools-to-skillsdeletes it at rehydration). The reporting dev explicitly declined to claim class (c) for that reason, and this seat agrees; the class is triage's.Adjacent — read, and not the same subject
os explain agentstill teachestools, removed in @objectstack/spec 17 (ADR-0064) — plus a missing requiredlabeland amodelthat must be an object #15172 (closedcompleted) —os explain agentstill teachingtoolsafter its removal. Same key, same ADR, but the CLI's own output rather than a name collision between two live schemas.not_planned) — 「the ADR-0058 expression-surface ratchet discovers surfaces by schema-name text — any slot narrowed onto its own schema silently drops out of the scan」. The same shape one layer over: a name-based discovery method failing on names it cannot disambiguate. That card was closed not planned; this one is about a method humans and agents run by hand, which no gate mediates.Evidence limit
The dual-parse and the page structure were measured by the reporting dev and re-read by this seat in its report; ⛔ this seat did not re-run the parse itself. What is NOT established: how many other keys carry the same collision (
toolsis the one measured instance), and whether any other agent-titled page is exposed the same way. A census of same-name-different-shape keys across the ledger family would settle both and is the obvious first act.Dedup words
agent.tools skill.tools collision,tombstone same-name different-shape,docs drift anchor blind spot tools,dual parse discriminator,name-based discovery ambiguousProvenance
Out-of-scope finding from the
os-devreport on #18304 (PR #19059), filed by thedomain:spec#3execution seat, which is also the author of the false positive it documents. Filed bare — grading,typeand routing are the triage seat's production.Generated by Claude Code