agentfootprint 9.86.0 → 9.87.1

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 (299) hide show
  1. package/CHANGELOG.md +319 -8
  2. package/README.md +14 -0
  3. package/canonical-notes.json +1 -1
  4. package/dist/artifacts/placement.js +4 -0
  5. package/dist/artifacts/placement.js.map +1 -1
  6. package/dist/artifacts/present.js +6 -0
  7. package/dist/artifacts/present.js.map +1 -1
  8. package/dist/artifacts/wants.js +8 -0
  9. package/dist/artifacts/wants.js.map +1 -1
  10. package/dist/core/Agent.js +21 -7
  11. package/dist/core/Agent.js.map +1 -1
  12. package/dist/core/LLMCall.js +2 -1
  13. package/dist/core/LLMCall.js.map +1 -1
  14. package/dist/core/agent/buildMessageApiChart.js +2 -1
  15. package/dist/core/agent/buildMessageApiChart.js.map +1 -1
  16. package/dist/core/agent/buildToolRegistry.js +4 -0
  17. package/dist/core/agent/buildToolRegistry.js.map +1 -1
  18. package/dist/core/agent/coverage/answer.js +4 -0
  19. package/dist/core/agent/coverage/answer.js.map +1 -1
  20. package/dist/core/agent/coverage/ledger.js +8 -2
  21. package/dist/core/agent/coverage/ledger.js.map +1 -1
  22. package/dist/core/agent/evidence/evidenceIndex.js +3 -0
  23. package/dist/core/agent/evidence/evidenceIndex.js.map +1 -1
  24. package/dist/core/agent/evidence/gate.js +3 -0
  25. package/dist/core/agent/evidence/gate.js.map +1 -1
  26. package/dist/core/agent/outputEnforcement.js +3 -0
  27. package/dist/core/agent/outputEnforcement.js.map +1 -1
  28. package/dist/core/agent/presentTool.js +3 -0
  29. package/dist/core/agent/presentTool.js.map +1 -1
  30. package/dist/core/agent/repeatedCall.js +3 -0
  31. package/dist/core/agent/repeatedCall.js.map +1 -1
  32. package/dist/core/agent/resultCeiling.js +3 -0
  33. package/dist/core/agent/resultCeiling.js.map +1 -1
  34. package/dist/core/agent/selfCallNotice.js +5 -0
  35. package/dist/core/agent/selfCallNotice.js.map +1 -1
  36. package/dist/core/agent/stagedRefs.js +5 -0
  37. package/dist/core/agent/stagedRefs.js.map +1 -1
  38. package/dist/core/agent/stages/callLLM.js +9 -0
  39. package/dist/core/agent/stages/callLLM.js.map +1 -1
  40. package/dist/core/agent/stages/evidenceRecheck.js +6 -0
  41. package/dist/core/agent/stages/evidenceRecheck.js.map +1 -1
  42. package/dist/core/agent/stages/stepNudge.js +5 -0
  43. package/dist/core/agent/stages/stepNudge.js.map +1 -1
  44. package/dist/core/agent/stages/toolCalls.js +136 -20
  45. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  46. package/dist/core/agent/stages/wrapUp.js +19 -4
  47. package/dist/core/agent/stages/wrapUp.js.map +1 -1
  48. package/dist/core/agent/window/notice.js +6 -0
  49. package/dist/core/agent/window/notice.js.map +1 -1
  50. package/dist/core/agent/window/summarize.js +4 -0
  51. package/dist/core/agent/window/summarize.js.map +1 -1
  52. package/dist/core/runbook/recording.js +3 -2
  53. package/dist/core/runbook/recording.js.map +1 -1
  54. package/dist/core/runbook/verdicts.js +3 -0
  55. package/dist/core/runbook/verdicts.js.map +1 -1
  56. package/dist/core/slots/buildToolsSlot.js +11 -0
  57. package/dist/core/slots/buildToolsSlot.js.map +1 -1
  58. package/dist/esm/artifacts/placement.js +4 -0
  59. package/dist/esm/artifacts/placement.js.map +1 -1
  60. package/dist/esm/artifacts/present.js +6 -0
  61. package/dist/esm/artifacts/present.js.map +1 -1
  62. package/dist/esm/artifacts/wants.js +8 -0
  63. package/dist/esm/artifacts/wants.js.map +1 -1
  64. package/dist/esm/core/Agent.js +21 -7
  65. package/dist/esm/core/Agent.js.map +1 -1
  66. package/dist/esm/core/LLMCall.js +2 -1
  67. package/dist/esm/core/LLMCall.js.map +1 -1
  68. package/dist/esm/core/agent/buildMessageApiChart.d.ts +2 -1
  69. package/dist/esm/core/agent/buildMessageApiChart.js +2 -1
  70. package/dist/esm/core/agent/buildMessageApiChart.js.map +1 -1
  71. package/dist/esm/core/agent/buildToolRegistry.js +4 -0
  72. package/dist/esm/core/agent/buildToolRegistry.js.map +1 -1
  73. package/dist/esm/core/agent/coverage/answer.js +4 -0
  74. package/dist/esm/core/agent/coverage/answer.js.map +1 -1
  75. package/dist/esm/core/agent/coverage/ledger.d.ts +5 -0
  76. package/dist/esm/core/agent/coverage/ledger.js +8 -2
  77. package/dist/esm/core/agent/coverage/ledger.js.map +1 -1
  78. package/dist/esm/core/agent/evidence/evidenceIndex.js +3 -0
  79. package/dist/esm/core/agent/evidence/evidenceIndex.js.map +1 -1
  80. package/dist/esm/core/agent/evidence/gate.js +3 -0
  81. package/dist/esm/core/agent/evidence/gate.js.map +1 -1
  82. package/dist/esm/core/agent/outputEnforcement.js +3 -0
  83. package/dist/esm/core/agent/outputEnforcement.js.map +1 -1
  84. package/dist/esm/core/agent/presentTool.js +3 -0
  85. package/dist/esm/core/agent/presentTool.js.map +1 -1
  86. package/dist/esm/core/agent/repeatedCall.js +3 -0
  87. package/dist/esm/core/agent/repeatedCall.js.map +1 -1
  88. package/dist/esm/core/agent/resultCeiling.js +3 -0
  89. package/dist/esm/core/agent/resultCeiling.js.map +1 -1
  90. package/dist/esm/core/agent/selfCallNotice.js +5 -0
  91. package/dist/esm/core/agent/selfCallNotice.js.map +1 -1
  92. package/dist/esm/core/agent/stagedRefs.js +5 -0
  93. package/dist/esm/core/agent/stagedRefs.js.map +1 -1
  94. package/dist/esm/core/agent/stages/callLLM.js +9 -0
  95. package/dist/esm/core/agent/stages/callLLM.js.map +1 -1
  96. package/dist/esm/core/agent/stages/evidenceRecheck.js +6 -0
  97. package/dist/esm/core/agent/stages/evidenceRecheck.js.map +1 -1
  98. package/dist/esm/core/agent/stages/stepNudge.js +5 -0
  99. package/dist/esm/core/agent/stages/stepNudge.js.map +1 -1
  100. package/dist/esm/core/agent/stages/toolCalls.d.ts +16 -2
  101. package/dist/esm/core/agent/stages/toolCalls.js +136 -20
  102. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  103. package/dist/esm/core/agent/stages/wrapUp.d.ts +11 -0
  104. package/dist/esm/core/agent/stages/wrapUp.js +19 -4
  105. package/dist/esm/core/agent/stages/wrapUp.js.map +1 -1
  106. package/dist/esm/core/agent/types.d.ts +5 -4
  107. package/dist/esm/core/agent/window/notice.js +6 -0
  108. package/dist/esm/core/agent/window/notice.js.map +1 -1
  109. package/dist/esm/core/agent/window/summarize.js +4 -0
  110. package/dist/esm/core/agent/window/summarize.js.map +1 -1
  111. package/dist/esm/core/runbook/recording.js +3 -2
  112. package/dist/esm/core/runbook/recording.js.map +1 -1
  113. package/dist/esm/core/runbook/verdicts.js +3 -0
  114. package/dist/esm/core/runbook/verdicts.js.map +1 -1
  115. package/dist/esm/core/slots/buildToolsSlot.js +11 -0
  116. package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
  117. package/dist/esm/events/eventTail.js +4 -0
  118. package/dist/esm/events/eventTail.js.map +1 -1
  119. package/dist/esm/events/payloads.d.ts +8 -0
  120. package/dist/esm/index.d.ts +1 -0
  121. package/dist/esm/index.js +9 -0
  122. package/dist/esm/index.js.map +1 -1
  123. package/dist/esm/integrity/disposition/ledger.js +0 -0
  124. package/dist/esm/integrity/disposition/ledger.js.map +1 -1
  125. package/dist/esm/lib/context-ledger/contextLedger.js +3 -0
  126. package/dist/esm/lib/context-ledger/contextLedger.js.map +1 -1
  127. package/dist/esm/lib/injection-engine/evaluator.js +3 -0
  128. package/dist/esm/lib/injection-engine/evaluator.js.map +1 -1
  129. package/dist/esm/lib/injection-engine/promptTemplate.js +4 -0
  130. package/dist/esm/lib/injection-engine/promptTemplate.js.map +1 -1
  131. package/dist/esm/lib/injection-engine/skillGraph.js +17 -0
  132. package/dist/esm/lib/injection-engine/skillGraph.js.map +1 -1
  133. package/dist/esm/lib/injection-engine/skillSteps.js +26 -2
  134. package/dist/esm/lib/injection-engine/skillSteps.js.map +1 -1
  135. package/dist/esm/lib/injection-engine/skillToolDescriptors.js +26 -0
  136. package/dist/esm/lib/injection-engine/skillToolDescriptors.js.map +1 -1
  137. package/dist/esm/lib/iterationBudget.js +4 -0
  138. package/dist/esm/lib/iterationBudget.js.map +1 -1
  139. package/dist/esm/lib/rag/defineRAG.js +4 -0
  140. package/dist/esm/lib/rag/defineRAG.js.map +1 -1
  141. package/dist/esm/lib/saidByPerson.js +4 -0
  142. package/dist/esm/lib/saidByPerson.js.map +1 -1
  143. package/dist/esm/lib/semantics/envelope.js +3 -0
  144. package/dist/esm/lib/semantics/envelope.js.map +1 -1
  145. package/dist/esm/lib/spokenIds.js +5 -0
  146. package/dist/esm/lib/spokenIds.js.map +1 -1
  147. package/dist/esm/lib/time-travel/index.d.ts +8 -0
  148. package/dist/esm/lib/time-travel/index.js +9 -0
  149. package/dist/esm/lib/time-travel/index.js.map +1 -0
  150. package/dist/esm/lib/time-travel/milestoneStops.d.ts +128 -0
  151. package/dist/esm/lib/time-travel/milestoneStops.js +179 -0
  152. package/dist/esm/lib/time-travel/milestoneStops.js.map +1 -0
  153. package/dist/esm/lib/trace-toolpack/debugPrompt.js +3 -0
  154. package/dist/esm/lib/trace-toolpack/debugPrompt.js.map +1 -1
  155. package/dist/esm/lib/trace-toolpack/traceToolpack.js +26 -14
  156. package/dist/esm/lib/trace-toolpack/traceToolpack.js.map +1 -1
  157. package/dist/esm/maps/engagement/lease.js +4 -0
  158. package/dist/esm/maps/engagement/lease.js.map +1 -1
  159. package/dist/esm/maps/engagement/parkCard.js +5 -0
  160. package/dist/esm/maps/engagement/parkCard.js.map +1 -1
  161. package/dist/esm/memory/beats/formatAsNarrative.js +4 -0
  162. package/dist/esm/memory/beats/formatAsNarrative.js.map +1 -1
  163. package/dist/esm/memory/causal/loadSnapshot.js +4 -0
  164. package/dist/esm/memory/causal/loadSnapshot.js.map +1 -1
  165. package/dist/esm/memory/facts/formatFacts.js +4 -0
  166. package/dist/esm/memory/facts/formatFacts.js.map +1 -1
  167. package/dist/esm/memory/stages/formatDefault.js +4 -0
  168. package/dist/esm/memory/stages/formatDefault.js.map +1 -1
  169. package/dist/esm/recorders/observability/FlowchartRecorder.js +3 -0
  170. package/dist/esm/recorders/observability/FlowchartRecorder.js.map +1 -1
  171. package/dist/esm/recorders/observability/recordRun.js +5 -0
  172. package/dist/esm/recorders/observability/recordRun.js.map +1 -1
  173. package/dist/esm/tool-providers/gatedTools.js +7 -0
  174. package/dist/esm/tool-providers/gatedTools.js.map +1 -1
  175. package/dist/esm/tool-providers/skillScopedTools.js +6 -0
  176. package/dist/esm/tool-providers/skillScopedTools.js.map +1 -1
  177. package/dist/events/eventTail.js +4 -0
  178. package/dist/events/eventTail.js.map +1 -1
  179. package/dist/index.js +115 -102
  180. package/dist/index.js.map +1 -1
  181. package/dist/integrity/disposition/ledger.js +0 -0
  182. package/dist/integrity/disposition/ledger.js.map +1 -1
  183. package/dist/lib/context-ledger/contextLedger.js +3 -0
  184. package/dist/lib/context-ledger/contextLedger.js.map +1 -1
  185. package/dist/lib/injection-engine/evaluator.js +3 -0
  186. package/dist/lib/injection-engine/evaluator.js.map +1 -1
  187. package/dist/lib/injection-engine/promptTemplate.js +4 -0
  188. package/dist/lib/injection-engine/promptTemplate.js.map +1 -1
  189. package/dist/lib/injection-engine/skillGraph.js +17 -0
  190. package/dist/lib/injection-engine/skillGraph.js.map +1 -1
  191. package/dist/lib/injection-engine/skillSteps.js +26 -2
  192. package/dist/lib/injection-engine/skillSteps.js.map +1 -1
  193. package/dist/lib/injection-engine/skillToolDescriptors.js +26 -0
  194. package/dist/lib/injection-engine/skillToolDescriptors.js.map +1 -1
  195. package/dist/lib/iterationBudget.js +4 -0
  196. package/dist/lib/iterationBudget.js.map +1 -1
  197. package/dist/lib/rag/defineRAG.js +4 -0
  198. package/dist/lib/rag/defineRAG.js.map +1 -1
  199. package/dist/lib/saidByPerson.js +4 -0
  200. package/dist/lib/saidByPerson.js.map +1 -1
  201. package/dist/lib/semantics/envelope.js +3 -0
  202. package/dist/lib/semantics/envelope.js.map +1 -1
  203. package/dist/lib/spokenIds.js +5 -0
  204. package/dist/lib/spokenIds.js.map +1 -1
  205. package/dist/lib/time-travel/index.js +15 -0
  206. package/dist/lib/time-travel/index.js.map +1 -0
  207. package/dist/lib/time-travel/milestoneStops.js +184 -0
  208. package/dist/lib/time-travel/milestoneStops.js.map +1 -0
  209. package/dist/lib/trace-toolpack/debugPrompt.js +3 -0
  210. package/dist/lib/trace-toolpack/debugPrompt.js.map +1 -1
  211. package/dist/lib/trace-toolpack/traceToolpack.js +26 -14
  212. package/dist/lib/trace-toolpack/traceToolpack.js.map +1 -1
  213. package/dist/maps/engagement/lease.js +4 -0
  214. package/dist/maps/engagement/lease.js.map +1 -1
  215. package/dist/maps/engagement/parkCard.js +5 -0
  216. package/dist/maps/engagement/parkCard.js.map +1 -1
  217. package/dist/memory/beats/formatAsNarrative.js +4 -0
  218. package/dist/memory/beats/formatAsNarrative.js.map +1 -1
  219. package/dist/memory/causal/loadSnapshot.js +4 -0
  220. package/dist/memory/causal/loadSnapshot.js.map +1 -1
  221. package/dist/memory/facts/formatFacts.js +4 -0
  222. package/dist/memory/facts/formatFacts.js.map +1 -1
  223. package/dist/memory/stages/formatDefault.js +4 -0
  224. package/dist/memory/stages/formatDefault.js.map +1 -1
  225. package/dist/recorders/observability/FlowchartRecorder.js +3 -0
  226. package/dist/recorders/observability/FlowchartRecorder.js.map +1 -1
  227. package/dist/recorders/observability/recordRun.js +5 -0
  228. package/dist/recorders/observability/recordRun.js.map +1 -1
  229. package/dist/tool-providers/gatedTools.js +7 -0
  230. package/dist/tool-providers/gatedTools.js.map +1 -1
  231. package/dist/tool-providers/skillScopedTools.js +6 -0
  232. package/dist/tool-providers/skillScopedTools.js.map +1 -1
  233. package/dist/types/artifacts/placement.d.ts.map +1 -1
  234. package/dist/types/artifacts/present.d.ts.map +1 -1
  235. package/dist/types/artifacts/wants.d.ts.map +1 -1
  236. package/dist/types/core/Agent.d.ts.map +1 -1
  237. package/dist/types/core/LLMCall.d.ts.map +1 -1
  238. package/dist/types/core/agent/buildMessageApiChart.d.ts +2 -1
  239. package/dist/types/core/agent/buildMessageApiChart.d.ts.map +1 -1
  240. package/dist/types/core/agent/buildToolRegistry.d.ts.map +1 -1
  241. package/dist/types/core/agent/coverage/answer.d.ts.map +1 -1
  242. package/dist/types/core/agent/coverage/ledger.d.ts +5 -0
  243. package/dist/types/core/agent/coverage/ledger.d.ts.map +1 -1
  244. package/dist/types/core/agent/evidence/evidenceIndex.d.ts.map +1 -1
  245. package/dist/types/core/agent/evidence/gate.d.ts.map +1 -1
  246. package/dist/types/core/agent/outputEnforcement.d.ts.map +1 -1
  247. package/dist/types/core/agent/presentTool.d.ts.map +1 -1
  248. package/dist/types/core/agent/repeatedCall.d.ts.map +1 -1
  249. package/dist/types/core/agent/resultCeiling.d.ts.map +1 -1
  250. package/dist/types/core/agent/selfCallNotice.d.ts.map +1 -1
  251. package/dist/types/core/agent/stagedRefs.d.ts.map +1 -1
  252. package/dist/types/core/agent/stages/callLLM.d.ts.map +1 -1
  253. package/dist/types/core/agent/stages/evidenceRecheck.d.ts.map +1 -1
  254. package/dist/types/core/agent/stages/stepNudge.d.ts.map +1 -1
  255. package/dist/types/core/agent/stages/toolCalls.d.ts +16 -2
  256. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  257. package/dist/types/core/agent/stages/wrapUp.d.ts +11 -0
  258. package/dist/types/core/agent/stages/wrapUp.d.ts.map +1 -1
  259. package/dist/types/core/agent/types.d.ts +5 -4
  260. package/dist/types/core/agent/types.d.ts.map +1 -1
  261. package/dist/types/core/agent/window/notice.d.ts.map +1 -1
  262. package/dist/types/core/agent/window/summarize.d.ts.map +1 -1
  263. package/dist/types/core/runbook/recording.d.ts.map +1 -1
  264. package/dist/types/core/runbook/verdicts.d.ts.map +1 -1
  265. package/dist/types/core/slots/buildToolsSlot.d.ts.map +1 -1
  266. package/dist/types/events/eventTail.d.ts.map +1 -1
  267. package/dist/types/events/payloads.d.ts +8 -0
  268. package/dist/types/events/payloads.d.ts.map +1 -1
  269. package/dist/types/index.d.ts +1 -0
  270. package/dist/types/index.d.ts.map +1 -1
  271. package/dist/types/integrity/disposition/ledger.d.ts.map +1 -1
  272. package/dist/types/lib/context-ledger/contextLedger.d.ts.map +1 -1
  273. package/dist/types/lib/injection-engine/evaluator.d.ts.map +1 -1
  274. package/dist/types/lib/injection-engine/promptTemplate.d.ts.map +1 -1
  275. package/dist/types/lib/injection-engine/skillGraph.d.ts.map +1 -1
  276. package/dist/types/lib/injection-engine/skillSteps.d.ts.map +1 -1
  277. package/dist/types/lib/injection-engine/skillToolDescriptors.d.ts.map +1 -1
  278. package/dist/types/lib/iterationBudget.d.ts.map +1 -1
  279. package/dist/types/lib/rag/defineRAG.d.ts.map +1 -1
  280. package/dist/types/lib/saidByPerson.d.ts.map +1 -1
  281. package/dist/types/lib/semantics/envelope.d.ts.map +1 -1
  282. package/dist/types/lib/spokenIds.d.ts.map +1 -1
  283. package/dist/types/lib/time-travel/index.d.ts +9 -0
  284. package/dist/types/lib/time-travel/index.d.ts.map +1 -0
  285. package/dist/types/lib/time-travel/milestoneStops.d.ts +129 -0
  286. package/dist/types/lib/time-travel/milestoneStops.d.ts.map +1 -0
  287. package/dist/types/lib/trace-toolpack/debugPrompt.d.ts.map +1 -1
  288. package/dist/types/lib/trace-toolpack/traceToolpack.d.ts.map +1 -1
  289. package/dist/types/maps/engagement/lease.d.ts.map +1 -1
  290. package/dist/types/maps/engagement/parkCard.d.ts.map +1 -1
  291. package/dist/types/memory/beats/formatAsNarrative.d.ts.map +1 -1
  292. package/dist/types/memory/causal/loadSnapshot.d.ts.map +1 -1
  293. package/dist/types/memory/facts/formatFacts.d.ts.map +1 -1
  294. package/dist/types/memory/stages/formatDefault.d.ts.map +1 -1
  295. package/dist/types/recorders/observability/FlowchartRecorder.d.ts.map +1 -1
  296. package/dist/types/recorders/observability/recordRun.d.ts.map +1 -1
  297. package/dist/types/tool-providers/gatedTools.d.ts.map +1 -1
  298. package/dist/types/tool-providers/skillScopedTools.d.ts.map +1 -1
  299. package/package.json +4 -4
