agentfootprint 9.75.0 → 9.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/CLAUDE.md +22 -18
  3. package/dist/artifacts/index.js +3 -1
  4. package/dist/artifacts/index.js.map +1 -1
  5. package/dist/artifacts/recordingArtifact.js +47 -1
  6. package/dist/artifacts/recordingArtifact.js.map +1 -1
  7. package/dist/core/Agent.js +30 -0
  8. package/dist/core/Agent.js.map +1 -1
  9. package/dist/core/agent/stages/toolCalls.js +42 -0
  10. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  11. package/dist/core/agent/toolDispatch.js +101 -0
  12. package/dist/core/agent/toolDispatch.js.map +1 -0
  13. package/dist/core/flowchartAsTool.js +9 -2
  14. package/dist/core/flowchartAsTool.js.map +1 -1
  15. package/dist/core/runbook/coverage.js +162 -0
  16. package/dist/core/runbook/coverage.js.map +1 -0
  17. package/dist/core/runbook/dispatch.js +119 -0
  18. package/dist/core/runbook/dispatch.js.map +1 -0
  19. package/dist/core/runbook/index.js +24 -0
  20. package/dist/core/runbook/index.js.map +1 -0
  21. package/dist/core/runbook/runbookAsTool.js +358 -0
  22. package/dist/core/runbook/runbookAsTool.js.map +1 -0
  23. package/dist/core/runbook/types.js +22 -0
  24. package/dist/core/runbook/types.js.map +1 -0
  25. package/dist/core/runbook/verdicts.js +156 -0
  26. package/dist/core/runbook/verdicts.js.map +1 -0
  27. package/dist/core/runbook/walk.js +115 -0
  28. package/dist/core/runbook/walk.js.map +1 -0
  29. package/dist/core/tools.js +55 -1
  30. package/dist/core/tools.js.map +1 -1
  31. package/dist/esm/artifacts/index.d.ts +1 -1
  32. package/dist/esm/artifacts/index.js +1 -1
  33. package/dist/esm/artifacts/index.js.map +1 -1
  34. package/dist/esm/artifacts/recordingArtifact.d.ts +36 -0
  35. package/dist/esm/artifacts/recordingArtifact.js +45 -0
  36. package/dist/esm/artifacts/recordingArtifact.js.map +1 -1
  37. package/dist/esm/core/Agent.js +30 -0
  38. package/dist/esm/core/Agent.js.map +1 -1
  39. package/dist/esm/core/agent/stages/toolCalls.js +42 -0
  40. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  41. package/dist/esm/core/agent/toolDispatch.d.ts +50 -0
  42. package/dist/esm/core/agent/toolDispatch.js +97 -0
  43. package/dist/esm/core/agent/toolDispatch.js.map +1 -0
  44. package/dist/esm/core/flowchartAsTool.d.ts +6 -0
  45. package/dist/esm/core/flowchartAsTool.js +9 -2
  46. package/dist/esm/core/flowchartAsTool.js.map +1 -1
  47. package/dist/esm/core/runbook/coverage.d.ts +69 -0
  48. package/dist/esm/core/runbook/coverage.js +155 -0
  49. package/dist/esm/core/runbook/coverage.js.map +1 -0
  50. package/dist/esm/core/runbook/dispatch.d.ts +69 -0
  51. package/dist/esm/core/runbook/dispatch.js +112 -0
  52. package/dist/esm/core/runbook/dispatch.js.map +1 -0
  53. package/dist/esm/core/runbook/index.d.ts +9 -0
  54. package/dist/esm/core/runbook/index.js +9 -0
  55. package/dist/esm/core/runbook/index.js.map +1 -0
  56. package/dist/esm/core/runbook/runbookAsTool.d.ts +88 -0
  57. package/dist/esm/core/runbook/runbookAsTool.js +354 -0
  58. package/dist/esm/core/runbook/runbookAsTool.js.map +1 -0
  59. package/dist/esm/core/runbook/types.d.ts +196 -0
  60. package/dist/esm/core/runbook/types.js +21 -0
  61. package/dist/esm/core/runbook/types.js.map +1 -0
  62. package/dist/esm/core/runbook/verdicts.d.ts +78 -0
  63. package/dist/esm/core/runbook/verdicts.js +148 -0
  64. package/dist/esm/core/runbook/verdicts.js.map +1 -0
  65. package/dist/esm/core/runbook/walk.d.ts +72 -0
  66. package/dist/esm/core/runbook/walk.js +110 -0
  67. package/dist/esm/core/runbook/walk.js.map +1 -0
  68. package/dist/esm/core/tools.d.ts +112 -0
  69. package/dist/esm/core/tools.js +52 -0
  70. package/dist/esm/core/tools.js.map +1 -1
  71. package/dist/esm/index.d.ts +4 -3
  72. package/dist/esm/index.js +19 -2
  73. package/dist/esm/index.js.map +1 -1
  74. package/dist/esm/lib/mcp/toolExtras.d.ts +8 -0
  75. package/dist/esm/lib/mcp/toolExtras.js +7 -1
  76. package/dist/esm/lib/mcp/toolExtras.js.map +1 -1
  77. package/dist/index.js +97 -66
  78. package/dist/index.js.map +1 -1
  79. package/dist/lib/mcp/toolExtras.js +6 -0
  80. package/dist/lib/mcp/toolExtras.js.map +1 -1
  81. package/dist/types/artifacts/index.d.ts +1 -1
  82. package/dist/types/artifacts/index.d.ts.map +1 -1
  83. package/dist/types/artifacts/recordingArtifact.d.ts +36 -0
  84. package/dist/types/artifacts/recordingArtifact.d.ts.map +1 -1
  85. package/dist/types/core/Agent.d.ts.map +1 -1
  86. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  87. package/dist/types/core/agent/toolDispatch.d.ts +51 -0
  88. package/dist/types/core/agent/toolDispatch.d.ts.map +1 -0
  89. package/dist/types/core/flowchartAsTool.d.ts +6 -0
  90. package/dist/types/core/flowchartAsTool.d.ts.map +1 -1
  91. package/dist/types/core/runbook/coverage.d.ts +70 -0
  92. package/dist/types/core/runbook/coverage.d.ts.map +1 -0
  93. package/dist/types/core/runbook/dispatch.d.ts +70 -0
  94. package/dist/types/core/runbook/dispatch.d.ts.map +1 -0
  95. package/dist/types/core/runbook/index.d.ts +10 -0
  96. package/dist/types/core/runbook/index.d.ts.map +1 -0
  97. package/dist/types/core/runbook/runbookAsTool.d.ts +89 -0
  98. package/dist/types/core/runbook/runbookAsTool.d.ts.map +1 -0
  99. package/dist/types/core/runbook/types.d.ts +197 -0
  100. package/dist/types/core/runbook/types.d.ts.map +1 -0
  101. package/dist/types/core/runbook/verdicts.d.ts +79 -0
  102. package/dist/types/core/runbook/verdicts.d.ts.map +1 -0
  103. package/dist/types/core/runbook/walk.d.ts +73 -0
  104. package/dist/types/core/runbook/walk.d.ts.map +1 -0
  105. package/dist/types/core/tools.d.ts +112 -0
  106. package/dist/types/core/tools.d.ts.map +1 -1
  107. package/dist/types/index.d.ts +4 -3
  108. package/dist/types/index.d.ts.map +1 -1
  109. package/dist/types/lib/mcp/toolExtras.d.ts +8 -0
  110. package/dist/types/lib/mcp/toolExtras.d.ts.map +1 -1
  111. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,70 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [9.76.0] - 2026-08-28