@@ -171,6 +171,9 @@ export function atMountedCursor(args) {
171
171
  }) === 'self';
172
172
  return stay && args.parked?.has(args.target) !== true;
173
173
  }
174
+ // LENS · tool-result · persistent-history
175
+ // reads: the dispatchable roster ← `toolCalls.ts` · dispatchRoster: registry ∪ provider cache, filtered through scope.hiddenSkillIds
176
+ // law: may omit, never deny; every clause anchored to the call it was composed on.
174
177
  /**
175
178
  * What a call to a name nothing can dispatch gets back (9.86.0).
176
179
  *
@@ -224,6 +227,11 @@ export function unknownToolResult(toolName, dispatchable) {
224
227
  ? head
225
228
  : `${head} No tool name resolved to an implementation on that call.`;
226
229
  }
230
+ // LENS · tool-result · persistent-history
231
+ // reads: hops/open ← deps.allowedSkillIds + deps.openSkillIds, each through scope.hiddenSkillIds via spoken()
232
+ // target class ← skillGraph.ts · classifySkillTarget, carried in, not re-derived
233
+ // menu/turnStartedBy ← scope.turnRoute (the routing verdict, whole, not a boolean)
234
+ // law: may omit, never deny; every clause anchored to the call it was composed on.
227
235
  /**
228
236
  * THE ONE COMPOSER of every `read_skill` refusal (9.86.0) — reachability,
229
237
  * posture and tree, from one set of inputs.
@@ -271,7 +279,7 @@ export function unknownToolResult(toolName, dispatchable) {
271
279
  * composers rather than re-deriving what it says.
272
280
  */
273
281
  export function composeReadSkillRefusal(args) {
274
- const { requestedId, targetClass, cursorId, hops, openIds, isTree, posture, menuOffered, routedDecisively, } = args;
282
+ const { requestedId, targetClass, cursorId, hops, openIds, isTree, posture, menuOffered, turnStartedBy, cursorWithheld, } = args;
275
283
  const head = `read_skill("${requestedId}") was not granted on that call: `;
276
284
  // Open skills are the one list every arm may name: they are admitted from
277
285
  // every cursor and no posture governs them (the posture arm below is reached
@@ -302,10 +310,23 @@ export function composeReadSkillRefusal(args) {
302
310
  return (`${head}this graph's 'guard' posture admits a routing pick only from the menu the ` +
303
311
  `framework offered, and '${requestedId}' was not admitted on that call.${openClause}`);
304
312
  }
313
+ // What the gate KNOWS about why no menu was outstanding is `TurnRoute.by`,
314
+ // and each value is a different finished fact. Nothing is asserted about
315
+ // how the cursor came to be where it was beyond that — the old tail,
316
+ // "Declared routes moved the cursor instead.", was composed for every
317
+ // value and was true of none of them in particular.
318
+ const startClause = turnStartedBy === 'entry' || turnStartedBy === 'intent'
319
+ ? " — the turn's start had already been resolved decisively"
320
+ : turnStartedBy === 'continuity'
321
+ ? ' — the cursor had been carried over from the previous turn'
322
+ : turnStartedBy === 'menu'
323
+ ? ' — the menu had already been resolved by an earlier pick'
324
+ : turnStartedBy === 'decider'
325
+ ? " — the menu had been resolved by the configured decider before the turn's first call"
326
+ : '';
305
327
  return (`${head}this graph's 'guard' posture admits a routing pick only while the framework ` +
306
328
  `has declared ambiguity, and no menu was outstanding when that call was made` +
307
- `${routedDecisively === true ? " — the turn's start had already been resolved decisively" : ''}` +
308
- `. Declared routes moved the cursor instead.${openClause}`);
329
+ `${startClause}.${openClause}`);
309
330
  }