11
+
12
+ ### Added
13
+
14
+ - **`runbookAsTool` — turn a written procedure into a tool whose every answer
15
+ is evidence.** Triage is the most-used agent job in a business: run the
16
+ standing procedure, come back with a verdict somebody can act on. The first
17
+ production tool of that shape hand-rolled ~800 lines of envelope around a
18
+ footprintjs chart — a coverage ledger merging every inner source's own
19
+ ledger, a rule-version stamp on every sentence, capped verdict rows beside a
20
+ pre-rendered table, and the recorded walk that lets a reader CHECK the
21
+ verdict instead of trusting it. `runbookAsTool` is that envelope as one
22
+ declaration bag; the smallest legal call is `{ name, description,
23
+ procedure }` and it still yields the honest spine.
24
+
25
+ **The mandatory honesty spine**, on every answer whatever the runbook's
26
+ shape: `af_coverage` (three lists + a sentence naming the rule set and
27
+ version, with every inner tool's ledger folded upward), `af_provenance`
28
+ re-emitted FIRST (a seeded source's confession survives composition),
29
+ `rule_version` (or the honest `'undeclared'`), and the recorded walk as an
30
+ artifact ticket — new kind **`recording/chart-walk`** beside
31
+ `recording/run`, with `chartWalkPutInput` beside `recordingPutInput`. The
32
+ walk descriptor carries truthful counters, the declared projection (over
33
+ the cap, the CONTROL FLOW survives — stages, forks, and every `condition`
34
+ entry with its decide() evidence — never a head slice that keeps four
35
+ hundred writes and drops every decision), and a `walk_segment` discriminant
36
+ (`'full'` today; the wire is ready for resumed segments before gates land).
37
+ A failed mint costs the ticket, never the answer.
38
+
39
+ **The optional verdict projection**, selected by `resultKind: 'verdict/*'`:
40
+ rows off the chart's `verdicts` state key, ONE cap for the structured list
41
+ and the rendered table, truthful `rows_shown/rows_total/rows_complete`, and
42
+ `verdict_meanings` GENERATED from the decider's declared branches plus the
43
+ rule labels this run's evidence carried — never hand-restated, so a rule
44
+ change and its meaning change on the same day. Three outcomes, honestly: a
45
+ clean envelope; an inner absence passed through VERBATIM (the framework
46
+ still reads it as an absence); and `declined` rows counted into the ledger
47
+ as not-checked ground.
48
+
49
+ `flowchartAsTool` stays for compatibility (its `resultMapper` users stay
50
+ put, byte-identical); its stale pause message now names the runbook
51
+ program's gate phase instead of a version that shipped years ago.
52
+
53
+ - **`ctx.tools` — a tool's body can call other registered tools through the
54
+ run's own dispatch.** The `procedure` factory is invoked per call with the
55
+ agent's dispatch (static + skill-carried tools; ToolProvider-delivered
56
+ tools are invisible — there is no build-time list, the stated 9.72.0
57
+ caveat), so stages compose registered sources instead of importing modules
58
+ and building a second query stack. Inner calls run with `hasArtifacts:
59
+ false` (one answer, one ticket — never competing chips), a derived
60
+ toolCallId naming the outer call, `needs` resolved on the fail-closed
61
+ non-interactive path, and `checkIn`/`wants` tools refused BY NAME (an inner
62
+ call cannot pause, and must never silently skip a consent gate).
63
+
64
+ - **`composedOf` + `gates` on `defineTool`.** A composed tool names its
65
+ ingredient tools; the drift gate runs at AGENT BUILD — the one moment the
66
+ catalog is complete — so a renamed ingredient fails the build by name, not
67
+ the first 3 a.m. run. `gates` declares a procedure that can raise an
68
+ approval gate (read by composition-time checks that must keep a gating tool
69
+ out of a fan-out branch). Both pass the declaration bar (consumer-side
70
+ rails read them; nothing governs execution) and travel the MCP `_meta` bag
71
+ in both directions, judged on ingest by the same exported asserts
72
+ `defineTool` uses.
73
+
10
74
  ## [9.75.0] - 2026-08-28
11
75
 
12
76
  ### Added
package/CLAUDE.md CHANGED
@@ -17,46 +17,50 @@ not in this table, search `src/index.ts` for the nearest noun before writing cod
17
17
 
18
18
  | If you are about to build… | It is | Where | Since |
19
19
  |---|---|---|---|
20
+ | turning a written operational procedure (a runbook, a triage playbook) into ONE agent tool whose every answer is EVIDENCE — coverage folded up from the inner tools it calls, rule name+version, verdict rows with GENERATED meanings, and the recorded walk as an artifact ticket, never bytes | `runbookAsTool` — dials: `procedure` (factory, invoked per call with `ctx.tools`) + `resultKind` (`'verdict/*'` arms the rowset projection; anything else ships spine + the chart's `report`) + `rules {name, version}` (default absent ⇒ `rule_version: 'undeclared'`) + `verdicts {decider, maxRows}` (default 50) + `walk {cap}` (default 500; over-cap ⇒ control-flow projection, declared) + `composedOf` (drift-checked at agent BUILD) + kept `recorders`/`keepRecord`/`keepRecordLimit`/`redact`; reserved state keys `verdicts`/`coverage`/`report`; inner `absent()` passes through VERBATIM unless the call said `allowAbsent`; walk kind `recording/chart-walk` + `walk_segment` discriminant | `src/core/runbook/` | 9.76.0 |
21
+ | calling ANOTHER registered tool from inside a tool's `execute` — composition over the agent's own dispatch map instead of importing the module and building a second query stack | `agentToolDispatch` + `ctx.tools` (ToolDispatch has/call) — sees static and skill-carried tools, NEVER ToolProvider-delivered ones (no build-time list, the 9.72.0 caveat); inner calls get the outer facts with hasArtifacts false and a derived toolCallId, `needs` resolved fail-closed non-interactively, `checkIn` and `wants` tools refused by name, no nested dispatch; declare ingredients via `composedOf` (and `gates` for a pausing procedure) — both travel MCP `_meta` | `src/core/agent/toolDispatch.ts` | 9.76.0 |
20
22
  | a tool returning numbers WITH the caveats that make them honest — interval/aggregation grain, is-it-a-counter, when the world was measured, which ground was NOT covered — as typed data the model reads compactly and the record keeps whole | `semantic()` + `tools.semantics_declared` (model sees `semanticsForModel` projection; `coverage` field absorbed by the coverage()/absent() channel) | `src/lib/semantics/` | 9.53.0 |
21
- | a build gate that refuses a triage/inventory tool that forgot its caveats, by tool name and field name | `checkSemantics` + `defineTool({ resultClass })` + bin `agentfootprint-check-semantics` | `src/lib/semantics/check.ts` | 9.53.0 |
23
+ | a build gate that refuses a triage/inventory tool that forgot its caveats, by tool name and field name | `checkSemantics` + `defineTool({ resultClass })` (`'triage'`/`'inventory'`, the closed set) + bin `agentfootprint-check-semantics` | `src/lib/semantics/check.ts` | 9.53.0 |
22
24
  | an agent that runs out of `maxIterations` mid-task handing back a HALF-SENTENCE as its answer — and nothing saying the budget ran out | `wrapUpAtMaxIterations` (default ON) + `WRAP_UP_INSTRUCTION` + `agent.budget_exhausted` + `stoppedEarly.wrappedUp` | `src/core/agent/stages/wrapUp.ts` | 9.56.0 |
25
+ | the conversation outgrowing the context window — dropping, summarizing or token-budgeting old turns, every removal on the record (the three refusal rows below all guard this window) | `.window()` + `slidingWindow` / `summarizeOldest` (= `.compaction()`) / `tokenBudget` + `keepRecentTurns` (default 6) + `thresholdTokens` (required, deliberately no default) + `retain: 'conversation'` (default) / `'discard'` | `src/core/agent/window/` | 7.17.0 |
23
26
  | keeping the user's own request in context while the window shrinks — the task's anchor, un-droppable by every window strategy including one you wrote | `'current-request'` refusal + `currentRequestIndexOf` + `WindowStrategyInput.currentRequestIndex` | `src/core/agent/window/currentRequest.ts` | 9.55.0 |
24
- | the window evicting the EVIDENCE while keeping the task — the tool result carrying the only valid ids leaves, and the model invents one that has never existed | `keepLastToolResults` (default 2) + `'last-tool-result'` refusal + `toolResultPinsOf` + `WindowRecord.observations` (what was kept, and its exact char cost) | `src/core/agent/window/lastToolResult.ts` | 9.57.0 |
27
+ | the window evicting the EVIDENCE while keeping the task — the tool result carrying the only valid ids leaves, and the model invents one that has never existed | `keepLastToolResults` (default 2; `0`/`false` disables) + `'last-tool-result'` refusal + `toolResultPinsOf` + `WindowRecord.observations` (what was kept, and its exact char cost) | `src/core/agent/window/lastToolResult.ts` | 9.57.0 |
25
28
  | telling the model WHICH tools' results a drop took, so it re-calls instead of reconstructing from memory — and filing the same fact on the record even when no notice was authored | `droppedToolNames` + the notice's tool sentence + `WindowRecord.droppedObservations` | `src/core/agent/window/toolNames.ts` | 9.57.0 |
26
- | an instruction that SAYS a run-time number rather than only gating on it ("you are on action 25 of 30") — with the library owning absence, so never "23 of undefined" and never a fabricated zero | `promptTemplate` + the closed `TEMPLATE_FACTS` vocabulary + `skipped: 'unknown-fact'` + `Injection.templated` | `src/lib/injection-engine/promptTemplate.ts` | 9.57.0 |
29
+ | an instruction that SAYS a run-time number rather than only gating on it ("you are on action 25 of 30") — with the library owning absence, so never "23 of undefined" and never a fabricated zero | `promptTemplate` + the closed `TEMPLATE_FACTS` vocabulary (`action`/`actionBudget`/`actionsRemaining`) + `skipped: 'unknown-fact'` + `Injection.templated` | `src/lib/injection-engine/promptTemplate.ts` | 9.57.0 |
27
30
  | an injection predicate that can see how much of the action budget is left | `InjectionContext.maxIterations` / `.iterationsRemaining` + `iterationsRemainingOf` (the ONE denominator, shared with the cache decision) | `src/lib/iterationBudget.ts` | 9.57.0 |
28
31
  | report progress from inside a tool — "hop 3 of 12 done", said mid-call while a long-running `execute` is still working (the record was otherwise atomic: tool_start, silence, tool_end) | `ctx.progress` + `agentfootprint.stream.tool_progress` | `src/core/tools.ts` | 9.52.0 |
29
- | show tool progress to the user — a mid-call report reaching the live status line / chat bubble, not just the record (`message` shown verbatim, capped; otherwise an honest generic line, never a payload dump) | `selectStatus` + `progressMessageOf` + `tool.progress` templates | `src/recorders/observability/status/statusTemplates.ts` | 9.54.0 |
32
+ | show tool progress to the user — a mid-call report reaching the live status line / chat bubble, not just the record (`message` shown verbatim, capped at 120 chars with the cut stated; otherwise an honest generic line, never a payload dump) | `selectStatus` + `progressMessageOf` + `tool.progress` templates | `src/recorders/observability/status/statusTemplates.ts` | 9.54.0 |
30
33
  | declaring which skills connect — the SkillMap as one named thing (the agent that mounts it is the SkillWalker; there is deliberately no walker class) | `defineSkillMap` + `SkillMap` (permanent reference-equal aliases of `skillGraph`/`SkillGraph`) | `src/lib/injection-engine/skillGraph.ts` | 9.51.0 |
31
- | guarding a skill transition on state or a tool result's fields — a route condition as DATA (comparable, drawable, evidence-recorded), not an opaque predicate | `guard:` + `compileGuard` + `guard-unsatisfiable` | `src/lib/injection-engine/skillGuard.ts` | 9.51.0 |
34
+ | guarding a skill transition on state or a tool result's fields — a route condition as DATA (comparable, drawable, evidence-recorded), not an opaque predicate | `guard:` + `compileGuard` (ops `'eq'`/`'ne'`/`'gt'`/`'gte'`/`'lt'`/`'lte'`/`'in'`/`'notIn'`) + `guard-unsatisfiable` | `src/lib/injection-engine/skillGuard.ts` | 9.51.0 |
32
35
  | seeing the skill map in a recording — the author's nodes + edges (guards included) as DATA, never parsed from prose or inferred from fired hops | `skill.graph_declared` + `buildSkillGraphDeclared` | `src/core/agent/skillGraphDeclared.ts` | 9.50.0 |
33
36
  | "where could the run go next?" — the reachable skill set at every cursor move, typed on the move itself | `cursorMove.reachable` + `reachableSkills` | `src/lib/injection-engine/buildInjectionEngineSubflow.ts` | 9.50.0 |
34
37
  | putting the ASSEMBLED system prompt in the recording — the exact string the model read (opt-in; default OFF is a privacy decision) | `recordSystemPrompt` | `src/core/agent/types.ts` | 9.50.0 |
35
- | a typed HITL prompt — let a person pick from a list, choose a range, use a real control instead of typing prose | `AskComponent` | `src/core/askComponent.ts` | 9.24.0 |
36
- | carrying WHAT the person chose back, with what they could see | `DecisionValue` | `src/core/checkin.ts` | 9.47.0 |
37
- | archiving a finished run — filing it, attaching it to a bug report, feeding it to an analysis tool | `persistRecording` + `RecordingEnvelope` | `src/recorders/observability/recordingEnvelope.ts` | 9.48.0 |
38
- | packaging a run for a HUMAN to file — a zip whose evidence is the archive envelope, plus host facts and a readable transcript | `exportBugReport` | `src/lib/bug-report/build.ts` | — |
38
+ | a typed HITL prompt — let a person pick from a list, choose a range, use a real control instead of typing prose | `AskComponent` + `componentId` (consumer-registered vocabulary, opaque here) + inline `props` + `propsRef` (artifact claim ticket for the big half) | `src/core/askComponent.ts` | 9.24.0 |
39
+ | carrying WHAT the person chose back, with what they could see | `DecisionValue` (`kind` / `value` / `from?` + `coverage {seen, total, filter?}`) | `src/core/checkin.ts` | 9.47.0 |
40
+ | archiving a finished run — filing it, attaching it to a bug report, feeding it to an analysis tool | `persistRecording` + `RecordingEnvelope` + `run.complete` (required) + `privacy.mode` (`'full'` today; `'structure-only'`/`'redacted'` refuse by name) | `src/recorders/observability/recordingEnvelope.ts` | 9.48.0 |
41
+ | packaging a run for a HUMAN to file — a zip whose evidence is the archive envelope, plus host facts and a readable transcript | `exportBugReport` + `include` (the consent seam; left-out units are counted in `manifest.excluded`) + `warnOverBytes` (default 20 MB) | `src/lib/bug-report/build.ts` | — |
39
42
  | writing archived runs somewhere — a directory, one JSON file per run | `fileRecordingSink` + `RecordingSink` | `src/recorders/observability/fileRecordingSink.ts` | 9.48.0 |
40
43
  | declaring an agent's whole setup as one named, versioned thing — a preset, a template, a blueprint, "the support agent we all use" | `defineAgentRecipe` + `AgentBuilder.recipe()` | `src/recipes/` | 9.48.0 |
41
44
  | naming your own branches and nodes — which prefix is reserved, and telling framework plumbing from consumer structure in a trace | `RESERVED_SUBFLOW_PREFIX` + `isReservedSubflowSegment` | `src/conventions.ts` | 9.49.0 |
42
- | keeping a large tool result out of the model's context | `artifacts` + `wants` + `placement` | `src/artifacts/` | 9.21.0 |
45
+ | keeping a large tool result out of the model's context | `artifacts` (bare store, or `{ store, placement: { maxInlineChars }, recordings }` — `placement` omitted ⇒ never placed; `recordings: true` / `{ label }`, default off) + `wants` + `placement` | `src/artifacts/` | 9.21.0 |
43
46
  | the ticket placement just minted being REFUSED by your own `wants` argument as a kind mismatch — because the mint says `tool-result/<toolName>` and your consumer says `dataset/rows` | `Tool.resultKind` + `placedResultKind(toolName, declared?)` (the mint speaks the consumer's vocabulary; the exact-match matcher is untouched) | `src/artifacts/placement.ts` | 9.70.0 |
44
47
  | letting the UI draw an artifact without the model naming a component | `registerArtifactComponent` (in the `agentfootprint-lens` package) | — | — |
45
48
  | finding which tools the model keeps writing by hand | `agentfootprint.tools.code_run` + `codeShape` | `src/core/codeRunnerTool.ts` | 9.46.0 |
46
- | a skill wrongly activated by a keyword staying loaded for the whole turn — suspending/parking a map's prompt + tools when its contribution goes unused, WITHOUT touching its cursor, and re-engaging it on evidence | `.maps()` + `advanceEngagement` + `agentfootprint.map.engaged/parked` + skip reason `'parked'` | `src/maps/` | 9.58.0 |
49
+ | a skill wrongly activated by a keyword staying loaded for the whole turn — suspending/parking a map's prompt + tools when its contribution goes unused, WITHOUT touching its cursor, and re-engaging it on evidence | `.maps({ renewalGrace })` (default 3) + `MountedMap.nonParkable` + `advanceEngagement` + `agentfootprint.map.engaged/parked` + skip reason `'parked'` | `src/maps/` | 9.58.0 |
47
50
  | a value that must say how it knows itself — an unknown count that can never render as zero | `Claim<T>` (`known`/`unknown`/`notApplicable`) | `src/lib/claim/claim.ts` | 9.58.0 |
48
51
  | asking a debugging model "what did this run contradict itself about, and why?" — the Context Integrity findings, joined to the step that filed them | `find_context_errors` | `src/lib/trace-toolpack/traceToolpack.ts` | 9.61.0 |
52
+ | the model inventing an id or a reading that no tool ever returned — a deterministic fabrication detector on the final answer, with a posture for how hard it pushes back | `.namesAndNumbersFromEvidence()` + `posture` (`'assist'` record+flag, the default / `'guard'` one revision then ship flagged / `'rails'` refuse instead) + `shapes` + `exempt` + `minDigits` (default 4) + `nudge` (default off) | `src/core/agent/evidence/` | 9.35.0 |
49
53
  | counting a HUMAN-VERIFIED value as ground for the choice-seam check — the person clicked a row, the app verified the cells against the artifact, and the id the model takes from that selection is not fabricated; the source label travels onto the record | `externalGrounds` + `ExternalGround` + `external_ground_used` | `src/integrity/unsupported-argument/check.ts` | 9.72.0 |
50
- | a model head-mathing a total from tool-result numbers while a compute tool sits unused on the wire — a LATE line each iteration naming the staged refs and the `wants` tool that spends them (recency working FOR the instruction), plus the revise correction naming the same route | `nudge: true` + `stagedRefsNudgeLine` + `findStagedRefs` + `grounding_nudged` | `src/core/agent/stagedRefs.ts` | 9.75.0 |
51
- | a tool answering "I looked and found nothing", routably | `absent` | `src/core/agent/coverage/absent.ts` | 9.43.0 |
52
- | stating what a clean answer does NOT rule out | `coverage` | `src/core/agent/coverage/ledger.ts` | 9.43.0 |
54
+ | a model head-mathing a total from tool-result numbers while a compute tool sits unused on the wire — a LATE line each iteration naming the staged refs and the `wants` tool that spends them (recency working FOR the instruction), plus the revise correction naming the same route | `nudge: true` (default off) + `stagedRefsNudgeLine` + `findStagedRefs` + `grounding_nudged` | `src/core/agent/stagedRefs.ts` | 9.75.0 |
55
+ | a tool answering "I looked and found nothing", routably | `absent` + `looked_for` + `checked`/`not_checked`/`cannot_cover` + `tryInstead` (delivered status `'absent'`, routable by `onToolStatus`) | `src/core/agent/coverage/absent.ts` | 9.43.0 |
56
+ | stating what a clean answer does NOT rule out | `coverage` + the declaration `{ checked, not_checked?, cannot_cover? }` | `src/core/agent/coverage/ledger.ts` | 9.43.0 |
53
57
  | minting one of those shapes from a tool that is NOT JavaScript — the canonical note sentences and reserved marker keys as DATA, so a Python/Go/Rust sidecar reads a file instead of regex-scraping `dist/esm` (which a consumer really did) | `canonical-notes.json` at the package root + the `./canonical-notes.json` exports entry, GENERATED from the built barrel by `scripts/gen-canonical-notes.mjs` | `scripts/gen-canonical-notes.mjs` | 9.70.0 |
54
- | proving a session store really honours the port | `runSessionLifecycleConformance` | `src/hosting/conformance/` | 9.37.0 |
58
+ | proving a session store really honours the port | `runSessionLifecycleConformance` + `declared` skips (by case name WITH the reason; a declared case still RUNS) + outcomes `'passed'`/`'not-applicable'`/`'declared'`/`'failed'` | `src/hosting/conformance/` | 9.37.0 |
55
59
  | deciding who owns a contested session write | `resolveSessionOwner` | `src/hosting/sessionOwnership.ts` | 9.37.0 |
56
- | making a caller-supplied id safe for a backend | `encodeIdentityField` | `src/memory/identity/encode.ts` | 9.40.0 |
57
- | scoping a skill's tools so they reach the model only while it is active | `toolsFromActiveSkill` | `src/core/agent/toolsFromActiveSkill.ts` | 9.43.0 |
60
+ | making a caller-supplied id safe for a backend | `encodeIdentityField` | `src/memory/identity/encode.ts` | 9.37.0 |
61
+ | scoping a skill's tools so they reach the model only while it is active | `toolsFromActiveSkill` + a no-arg posture (default off) + the stamp `autoActivate: 'currentSkill'` (a default, never an override) | `src/core/agent/toolsFromActiveSkill.ts` | 9.36.0 |
58
62
  | subscribing to every event in one domain at once | `DomainWildcard` | `src/events/dispatcher.ts` | 9.4.0 |
59
- | pausing a run for a person and resuming it later | `checkInApproved` / `checkInDeclined` | `src/core/checkin.ts` | 9.24.0 |
63
+ | pausing a run for a person and resuming it later | `checkInApproved` / `checkInDeclined` (`{ by, note?, value? }`; a decline is NOT an abort — the model gets a "declined by human" tool result and adapts in-loop) | `src/core/checkin.ts` | 7.5.0 |
60
64
 
61
65
  **One law before you add a mapping.** Any function turning caller data into a KEY,
62
66
  a namespace, a filename or an index entry must be injective, and its collision
@@ -11,7 +11,7 @@
11
11
  * this folder for the one-job map and the import direction.
12
12
  */
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.placedToolResult = exports.placedResultKind = exports.isPlacedToolResult = exports.assertArtifactPlacement = exports.runArtifactStoreConformance = exports.runArtifactStoreCase = exports.formatArtifactStoreReport = exports.artifactStoreConformance = exports.UnserializableRecordingError = exports.RECORDING_MEDIA_TYPE = exports.RECORDING_ARTIFACT_KIND = exports.recordingPutInput = exports.presentArtifact = exports.PRESENT_TOOL_NAME = exports.wantsNeedsStoreRefusal = exports.resolveToolWants = exports.assertToolWants = exports.unconfiguredArtifacts = exports.bindArtifacts = exports.collectStream = exports.canStreamArtifacts = exports.canPutArtifactStream = exports.canGetArtifactStream = exports.bytesAsStream = exports.assertStreamBytes = exports.gcsArtifacts = exports.s3Artifacts = exports.UnreadableArtifactStoreError = exports.sqliteArtifacts = exports.UnreadableArtifactFileError = exports.fileArtifacts = exports.DEFAULT_IN_MEMORY_ARTIFACT_RETENTION = exports.inMemoryArtifacts = exports.mintArtifactRef = exports.isArtifactRef = exports.ARTIFACT_REF_PREFIX = exports.UnknownParentRefError = exports.InvalidArtifactError = exports.ArtifactIntegrityError = void 0;
14
+ exports.placedToolResult = exports.placedResultKind = exports.isPlacedToolResult = exports.assertArtifactPlacement = exports.runArtifactStoreConformance = exports.runArtifactStoreCase = exports.formatArtifactStoreReport = exports.artifactStoreConformance = exports.UnserializableRecordingError = exports.chartWalkPutInput = exports.CHART_WALK_ARTIFACT_KIND = exports.RECORDING_MEDIA_TYPE = exports.RECORDING_ARTIFACT_KIND = exports.recordingPutInput = exports.presentArtifact = exports.PRESENT_TOOL_NAME = exports.wantsNeedsStoreRefusal = exports.resolveToolWants = exports.assertToolWants = exports.unconfiguredArtifacts = exports.bindArtifacts = exports.collectStream = exports.canStreamArtifacts = exports.canPutArtifactStream = exports.canGetArtifactStream = exports.bytesAsStream = exports.assertStreamBytes = exports.gcsArtifacts = exports.s3Artifacts = exports.UnreadableArtifactStoreError = exports.sqliteArtifacts = exports.UnreadableArtifactFileError = exports.fileArtifacts = exports.DEFAULT_IN_MEMORY_ARTIFACT_RETENTION = exports.inMemoryArtifacts = exports.mintArtifactRef = exports.isArtifactRef = exports.ARTIFACT_REF_PREFIX = exports.UnknownParentRefError = exports.InvalidArtifactError = exports.ArtifactIntegrityError = void 0;
15
15
  var types_js_1 = require("./types.js");
16
16
  Object.defineProperty(exports, "ArtifactIntegrityError", { enumerable: true, get: function () { return types_js_1.ArtifactIntegrityError; } });
17
17
  Object.defineProperty(exports, "InvalidArtifactError", { enumerable: true, get: function () { return types_js_1.InvalidArtifactError; } });
@@ -54,6 +54,8 @@ var recordingArtifact_js_1 = require("./recordingArtifact.js");
54
54
  Object.defineProperty(exports, "recordingPutInput", { enumerable: true, get: function () { return recordingArtifact_js_1.recordingPutInput; } });
55
55
  Object.defineProperty(exports, "RECORDING_ARTIFACT_KIND", { enumerable: true, get: function () { return recordingArtifact_js_1.RECORDING_ARTIFACT_KIND; } });
56
56
  Object.defineProperty(exports, "RECORDING_MEDIA_TYPE", { enumerable: true, get: function () { return recordingArtifact_js_1.RECORDING_MEDIA_TYPE; } });
57
+ Object.defineProperty(exports, "CHART_WALK_ARTIFACT_KIND", { enumerable: true, get: function () { return recordingArtifact_js_1.CHART_WALK_ARTIFACT_KIND; } });
58
+ Object.defineProperty(exports, "chartWalkPutInput", { enumerable: true, get: function () { return recordingArtifact_js_1.chartWalkPutInput; } });
57
59
  Object.defineProperty(exports, "UnserializableRecordingError", { enumerable: true, get: function () { return recordingArtifact_js_1.UnserializableRecordingError; } });
58
60
  // The battery a store must pass to CLAIM the port, exported beside the port
59
61
  // itself so an out-of-tree store imports the check the same way it imports the
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAEH,uCAkBoB;AAjBlB,kHAAA,sBAAsB,OAAA;AACtB,gHAAA,oBAAoB,OAAA;AACpB,iHAAA,qBAAqB,OAAA;AAgBvB,yCAAkF;AAAzE,gHAAA,mBAAmB,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,4GAAA,eAAe,OAAA;AAE5D,+DAKgC;AAJ9B,yHAAA,iBAAiB,OAAA;AACjB,4IAAA,oCAAoC,OAAA;AAItC,uDAI4B;AAH1B,iHAAA,aAAa,OAAA;AACb,+HAAA,2BAA2B,OAAA;AAG7B,2DAK8B;AAJ5B,qHAAA,eAAe,OAAA;AACf,kIAAA,4BAA4B,OAAA;AAI9B,mDAAwE;AAA/D,6GAAA,WAAW,OAAA;AACpB,qDAA2E;AAAlE,+GAAA,YAAY,OAAA;AACrB,+CAUwB;AATtB,iHAAA,iBAAiB,OAAA;AACjB,6GAAA,aAAa,OAAA;AACb,oHAAA,oBAAoB,OAAA;AACpB,oHAAA,oBAAoB,OAAA;AACpB,kHAAA,kBAAkB,OAAA;AAClB,6GAAA,aAAa,OAAA;AAKf,iDAUyB;AATvB,8GAAA,aAAa,OAAA;AACb,sHAAA,qBAAqB,OAAA;AASvB,uCAOoB;AANlB,2GAAA,eAAe,OAAA;AACf,4GAAA,gBAAgB,OAAA;AAChB,kHAAA,sBAAsB,OAAA;AAKxB,2CAMsB;AALpB,+GAAA,iBAAiB,OAAA;AACjB,6GAAA,eAAe,OAAA;AAKjB,+DAMgC;AAL9B,yHAAA,iBAAiB,OAAA;AACjB,+HAAA,uBAAuB,OAAA;AACvB,4HAAA,oBAAoB,OAAA;AACpB,oIAAA,4BAA4B,OAAA;AAG9B,4EAA4E;AAC5E,+EAA+E;AAC/E,6EAA6E;AAC7E,mCAAmC;AACnC,mDAagC;AAZ9B,oHAAA,wBAAwB,OAAA;AACxB,qHAAA,yBAAyB,OAAA;AACzB,gHAAA,oBAAoB,OAAA;AACpB,uHAAA,2BAA2B,OAAA;AAU7B,+CAOwB;AANtB,uHAAA,uBAAuB,OAAA;AACvB,kHAAA,kBAAkB,OAAA;AAClB,gHAAA,gBAAgB,OAAA;AAChB,gHAAA,gBAAgB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/artifacts/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAEH,uCAkBoB;AAjBlB,kHAAA,sBAAsB,OAAA;AACtB,gHAAA,oBAAoB,OAAA;AACpB,iHAAA,qBAAqB,OAAA;AAgBvB,yCAAkF;AAAzE,gHAAA,mBAAmB,OAAA;AAAE,0GAAA,aAAa,OAAA;AAAE,4GAAA,eAAe,OAAA;AAE5D,+DAKgC;AAJ9B,yHAAA,iBAAiB,OAAA;AACjB,4IAAA,oCAAoC,OAAA;AAItC,uDAI4B;AAH1B,iHAAA,aAAa,OAAA;AACb,+HAAA,2BAA2B,OAAA;AAG7B,2DAK8B;AAJ5B,qHAAA,eAAe,OAAA;AACf,kIAAA,4BAA4B,OAAA;AAI9B,mDAAwE;AAA/D,6GAAA,WAAW,OAAA;AACpB,qDAA2E;AAAlE,+GAAA,YAAY,OAAA;AACrB,+CAUwB;AATtB,iHAAA,iBAAiB,OAAA;AACjB,6GAAA,aAAa,OAAA;AACb,oHAAA,oBAAoB,OAAA;AACpB,oHAAA,oBAAoB,OAAA;AACpB,kHAAA,kBAAkB,OAAA;AAClB,6GAAA,aAAa,OAAA;AAKf,iDAUyB;AATvB,8GAAA,aAAa,OAAA;AACb,sHAAA,qBAAqB,OAAA;AASvB,uCAOoB;AANlB,2GAAA,eAAe,OAAA;AACf,4GAAA,gBAAgB,OAAA;AAChB,kHAAA,sBAAsB,OAAA;AAKxB,2CAMsB;AALpB,+GAAA,iBAAiB,OAAA;AACjB,6GAAA,eAAe,OAAA;AAKjB,+DASgC;AAR9B,yHAAA,iBAAiB,OAAA;AACjB,+HAAA,uBAAuB,OAAA;AACvB,4HAAA,oBAAoB,OAAA;AACpB,gIAAA,wBAAwB,OAAA;AACxB,yHAAA,iBAAiB,OAAA;AACjB,oIAAA,4BAA4B,OAAA;AAI9B,4EAA4E;AAC5E,+EAA+E;AAC/E,6EAA6E;AAC7E,mCAAmC;AACnC,mDAagC;AAZ9B,oHAAA,wBAAwB,OAAA;AACxB,qHAAA,yBAAyB,OAAA;AACzB,gHAAA,oBAAoB,OAAA;AACpB,uHAAA,2BAA2B,OAAA;AAU7B,+CAOwB;AANtB,uHAAA,uBAAuB,OAAA;AACvB,kHAAA,kBAAkB,OAAA;AAClB,gHAAA,gBAAgB,OAAA;AAChB,gHAAA,gBAAgB,OAAA"}
@@ -33,10 +33,18 @@
33
33
  * than at whatever reads it next.
34
34
  */
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.recordingPutInput = exports.UnserializableRecordingError = exports.RECORDING_MEDIA_TYPE = exports.RECORDING_ARTIFACT_KIND = void 0;
36
+ exports.chartWalkPutInput = exports.recordingPutInput = exports.UnserializableRecordingError = exports.RECORDING_MEDIA_TYPE = exports.CHART_WALK_ARTIFACT_KIND = exports.RECORDING_ARTIFACT_KIND = void 0;
37
37
  /** The consumer vocabulary a run recording is stored under. One kind, exact
38
38
  * match — the same rule every `wants` declaration is judged by. */
39
39
  exports.RECORDING_ARTIFACT_KIND = 'recording/run';
40
+ /**
41
+ * The consumer vocabulary a chart WALK is stored under (9.76.0) — one row per
42
+ * execution step of a runbook's inner chart, with the decider evidence
43
+ * sentences in the `condition` rows. Namespaced by what it IS (`recording/…`,
44
+ * beside `recording/run`), never by what produced it: a walk is a recording
45
+ * projection, not a dataset that happens to mention stages.
46
+ */
47
+ exports.CHART_WALK_ARTIFACT_KIND = 'recording/chart-walk';
40
48
  /** The media type a recording is minted with. */
41
49
  exports.RECORDING_MEDIA_TYPE = 'application/json';
42
50
  /**
@@ -85,4 +93,42 @@ function recordingPutInput(recording, facts = {}) {
85
93
  };
86
94
  }
87
95
  exports.recordingPutInput = recordingPutInput;
96
+ /**
97
+ * Turn one chart walk into the `put` input that stores it under
98
+ * {@link CHART_WALK_ARTIFACT_KIND}.
99
+ *
100
+ * Pure, and serialized to JSON TEXT at the mint for exactly the reasons the
101
+ * run recording is (see the file header): a walk row must never be a live
102
+ * view into engine memory, and a walk JSON cannot carry could not cross any
103
+ * wire either.
104
+ *
105
+ * @throws UnserializableRecordingError when the rows cannot be
106
+ * JSON-serialized. Walk rows are projected to plain data upstream, so this
107
+ * firing means the projection let a live value through — fail at the mint,
108
+ * loudly.
109
+ */
110
+ function chartWalkPutInput(rows, facts = {}) {
111
+ let text;
112
+ try {
113
+ text = JSON.stringify(rows) ?? '';
114
+ }
115
+ catch (err) {
116
+ throw new UnserializableRecordingError(err instanceof Error ? err.message : String(err));
117
+ }
118
+ if (text === '') {
119
+ throw new UnserializableRecordingError('it serializes to nothing');
120
+ }
121
+ const origin = {
122
+ ...(facts.runId !== undefined && { runId: facts.runId }),
123
+ ...(facts.toolCallId !== undefined && { toolCallId: facts.toolCallId }),
124
+ };
125
+ return {
126
+ kind: exports.CHART_WALK_ARTIFACT_KIND,
127
+ mediaType: exports.RECORDING_MEDIA_TYPE,
128
+ data: text,
129
+ label: facts.label ?? (facts.toolName !== undefined ? `${facts.toolName} walk` : 'chart walk'),
130
+ ...(Object.keys(origin).length > 0 && { origin }),
131
+ };
132
+ }
133
+ exports.chartWalkPutInput = chartWalkPutInput;
88
134
  //# sourceMappingURL=recordingArtifact.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"recordingArtifact.js","sourceRoot":"","sources":["../../src/artifacts/recordingArtifact.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;;;AAIH;oEACoE;AACvD,QAAA,uBAAuB,GAAG,eAAe,CAAC;AAEvD,iDAAiD;AACpC,QAAA,oBAAoB,GAAG,kBAAkB,CAAC;AAoBvD;;;;;GAKG;AACH,MAAa,4BAA6B,SAAQ,KAAK;IAC5C,IAAI,GAAG,8BAAuC,CAAC;IAExD,YAAY,MAAc;QACxB,KAAK,CACH,0DAA0D,MAAM,mBAAmB;YACjF,kFAAkF;YAClF,oFAAoF;YACpF,kFAAkF,CACrF,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,8BAA8B,CAAC;IAC7C,CAAC;CACF;AAZD,oEAYC;AAED;;;;;;;;GAQG;AACH,SAAgB,iBAAiB,CAC/B,SAAkB,EAClB,QAA4B,EAAE;IAE9B,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACzC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,4BAA4B,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3F,CAAC;IACD,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,4BAA4B,CAAC,0BAA0B,CAAC,CAAC;IACrE,CAAC;IACD,OAAO;QACL,IAAI,EAAE,+BAAuB;QAC7B,SAAS,EAAE,4BAAoB;QAC/B,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,eAAe,CAAC;QAC1F,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;KACrE,CAAC;AACJ,CAAC;AApBD,8CAoBC"}
1
+ {"version":3,"file":"recordingArtifact.js","sourceRoot":"","sources":["../../src/artifacts/recordingArtifact.ts"],"names":[],"mappings":"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"}
@@ -2902,6 +2902,36 @@ class Agent extends RunnerBase_js_1.RunnerBase {
2902
2902
  }
2903
2903
  }
2904
2904
  }
2905
+ // The composedOf drift gate (9.76.0), judged HERE and not at defineTool —
2906
+ // the one moment the catalog is complete. A tool that declares its
2907
+ // ingredients (`composedOf`, the runbookAsTool law) whose ingredient was
2908
+ // renamed or never registered fails the BUILD by name, instead of failing
2909
+ // its first run inside a stage. Tools delivered by a ToolProvider are
2910
+ // invisible to this check (no build-time list — the 9.72.0 caveat), so
2911
+ // with a provider configured an unmatched name is a dev-mode heads-up
2912
+ // rather than a refusal: the ingredient may genuinely arrive at dispatch.
2913
+ for (const [composedName, registered] of registryByName) {
2914
+ for (const ingredient of registered.composedOf ?? []) {
2915
+ if (registryByName.has(ingredient))
2916
+ continue;
2917
+ if (this.externalToolProvider !== undefined) {
2918
+ if ((0, footprintjs_2.isDevMode)()) {
2919
+ // eslint-disable-next-line no-console
2920
+ console.warn(`[agentfootprint] tool '${composedName}' declares composedOf ingredient ` +
2921
+ `'${ingredient}', which is not in the static catalog. A ToolProvider is ` +
2922
+ `configured, so it may arrive at dispatch — but provider-delivered tools ` +
2923
+ `cannot be drift-checked at build. If '${ingredient}' is static, this is ` +
2924
+ `the rename the check exists to catch.`);
2925
+ }
2926
+ continue;
2927
+ }
2928
+ throw new Error(`Agent: tool '${composedName}' declares composedOf ingredient '${ingredient}', ` +
2929
+ `but no tool of that name is registered on this agent. The declaration names ` +
2930
+ `the tools its procedure calls through ctx.tools, and an ingredient that is ` +
2931
+ `not in the dispatch map fails at its first inner call — refused at build ` +
2932
+ `instead. Register '${ingredient}' (or fix the name in composedOf).`);
2933
+ }
2934
+ }
2905
2935
  // Late-bind toolSchemas into the seed stage's deps (the factory was
2906
2936
  // built earlier with a getter; this resolves the actual value).
2907
2937
  toolSchemasResolved = toolSchemas;