310
331
  if (isTree === true) {
311
332
  return (`${head}this map is a decision tree. A tree routes by predicate on every iteration ` +
@@ -316,7 +337,14 @@ export function composeReadSkillRefusal(args) {
316
337
  // this arm — 'self' is answered by the notice, 'hop' and 'open' are admitted
317
338
  // — and it is carried rather than re-derived so the sentence and the verdict
318
339
  // read the same classification.
319
- const from = cursorId !== undefined ? `'${cursorId}'` : "the turn's start";
340
+ // Three anchors, not two: a named cursor, a cursor this caller may not be
341
+ // told the name of, and a genuine cold start. The middle one used to print
342
+ // the raw id — the one name the description's own law withholds.
343
+ const from = cursorId !== undefined
344
+ ? `'${cursorId}'`
345
+ : cursorWithheld === true
346
+ ? 'the skill the cursor stood in'
347
+ : "the turn's start";
320
348
  // The gate reaches this arm only with `'unreachable'`; the weaker sentence is
321
349
  // for a caller that refused an admissible class for a reason of its own, and
322
350
  // it is deliberately not an invented explanation of one.
@@ -435,6 +463,9 @@ export function buildToolCallsHandler(deps) {
435
463
  : capToolResult(values.modelResult, { toolName, maxChars: max }).value,
436
464
  };
437
465
  };
466
+ // LENS · tool-result · persistent-history
467
+ // reads: the tool's own declared resultCeiling / resultColumns ← ../resultCeiling.ts · applyResultCeiling, one owner of the measurement and the sentence
468
+ // law: may omit, never deny; every clause anchored to the call it was composed on.
438
469
  /**
439
470
  * The tool's OWN refusing ceiling (9.20.0) — ONE implementation for every
440
471
  * dispatch door, applied at the execute boundary the moment the handler's
@@ -775,6 +806,10 @@ export function buildToolCallsHandler(deps) {
775
806
  const step = currentStepOf(ptr, plan);
776
807
  return step ? { ptr, plan, step } : undefined;
777
808
  };
809
+ // LENS · tool-result · persistent-history
810
+ // reads: the advanced pointer ← pointerOf(scope.stepPointer), under `toolCalls.ts` · "── Step-procedure boundary (9.18.0)"; the sentence ← ../../lib/injection-engine/skillSteps.ts
811
+ // note: it overwrites the placeholder BEFORE the after-tool moment, so the record carries the authoritative words.
812
+ // law: may omit, never deny; every clause anchored to the call it was composed on.
778
813
  /**
779
814
  * `skip_step` bookkeeping — returns the AUTHORITATIVE result that
780
815
  * replaces the tool's placeholder (both channels, the read_skill-refusal
@@ -925,6 +960,11 @@ export function buildToolCallsHandler(deps) {
925
960
  }
926
961
  const currentSkillId = scope.currentSkillId;
927
962
  const hops = deps.allowedSkillIds(currentSkillId);
963
+ const targetClass = classifySkillTarget({
964
+ ...(currentSkillId !== undefined && { cursor: currentSkillId }),
965
+ target,
966
+ hops,
967
+ });
928
968
  // ── A PROPOSAL TO THE CURSOR'S OWN SKILL IS A STAY (9.86.0) ──────
929
969
  // `makeReachableSkills` filters the cursor out of its own successor
930
970
  // set — right for a MOVE, and this judge read it as "not reachable"
@@ -937,11 +977,47 @@ export function buildToolCallsHandler(deps) {
937
977
  // The event carries the existing `'accepted'` outcome plus an
938
978
  // ADDITIVE `stay: true`, deliberately not a new enum member: an
939
979
  // exhaustive switch over `outcome` in a consumer must keep compiling.
940
- if (classifySkillTarget({
941
- ...(currentSkillId !== undefined && { cursor: currentSkillId }),
942
- target,
943
- hops,
944
- }) === 'self') {
980
+ //
981
+ // A STAY COMPETES FOR THE SLOT LIKE ANY OTHER ACCEPTED PROPOSAL
982
+ // (9.86.1). The batch law is "first ACCEPTED proposal wins, later
983
+ // proposals to OTHER targets are superseded", and a stay is accepted
984
+ // — so a stay judged first holds the slot (with nothing written to
985
+ // `pendingToolTransition`, because a stay moves nothing) and a later
986
+ // sibling proposing a hop is `'superseded'` and lands in the
987
+ // `route_conflict` losers, exactly as two conflicting hops do. Before
988
+ // this the stay `continue`d past the bookkeeping, so the tool that
989
+ // judged its data first lost to whichever sibling came second, with
990
+ // two `'accepted'` events in one batch and no conflict on the record.
991
+ // The same law in the other order: a stay proposed AFTER an accepted
992
+ // hop is superseded by it, not accepted beside it.
993
+ if (targetClass === 'self') {
994
+ if (state.winner !== undefined && state.winner.targetSkillId !== target) {
995
+ state.losers.push({
996
+ toolCallId: call.toolCallId,
997
+ toolName: call.toolName,
998
+ target,
999
+ });
1000
+ typedEmit(scope, 'agentfootprint.tools.effect', {
1001
+ kind: 'propose-transition',
1002
+ outcome: 'superseded',
1003
+ toolName: call.toolName,
1004
+ toolCallId: call.toolCallId,
1005
+ iteration: call.iteration,
1006
+ targetSkillId: target,
1007
+ reason: effect.reason,
1008
+ supersededBy: 'earlier-proposal',
1009
+ });
1010
+ continue;
1011
+ }
1012
+ if (state.winner === undefined) {
1013
+ state.winner = {
1014
+ targetSkillId: target,
1015
+ toolName: call.toolName,
1016
+ toolCallId: call.toolCallId,
1017
+ reason: effect.reason,
1018
+ iteration: call.iteration,
1019
+ };
1020
+ }
945
1021
  typedEmit(scope, 'agentfootprint.tools.effect', {
946
1022
  kind: 'propose-transition',
947
1023
  outcome: 'accepted',
@@ -954,10 +1030,25 @@ export function buildToolCallsHandler(deps) {
954
1030
  });
955
1031
  continue;
956
1032
  }
957
- if (!hops.includes(target)) {
1033
+ if (targetClass === 'unreachable') {
1034
+ // ── THE REFUSAL SPEAKS WITH THE FILTERED SETS (9.86.1) ──────────
1035
+ // This sentence is appended to the tool result the model reads and
1036
+ // rides the `tools.effect` payload, and it named the raw hop set and
1037
+ // the raw cursor — the leak the `read_skill` refusals closed one
1038
+ // function up. Same filter, same law: the hidden set the tools slot
1039
+ // resolved for this iteration, and OMIT, NEVER DENY — a hop set the
1040
+ // filter emptied composes no reachable clause rather than an empty
1041
+ // one. Admission is still judged on the raw `hops`.
1042
+ const hiddenIds = new Set(scope.hiddenSkillIds ?? []);
1043
+ const mayName = (id) => !hiddenIds.has(id);
1044
+ const reachable = spoken(hops, mayName);
1045
+ const from = currentSkillId === undefined
1046
+ ? 'the turn start'
1047
+ : mayName(currentSkillId)
1048
+ ? `'${currentSkillId}'`
1049
+ : 'the skill the cursor stood in';
958
1050
  refuse('propose-transition', `propose-transition → '${target}' was refused: '${target}' is not reachable from ` +
959
- `${currentSkillId !== undefined ? `'${currentSkillId}'` : 'the turn start'} per ` +
960
- `the graph's own law${hops.length > 0 ? ` (reachable: ${hops.join(', ')})` : ''}. The graph decides — a proposal is evidence, never authority.`, { targetSkillId: target, reason: effect.reason });
1051
+ `${from} per the graph's own law${reachable.named.length > 0 ? ` (reachable: ${reachable.named.join(', ')})` : ''}. The graph decides — a proposal is evidence, never authority.`, { targetSkillId: target, reason: effect.reason });
961
1052
  continue;
962
1053
  }
963
1054
  if (state.winner !== undefined && state.winner.targetSkillId !== target) {
@@ -1437,6 +1528,9 @@ export function buildToolCallsHandler(deps) {
1437
1528
  // which owns the scope, the store and the emit channel — OVERWRITES its
1438
1529
  // result with the description snapshot (or the teaching refusal), so
1439
1530
  // governance rules and the caps compose over what the model will read.
1531
+ // LENS · tool-result · persistent-history
1532
+ // reads: the artifact's description snapshot ← the ArtifactStore port (src/artifacts/present.ts, the owner of head/list)
1533
+ // law: may omit, never deny; every clause anchored to the call it was composed on.
1440
1534
  const applyPresent = async (scope, call) => {
1441
1535
  const store = deps.artifactStore;
1442
1536
  if (store === undefined) {
@@ -1617,6 +1711,9 @@ export function buildToolCallsHandler(deps) {
1617
1711
  const parkedNow = (scope) => deps.engagementPlan === undefined
1618
1712
  ? undefined
1619
1713
  : parkedMemberIds(deps.engagementPlan, scope.mapEngagement);
1714
+ // FOLD · the one owner of "which tool names this caller may be told exist" for one iteration
1715
+ // consumers read this and never re-derive it: `toolCalls.ts` · unknownToolResult, called at both dispatch doors
1716
+ // detached: yes — a fresh SpokenIds; the named half leaves through spoken().
1620
1717
  /**
1621
1718
  * Every name `lookupTool` would resolve, in resolution order, through the
1622
1719
  * role filter (9.86.0) — the roster `unknownToolResult` names.
@@ -2097,6 +2194,12 @@ export function buildToolCallsHandler(deps) {
2097
2194
  ...(decision.rationale !== undefined && { rationale: decision.rationale }),
2098
2195
  ...(decision.reason !== undefined && { reason: decision.reason }),
2099
2196
  });
2197
+ // LENS · tool-result · persistent-history
2198
+ // reads: the checker's own words ← decision.tellLLM ?? decision.rationale (an AUTHORITY omission: the rule space is never named)
2199
+ // known gap: the generic fallback anchors a per-call refusal to the whole run and is on the record as
2200
+ // unrepaired in test/modelFacingScan.test.ts · `LEDGER`, under this file's own key.
2201
+ // Do not widen it here without that test.
2202
+ // law: may omit, never deny; every clause anchored to the call it was composed on.
2100
2203
  if (decision.result === 'deny') {
2101
2204
  denied = true;
2102
2205
  // Deny default keeps the existing v2.4 shape (carries
@@ -2779,6 +2882,15 @@ export function buildToolCallsHandler(deps) {
2779
2882
  // "nothing reachable may be named", and it used to assert the first.
2780
2883
  const hopsSpoken = spoken(hops, mayName);
2781
2884
  const openSpoken = spoken(openAll, mayName);
2885
+ // The cursor through the SAME filter (9.86.1). The description
2886
+ // withholds a hidden cursor's name and every refusal below printed
2887
+ // it raw in two clauses; `cursorWithheld` keeps the sentence's
2888
+ // anchor honest ("the skill the cursor stood in") without the id.
2889
+ const cursorSpoken = currentSkillId === undefined
2890
+ ? {}
2891
+ : mayName(currentSkillId)
2892
+ ? { cursorId: currentSkillId }
2893
+ : { cursorWithheld: true };
2782
2894
  const hopsNamed = hopsSpoken.named;
2783
2895
  const openNamed = openSpoken.named;
2784
2896
  // The ONE owner of "is this target the cursor?" — the same function
@@ -2896,7 +3008,7 @@ export function buildToolCallsHandler(deps) {
2896
3008
  result = composeReadSkillRefusal({
2897
3009
  requestedId: reqId,
2898
3010
  targetClass,
2899
- ...(currentSkillId !== undefined && { cursorId: currentSkillId }),
3011
+ ...cursorSpoken,
2900
3012
  hops: hopsSpoken,
2901
3013
  openIds: openSpoken,
2902
3014
  ...(deps.skillGraphIsTree === true && { isTree: true }),
@@ -2933,7 +3045,7 @@ export function buildToolCallsHandler(deps) {
2933
3045
  result = composeReadSkillRefusal({
2934
3046
  requestedId: reqId,
2935
3047
  targetClass,
2936
- ...(currentSkillId !== undefined && { cursorId: currentSkillId }),
3048
+ ...cursorSpoken,
2937
3049
  // No hop is named under a posture, and the graph's hop set
2938
3050
  // is not this arm's subject — `held: false` is the honest
2939
3051
  // shape, not a claim that nothing was reachable (this arm
@@ -2942,9 +3054,9 @@ export function buildToolCallsHandler(deps) {
2942
3054
  openIds: openSpoken,
2943
3055
  posture: deps.skillStrictness,
2944
3056
  ...(menuNamed !== undefined && { menuOffered: menuNamed }),
2945
- ...((turnRoute?.by === 'intent' || turnRoute?.by === 'entry') && {
2946
- routedDecisively: true,
2947
- }),
3057
+ // The whole verdict, not a boolean derived from two of its
3058
+ // six values: the composer says one past fact per value.
3059
+ ...(turnRoute !== undefined && { turnStartedBy: turnRoute.by }),
2948
3060
  });
2949
3061
  typedEmit(scope, 'agentfootprint.skill.rejected', {
2950
3062
  requestedId: reqId,
@@ -3390,10 +3502,14 @@ export function buildToolCallsHandler(deps) {
3390
3502
  // silently invents a decision, for the same reason it never silently
3391
3503
  // drops one.
3392
3504
  error = true;
3505
+ // A past fact about the resumed call, not a forecast about the
3506
+ // turn (9.86.1): "cannot be retried this turn … Answer without it,
3507
+ // or finish" was a prediction plus a standing order on a result
3508
+ // that is re-read on every later call.
3393
3509
  result =
3394
- `tool '${toolName}' was not executed and cannot be retried this turn: it declares ` +
3395
- `its own checkIn consent gate, that gate trips for these arguments, and a resumed ` +
3396
- `dispatch has no second checkpoint to ask on. Answer without it, or finish. (To ` +
3510
+ `tool '${toolName}' was not executed on that call, and the resumed dispatch had ` +
3511
+ `no second checkpoint to retry it on: it declares its own checkIn consent gate, ` +
3512
+ `and that gate tripped for those arguments. (To ` +
3397
3513
  `the agent's author: the middleware '${askedBy}' and the tool's checkIn ask ` +
3398
3514
  `different questions — one is the rule's, one is the tool's with the evidence ` +
3399
3515
  `pack attached — so approving one is not answering the other. Keep one gate for ` +