agentfootprint 9.85.0 → 9.86.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 (163) hide show
  1. package/CHANGELOG.md +547 -24
  2. package/canonical-notes.json +1 -1
  3. package/dist/core/Agent.js +15 -4
  4. package/dist/core/Agent.js.map +1 -1
  5. package/dist/core/agent/AgentBuilder.js.map +1 -1
  6. package/dist/core/agent/buildAgentChart.js +5 -0
  7. package/dist/core/agent/buildAgentChart.js.map +1 -1
  8. package/dist/core/agent/buildDynamicAgentChart.js +22 -4
  9. package/dist/core/agent/buildDynamicAgentChart.js.map +1 -1
  10. package/dist/core/agent/buildToolRegistry.js +12 -1
  11. package/dist/core/agent/buildToolRegistry.js.map +1 -1
  12. package/dist/core/agent/coverage/ledger.js +8 -2
  13. package/dist/core/agent/coverage/ledger.js.map +1 -1
  14. package/dist/core/agent/selfCallNotice.js +20 -7
  15. package/dist/core/agent/selfCallNotice.js.map +1 -1
  16. package/dist/core/agent/skillBrains.js +3 -2
  17. package/dist/core/agent/skillBrains.js.map +1 -1
  18. package/dist/core/agent/stages/stepNudge.js +13 -4
  19. package/dist/core/agent/stages/stepNudge.js.map +1 -1
  20. package/dist/core/agent/stages/toolCalls.js +484 -64
  21. package/dist/core/agent/stages/toolCalls.js.map +1 -1
  22. package/dist/core/agent/stages/wrapUp.js +54 -6
  23. package/dist/core/agent/stages/wrapUp.js.map +1 -1
  24. package/dist/core/agent/window/currentRequest.js +4 -2
  25. package/dist/core/agent/window/currentRequest.js.map +1 -1
  26. package/dist/core/runbook/recording.js +3 -2
  27. package/dist/core/runbook/recording.js.map +1 -1
  28. package/dist/core/slots/buildToolsSlot.js +20 -4
  29. package/dist/core/slots/buildToolsSlot.js.map +1 -1
  30. package/dist/doors/skill-graph.js +4 -1
  31. package/dist/doors/skill-graph.js.map +1 -1
  32. package/dist/esm/core/Agent.js +15 -4
  33. package/dist/esm/core/Agent.js.map +1 -1
  34. package/dist/esm/core/agent/AgentBuilder.d.ts +2 -1
  35. package/dist/esm/core/agent/AgentBuilder.js.map +1 -1
  36. package/dist/esm/core/agent/buildAgentChart.js +5 -0
  37. package/dist/esm/core/agent/buildAgentChart.js.map +1 -1
  38. package/dist/esm/core/agent/buildDynamicAgentChart.js +22 -4
  39. package/dist/esm/core/agent/buildDynamicAgentChart.js.map +1 -1
  40. package/dist/esm/core/agent/buildToolRegistry.d.ts +20 -0
  41. package/dist/esm/core/agent/buildToolRegistry.js +12 -1
  42. package/dist/esm/core/agent/buildToolRegistry.js.map +1 -1
  43. package/dist/esm/core/agent/coverage/ledger.d.ts +5 -0
  44. package/dist/esm/core/agent/coverage/ledger.js +8 -2
  45. package/dist/esm/core/agent/coverage/ledger.js.map +1 -1
  46. package/dist/esm/core/agent/selfCallNotice.d.ts +20 -7
  47. package/dist/esm/core/agent/selfCallNotice.js +20 -7
  48. package/dist/esm/core/agent/selfCallNotice.js.map +1 -1
  49. package/dist/esm/core/agent/skillBrains.d.ts +12 -4
  50. package/dist/esm/core/agent/skillBrains.js +3 -2
  51. package/dist/esm/core/agent/skillBrains.js.map +1 -1
  52. package/dist/esm/core/agent/stages/stepNudge.d.ts +13 -4
  53. package/dist/esm/core/agent/stages/stepNudge.js +13 -4
  54. package/dist/esm/core/agent/stages/stepNudge.js.map +1 -1
  55. package/dist/esm/core/agent/stages/toolCalls.d.ts +185 -0
  56. package/dist/esm/core/agent/stages/toolCalls.js +480 -63
  57. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -1
  58. package/dist/esm/core/agent/stages/wrapUp.d.ts +44 -2
  59. package/dist/esm/core/agent/stages/wrapUp.js +52 -5
  60. package/dist/esm/core/agent/stages/wrapUp.js.map +1 -1
  61. package/dist/esm/core/agent/types.d.ts +22 -4
  62. package/dist/esm/core/agent/window/currentRequest.d.ts +4 -2
  63. package/dist/esm/core/agent/window/currentRequest.js +4 -2
  64. package/dist/esm/core/agent/window/currentRequest.js.map +1 -1
  65. package/dist/esm/core/runbook/recording.js +3 -2
  66. package/dist/esm/core/runbook/recording.js.map +1 -1
  67. package/dist/esm/core/slots/buildToolsSlot.d.ts +1 -1
  68. package/dist/esm/core/slots/buildToolsSlot.js +20 -4
  69. package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
  70. package/dist/esm/doors/skill-graph.d.ts +1 -1
  71. package/dist/esm/doors/skill-graph.js +4 -1
  72. package/dist/esm/doors/skill-graph.js.map +1 -1
  73. package/dist/esm/events/payloads.d.ts +34 -2
  74. package/dist/esm/index.js +6 -5
  75. package/dist/esm/index.js.map +1 -1
  76. package/dist/esm/lib/injection-engine/index.d.ts +1 -1
  77. package/dist/esm/lib/injection-engine/index.js +4 -1
  78. package/dist/esm/lib/injection-engine/index.js.map +1 -1
  79. package/dist/esm/lib/injection-engine/skillGraph.d.ts +56 -0
  80. package/dist/esm/lib/injection-engine/skillGraph.js +29 -3
  81. package/dist/esm/lib/injection-engine/skillGraph.js.map +1 -1
  82. package/dist/esm/lib/injection-engine/skillSteps.d.ts +20 -1
  83. package/dist/esm/lib/injection-engine/skillSteps.js +28 -3
  84. package/dist/esm/lib/injection-engine/skillSteps.js.map +1 -1
  85. package/dist/esm/lib/injection-engine/skillToolDescriptors.d.ts +18 -0
  86. package/dist/esm/lib/injection-engine/skillToolDescriptors.js +103 -10
  87. package/dist/esm/lib/injection-engine/skillToolDescriptors.js.map +1 -1
  88. package/dist/esm/lib/injection-engine/types.d.ts +12 -10
  89. package/dist/esm/lib/injection-engine/types.js +5 -4
  90. package/dist/esm/lib/injection-engine/types.js.map +1 -1
  91. package/dist/esm/lib/saidByPerson.d.ts +48 -15
  92. package/dist/esm/lib/saidByPerson.js +52 -17
  93. package/dist/esm/lib/saidByPerson.js.map +1 -1
  94. package/dist/esm/lib/spokenIds.d.ts +52 -0
  95. package/dist/esm/lib/spokenIds.js +11 -0
  96. package/dist/esm/lib/spokenIds.js.map +1 -0
  97. package/dist/esm/lib/trace-toolpack/traceToolpack.js +33 -19
  98. package/dist/esm/lib/trace-toolpack/traceToolpack.js.map +1 -1
  99. package/dist/index.js +6 -5
  100. package/dist/index.js.map +1 -1
  101. package/dist/lib/injection-engine/index.js +5 -2
  102. package/dist/lib/injection-engine/index.js.map +1 -1
  103. package/dist/lib/injection-engine/skillGraph.js +31 -4
  104. package/dist/lib/injection-engine/skillGraph.js.map +1 -1
  105. package/dist/lib/injection-engine/skillSteps.js +28 -3
  106. package/dist/lib/injection-engine/skillSteps.js.map +1 -1
  107. package/dist/lib/injection-engine/skillToolDescriptors.js +103 -10
  108. package/dist/lib/injection-engine/skillToolDescriptors.js.map +1 -1
  109. package/dist/lib/injection-engine/types.js +5 -4
  110. package/dist/lib/injection-engine/types.js.map +1 -1
  111. package/dist/lib/saidByPerson.js +53 -18
  112. package/dist/lib/saidByPerson.js.map +1 -1
  113. package/dist/lib/spokenIds.js +15 -0
  114. package/dist/lib/spokenIds.js.map +1 -0
  115. package/dist/lib/trace-toolpack/traceToolpack.js +33 -19
  116. package/dist/lib/trace-toolpack/traceToolpack.js.map +1 -1
  117. package/dist/types/core/Agent.d.ts.map +1 -1
  118. package/dist/types/core/agent/AgentBuilder.d.ts +2 -1
  119. package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
  120. package/dist/types/core/agent/buildAgentChart.d.ts.map +1 -1
  121. package/dist/types/core/agent/buildDynamicAgentChart.d.ts.map +1 -1
  122. package/dist/types/core/agent/buildToolRegistry.d.ts +20 -0
  123. package/dist/types/core/agent/buildToolRegistry.d.ts.map +1 -1
  124. package/dist/types/core/agent/coverage/ledger.d.ts +5 -0
  125. package/dist/types/core/agent/coverage/ledger.d.ts.map +1 -1
  126. package/dist/types/core/agent/selfCallNotice.d.ts +20 -7
  127. package/dist/types/core/agent/selfCallNotice.d.ts.map +1 -1
  128. package/dist/types/core/agent/skillBrains.d.ts +12 -4
  129. package/dist/types/core/agent/skillBrains.d.ts.map +1 -1
  130. package/dist/types/core/agent/stages/stepNudge.d.ts +13 -4
  131. package/dist/types/core/agent/stages/stepNudge.d.ts.map +1 -1
  132. package/dist/types/core/agent/stages/toolCalls.d.ts +185 -0
  133. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -1
  134. package/dist/types/core/agent/stages/wrapUp.d.ts +44 -2
  135. package/dist/types/core/agent/stages/wrapUp.d.ts.map +1 -1
  136. package/dist/types/core/agent/types.d.ts +22 -4
  137. package/dist/types/core/agent/types.d.ts.map +1 -1
  138. package/dist/types/core/agent/window/currentRequest.d.ts +4 -2
  139. package/dist/types/core/agent/window/currentRequest.d.ts.map +1 -1
  140. package/dist/types/core/runbook/recording.d.ts.map +1 -1
  141. package/dist/types/core/slots/buildToolsSlot.d.ts +1 -1
  142. package/dist/types/core/slots/buildToolsSlot.d.ts.map +1 -1
  143. package/dist/types/doors/skill-graph.d.ts +1 -1
  144. package/dist/types/doors/skill-graph.d.ts.map +1 -1
  145. package/dist/types/events/payloads.d.ts +34 -2
  146. package/dist/types/events/payloads.d.ts.map +1 -1
  147. package/dist/types/index.d.ts.map +1 -1
  148. package/dist/types/lib/injection-engine/index.d.ts +1 -1
  149. package/dist/types/lib/injection-engine/index.d.ts.map +1 -1
  150. package/dist/types/lib/injection-engine/skillGraph.d.ts +56 -0
  151. package/dist/types/lib/injection-engine/skillGraph.d.ts.map +1 -1
  152. package/dist/types/lib/injection-engine/skillSteps.d.ts +20 -1
  153. package/dist/types/lib/injection-engine/skillSteps.d.ts.map +1 -1
  154. package/dist/types/lib/injection-engine/skillToolDescriptors.d.ts +18 -0
  155. package/dist/types/lib/injection-engine/skillToolDescriptors.d.ts.map +1 -1
  156. package/dist/types/lib/injection-engine/types.d.ts +12 -10
  157. package/dist/types/lib/injection-engine/types.d.ts.map +1 -1
  158. package/dist/types/lib/saidByPerson.d.ts +48 -15
  159. package/dist/types/lib/saidByPerson.d.ts.map +1 -1
  160. package/dist/types/lib/spokenIds.d.ts +53 -0
  161. package/dist/types/lib/spokenIds.d.ts.map +1 -0
  162. package/dist/types/lib/trace-toolpack/traceToolpack.d.ts.map +1 -1
  163. package/package.json +1 -1
@@ -34,11 +34,12 @@ export function toolResultsOf(ctx) {
34
34
  * The messages in `ctx.history` a PERSON actually wrote, in order (9.84.0).
35
35
  * THE one reader for a predicate that judges what was said.
36
36
  *
37
- * Five kinds of `role: 'user'` message in that list came from this library,
37
+ * Seven kinds of `role: 'user'` message in that list came from this library,
38
38
  * not from anybody: a compaction frame, a drop notice, the two in-loop
39
- * corrections, and a message an Injection delivered. They are ours, they are
40
- * in the person's voice, one of them names tools and two quote text the model
41
- * or a validator produced — so a rule written as
39
+ * corrections, the out-of-budget wrap-up instruction, the stepped-skill nudge,
40
+ * and a message an Injection delivered. They are ours, they are in the
41
+ * person's voice, two of them name tools and two quote text the model or a
42
+ * validator produced — so a rule written as
42
43
  *
43
44
  * ```ts
44
45
  * activeWhen: (ctx) => ctx.history.some((m) => m.content.includes('refund'))
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/lib/injection-engine/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AA8TrD;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,GAAqB;IAMjD,OAAO,GAAG,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,YAAY,CAAC,GAAqB;IAChD,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;AAC5C,CAAC;AAoMD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,sBAAsB,CACpC,GAAc,EACd,GAA2D;IAE3D,qEAAqE;IACrE,+DAA+D;IAC/D,0EAA0E;IAC1E,2EAA2E;IAC3E,sBAAsB;IACtB,MAAM,IAAI,GAAG,GAAG,CAAC,QAEJ,CAAC;IACd,wEAAwE;IACxE,2EAA2E;IAC3E,kDAAkD;IAClD,MAAM,YAAY,GAChB,GAAG,CAAC,SAAS,KAAK,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,YAAY,KAAK,SAAS;QAC7D,CAAC,CAAC,GAAG,KAAK,SAAS;YACjB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC;QAChD,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC;IAC9B,MAAM,GAAG,GAAoB;QAC3B,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC;QACxD,GAAG,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAA6C,EAAE,CAAC;QAC7F,GAAG,CAAC,IAAI,EAAE,YAAY,IAAI;YACxB,YAAY,EAAE,IAAI,CAAC,YAA+C;SACnE,CAAC;QACF,0EAA0E;QAC1E,2EAA2E;QAC3E,yEAAyE;QACzE,GAAG,CAAC,IAAI,EAAE,KAAK,KAAK,SAAS,IAAI;YAC/B,KAAK,EAAE,IAAI,CAAC,KAAiC;SAC9C,CAAC;QACF,MAAM,EAAE;YACN,GAAG,CAAC,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC;YAC9E,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACpF,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI;gBACtB,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAClC,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE;oBACvB,WAAW,EAAE,GAAG,CAAC,EAAE;iBACpB,CAAC,CAAC;aACJ,CAAC;SACH;KACF,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/lib/injection-engine/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAKH,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AA+TrD;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,GAAqB;IAMjD,OAAO,GAAG,CAAC,WAAW,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,YAAY,CAAC,GAAqB;IAChD,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;AAC5C,CAAC;AAoMD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,sBAAsB,CACpC,GAAc,EACd,GAA2D;IAE3D,qEAAqE;IACrE,+DAA+D;IAC/D,0EAA0E;IAC1E,2EAA2E;IAC3E,sBAAsB;IACtB,MAAM,IAAI,GAAG,GAAG,CAAC,QAEJ,CAAC;IACd,wEAAwE;IACxE,2EAA2E;IAC3E,kDAAkD;IAClD,MAAM,YAAY,GAChB,GAAG,CAAC,SAAS,KAAK,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,YAAY,KAAK,SAAS;QAC7D,CAAC,CAAC,GAAG,KAAK,SAAS;YACjB,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,CAAC;QAChD,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC;IAC9B,MAAM,GAAG,GAAoB;QAC3B,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC;QACxD,GAAG,CAAC,IAAI,EAAE,WAAW,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,WAA6C,EAAE,CAAC;QAC7F,GAAG,CAAC,IAAI,EAAE,YAAY,IAAI;YACxB,YAAY,EAAE,IAAI,CAAC,YAA+C;SACnE,CAAC;QACF,0EAA0E;QAC1E,2EAA2E;QAC3E,yEAAyE;QACzE,GAAG,CAAC,IAAI,EAAE,KAAK,KAAK,SAAS,IAAI;YAC/B,KAAK,EAAE,IAAI,CAAC,KAAiC;SAC9C,CAAC;QACF,MAAM,EAAE;YACN,GAAG,CAAC,YAAY,KAAK,SAAS,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,CAAC;YAC9E,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YACpF,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI;gBACtB,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAClC,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE;oBACvB,WAAW,EAAE,GAAG,CAAC,EAAE;iBACpB,CAAC,CAAC;aACJ,CAAC;SACH;KACF,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -6,20 +6,24 @@
6
6
  * imports, no state, no clock.
7
7
  * Role: Leaf. Several layers ask the same question and must not answer it
8
8
  * differently: the window's refusal engine (`currentRequest.ts`,
9
- * which will not let a strategy drop the request), the four authors
9
+ * which will not let a strategy drop the request), the six authors
10
10
  * of library-written user turns (`window/notice.ts`,
11
- * `window/summarize.ts`, `outputEnforcement.ts`, `evidence/gate.ts`
12
- * — they own the sentences and take the markers from here), and —
13
- * since 9.84.0 — a rule author reading `InjectionContext.history`
14
- * (`saidByPerson(ctx)`).
11
+ * `window/summarize.ts`, `outputEnforcement.ts`, `evidence/gate.ts`,
12
+ * `stages/wrapUp.ts`, and `skillSteps.ts` for the nudge
13
+ * `stages/stepNudge.ts` appends — they own the sentences and take
14
+ * the markers from here), and — since 9.84.0 — a rule author reading
15
+ * `InjectionContext.history` (`saidByPerson(ctx)`).
15
16
  * Emits: N/A.
16
17
  *
17
18
  * ## Why this is a leaf and not a private helper
18
19
  *
19
- * This library writes FIVE kinds of `role: 'user'` message that nobody said:
20
+ * This library writes SEVEN kinds of `role: 'user'` message that nobody said:
20
21
  * a compaction frame, a drop notice, a schema-check correction, an
21
- * evidence-check correction, and a message an Injection delivered. The window
22
- * layer knew two of them and the marker; the evidence layer knew the other two
22
+ * evidence-check correction, a budget wrap-up instruction, a stepped-skill
23
+ * nudge, and a message an Injection delivered. Six of the seven are read off
24
+ * the OPENING they carry ({@link LIBRARY_AUTHORED_PREFIXES}); the delivered
25
+ * one carries an `injectedBy` marker instead. The window layer knew two of the
26
+ * openings and the marker; the evidence layer knew two more
23
27
  * (`evidence/frames.ts`); neither list was reachable from the routing layer at
24
28
  * all — the skill-graph fence forbids it from importing the agent loop, and
25
29
  * rightly. So a predicate reading `history` could filter some of the classes
@@ -32,12 +36,27 @@
32
36
  * wrote. That is a fixable bug in one place only: the rule has to be one
33
37
  * implementation both sides import, not two that agree until they do not.
34
38
  *
35
- * The markers move here with it, as a LIST rather than four constants in four
36
- * files. A prefix is what the recognizer matches AND what the writer emits;
37
- * separating those is how a prefix silently stops being recognized, and a
38
- * sixth authored frame that lands anywhere else is a hole nobody will see
39
- * until a rule fires on it. Adding one means adding it to
40
- * {@link LIBRARY_AUTHORED_PREFIXES}, and every reader is fixed at once.
39
+ * The two frames added in 9.86.0 are the same bug found again, and found by
40
+ * counting rather than by reading: 9.84.0 registered four openings and wrote
41
+ * "five classes" in prose, while the tree already had SEVEN producers of a
42
+ * user-role message that reach `scope.history`. The budget wrap-up
43
+ * (`stages/wrapUp.ts`) carried an unprefixed sentence containing "Do not
44
+ * request tools", and the stepped-skill nudge (`stages/stepNudge.ts`) carries
45
+ * a skill id and every unrun step's TOOL NAME — so both were credited to a
46
+ * person, a `saidByPerson(ctx).some(m => m.content.includes(…))` rule matched
47
+ * on them, and the window could anchor its refusal on the wrap-up frame.
48
+ *
49
+ * The markers live here, as a LIST rather than one constant per writing file.
50
+ * A prefix is what the recognizer matches AND what the writer emits;
51
+ * separating those is how a prefix silently stops being recognized, and an
52
+ * authored frame that lands anywhere else is a hole nobody will see until a
53
+ * rule fires on it. Adding one means adding it to
54
+ * {@link LIBRARY_AUTHORED_PREFIXES}, and every reader is fixed at once —
55
+ * which is why the count is no longer asserted in prose alone:
56
+ * `test/lib/injection-engine/userTurnProducers.test.ts` WALKS the tree for
57
+ * every `role: 'user'` construction site and fails, with the file and line, on
58
+ * one that is neither registered here, nor a person's own turn, nor
59
+ * wire-only.
41
60
  */
42
61
  /**
43
62
  * The fields authorship is decided from — structural, so both
@@ -65,6 +84,14 @@ export declare const SCHEMA_CHECK_FRAME_PREFIX = "[schema check";
65
84
  /** Opening of the authored frame the evidence gate writes. Stable — tests,
66
85
  * docs and readers match on it. Written by `buildEvidenceCorrection`. */
67
86
  export declare const EVIDENCE_CHECK_FRAME_PREFIX = "[evidence check";
87
+ /** Opening of the authored instruction the out-of-budget WRAP-UP call carries.
88
+ * Stable — tests and readers match on it. Written by `wrapUpStage`
89
+ * (`WRAP_UP_INSTRUCTION`). */
90
+ export declare const WRAP_UP_FRAME_PREFIX = "[budget exhausted";
91
+ /** Opening of the authored frame the stepped-skill NUDGE carries. Stable —
92
+ * tests and readers match on it. Written by `nudgeTeachingMessage`, appended
93
+ * by `buildStepNudgeStage`. */
94
+ export declare const STEP_NUDGE_FRAME_PREFIX = "[steps unrun";
68
95
  /**
69
96
  * Every opening this library puts on a `role: 'user'` message it wrote itself.
70
97
  *
@@ -76,7 +103,13 @@ export declare const EVIDENCE_CHECK_FRAME_PREFIX = "[evidence check";
76
103
  *
77
104
  * The two correction frames both QUOTE untrusted text after their label (a
78
105
  * validator's error, the model's own flagged values), which is exactly why
79
- * they are matched by PREFIX and never by anything further in.
106
+ * they are matched by PREFIX and never by anything further in. The nudge is
107
+ * the same shape for a different reason: its body is a list of a skill's own
108
+ * step notes and tool names, which is exactly the text a rule watches for.
109
+ *
110
+ * The list is frozen because it is a registry, not a scratch array: a consumer
111
+ * holds the same object this library's own readers hold, and a `push` into it
112
+ * would change what every reader calls a person's message.
80
113
  */
81
114
  export declare const LIBRARY_AUTHORED_PREFIXES: readonly string[];
82
115
  /** True when this user-role message opens with a frame this library authored. */
@@ -6,20 +6,24 @@
6
6
  * imports, no state, no clock.
7
7
  * Role: Leaf. Several layers ask the same question and must not answer it
8
8
  * differently: the window's refusal engine (`currentRequest.ts`,
9
- * which will not let a strategy drop the request), the four authors
9
+ * which will not let a strategy drop the request), the six authors
10
10
  * of library-written user turns (`window/notice.ts`,
11
- * `window/summarize.ts`, `outputEnforcement.ts`, `evidence/gate.ts`
12
- * — they own the sentences and take the markers from here), and —
13
- * since 9.84.0 — a rule author reading `InjectionContext.history`
14
- * (`saidByPerson(ctx)`).
11
+ * `window/summarize.ts`, `outputEnforcement.ts`, `evidence/gate.ts`,
12
+ * `stages/wrapUp.ts`, and `skillSteps.ts` for the nudge
13
+ * `stages/stepNudge.ts` appends — they own the sentences and take
14
+ * the markers from here), and — since 9.84.0 — a rule author reading
15
+ * `InjectionContext.history` (`saidByPerson(ctx)`).
15
16
  * Emits: N/A.
16
17
  *
17
18
  * ## Why this is a leaf and not a private helper
18
19
  *
19
- * This library writes FIVE kinds of `role: 'user'` message that nobody said:
20
+ * This library writes SEVEN kinds of `role: 'user'` message that nobody said:
20
21
  * a compaction frame, a drop notice, a schema-check correction, an
21
- * evidence-check correction, and a message an Injection delivered. The window
22
- * layer knew two of them and the marker; the evidence layer knew the other two
22
+ * evidence-check correction, a budget wrap-up instruction, a stepped-skill
23
+ * nudge, and a message an Injection delivered. Six of the seven are read off
24
+ * the OPENING they carry ({@link LIBRARY_AUTHORED_PREFIXES}); the delivered
25
+ * one carries an `injectedBy` marker instead. The window layer knew two of the
26
+ * openings and the marker; the evidence layer knew two more
23
27
  * (`evidence/frames.ts`); neither list was reachable from the routing layer at
24
28
  * all — the skill-graph fence forbids it from importing the agent loop, and
25
29
  * rightly. So a predicate reading `history` could filter some of the classes
@@ -32,12 +36,27 @@
32
36
  * wrote. That is a fixable bug in one place only: the rule has to be one
33
37
  * implementation both sides import, not two that agree until they do not.
34
38
  *
35
- * The markers move here with it, as a LIST rather than four constants in four
36
- * files. A prefix is what the recognizer matches AND what the writer emits;
37
- * separating those is how a prefix silently stops being recognized, and a
38
- * sixth authored frame that lands anywhere else is a hole nobody will see
39
- * until a rule fires on it. Adding one means adding it to
40
- * {@link LIBRARY_AUTHORED_PREFIXES}, and every reader is fixed at once.
39
+ * The two frames added in 9.86.0 are the same bug found again, and found by
40
+ * counting rather than by reading: 9.84.0 registered four openings and wrote
41
+ * "five classes" in prose, while the tree already had SEVEN producers of a
42
+ * user-role message that reach `scope.history`. The budget wrap-up
43
+ * (`stages/wrapUp.ts`) carried an unprefixed sentence containing "Do not
44
+ * request tools", and the stepped-skill nudge (`stages/stepNudge.ts`) carries
45
+ * a skill id and every unrun step's TOOL NAME — so both were credited to a
46
+ * person, a `saidByPerson(ctx).some(m => m.content.includes(…))` rule matched
47
+ * on them, and the window could anchor its refusal on the wrap-up frame.
48
+ *
49
+ * The markers live here, as a LIST rather than one constant per writing file.
50
+ * A prefix is what the recognizer matches AND what the writer emits;
51
+ * separating those is how a prefix silently stops being recognized, and an
52
+ * authored frame that lands anywhere else is a hole nobody will see until a
53
+ * rule fires on it. Adding one means adding it to
54
+ * {@link LIBRARY_AUTHORED_PREFIXES}, and every reader is fixed at once —
55
+ * which is why the count is no longer asserted in prose alone:
56
+ * `test/lib/injection-engine/userTurnProducers.test.ts` WALKS the tree for
57
+ * every `role: 'user'` construction site and fails, with the file and line, on
58
+ * one that is neither registered here, nor a person's own turn, nor
59
+ * wire-only.
41
60
  */
42
61
  /** Opening of the authored notice a DROP leaves behind. Stable — tests and
43
62
  * readers match on it. Written by `buildDropNotice`. */
@@ -51,6 +70,14 @@ export const SCHEMA_CHECK_FRAME_PREFIX = '[schema check';
51
70
  /** Opening of the authored frame the evidence gate writes. Stable — tests,
52
71
  * docs and readers match on it. Written by `buildEvidenceCorrection`. */
53
72
  export const EVIDENCE_CHECK_FRAME_PREFIX = '[evidence check';
73
+ /** Opening of the authored instruction the out-of-budget WRAP-UP call carries.
74
+ * Stable — tests and readers match on it. Written by `wrapUpStage`
75
+ * (`WRAP_UP_INSTRUCTION`). */
76
+ export const WRAP_UP_FRAME_PREFIX = '[budget exhausted';
77
+ /** Opening of the authored frame the stepped-skill NUDGE carries. Stable —
78
+ * tests and readers match on it. Written by `nudgeTeachingMessage`, appended
79
+ * by `buildStepNudgeStage`. */
80
+ export const STEP_NUDGE_FRAME_PREFIX = '[steps unrun';
54
81
  /**
55
82
  * Every opening this library puts on a `role: 'user'` message it wrote itself.
56
83
  *
@@ -62,14 +89,22 @@ export const EVIDENCE_CHECK_FRAME_PREFIX = '[evidence check';
62
89
  *
63
90
  * The two correction frames both QUOTE untrusted text after their label (a
64
91
  * validator's error, the model's own flagged values), which is exactly why
65
- * they are matched by PREFIX and never by anything further in.
92
+ * they are matched by PREFIX and never by anything further in. The nudge is
93
+ * the same shape for a different reason: its body is a list of a skill's own
94
+ * step notes and tool names, which is exactly the text a rule watches for.
95
+ *
96
+ * The list is frozen because it is a registry, not a scratch array: a consumer
97
+ * holds the same object this library's own readers hold, and a `push` into it
98
+ * would change what every reader calls a person's message.
66
99
  */
67
- export const LIBRARY_AUTHORED_PREFIXES = [
100
+ export const LIBRARY_AUTHORED_PREFIXES = Object.freeze([
68
101
  DROP_NOTICE_PREFIX,
69
102
  COMPACTED_FRAME_PREFIX,
70
103
  SCHEMA_CHECK_FRAME_PREFIX,
71
104
  EVIDENCE_CHECK_FRAME_PREFIX,
72
- ];
105
+ WRAP_UP_FRAME_PREFIX,
106
+ STEP_NUDGE_FRAME_PREFIX,
107
+ ]);
73
108
  /** True when this user-role message opens with a frame this library authored. */
74
109
  export function isLibraryAuthoredFrame(msg) {
75
110
  return (msg !== undefined &&
@@ -1 +1 @@
1
- {"version":3,"file":"saidByPerson.js","sourceRoot":"","sources":["../../../src/lib/saidByPerson.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AAiBH;yDACyD;AACzD,MAAM,CAAC,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;AAErD;6DAC6D;AAC7D,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAE3D;uEACuE;AACvE,MAAM,CAAC,MAAM,yBAAyB,GAAG,eAAe,CAAC;AAEzD;0EAC0E;AAC1E,MAAM,CAAC,MAAM,2BAA2B,GAAG,iBAAiB,CAAC;AAE7D;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAsB;IAC1D,kBAAkB;IAClB,sBAAsB;IACtB,yBAAyB;IACzB,2BAA2B;CAC5B,CAAC;AAEF,iFAAiF;AACjF,MAAM,UAAU,sBAAsB,CAAC,GAAgC;IACrE,OAAO,CACL,GAAG,KAAK,SAAS;QACjB,GAAG,CAAC,IAAI,KAAK,MAAM;QACnB,yBAAyB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAC3E,CAAC;AACJ,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,YAAY,CAAC,GAAgC;IAC3D,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;AAChG,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,kBAAkB,CAAC,GAAgC;IACjE,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;AACpG,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,GAAgC;IAC7D,OAAO,CACL,GAAG,KAAK,SAAS;QACjB,GAAG,CAAC,IAAI,KAAK,MAAM;QACnB,GAAG,CAAC,UAAU,KAAK,SAAS;QAC5B,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAC7B,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"saidByPerson.js","sourceRoot":"","sources":["../../../src/lib/saidByPerson.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAiBH;yDACyD;AACzD,MAAM,CAAC,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;AAErD;6DAC6D;AAC7D,MAAM,CAAC,MAAM,sBAAsB,GAAG,oBAAoB,CAAC;AAE3D;uEACuE;AACvE,MAAM,CAAC,MAAM,yBAAyB,GAAG,eAAe,CAAC;AAEzD;0EAC0E;AAC1E,MAAM,CAAC,MAAM,2BAA2B,GAAG,iBAAiB,CAAC;AAE7D;;+BAE+B;AAC/B,MAAM,CAAC,MAAM,oBAAoB,GAAG,mBAAmB,CAAC;AAExD;;gCAEgC;AAChC,MAAM,CAAC,MAAM,uBAAuB,GAAG,cAAc,CAAC;AAEtD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAsB,MAAM,CAAC,MAAM,CAAC;IACxE,kBAAkB;IAClB,sBAAsB;IACtB,yBAAyB;IACzB,2BAA2B;IAC3B,oBAAoB;IACpB,uBAAuB;CACxB,CAAC,CAAC;AAEH,iFAAiF;AACjF,MAAM,UAAU,sBAAsB,CAAC,GAAgC;IACrE,OAAO,CACL,GAAG,KAAK,SAAS;QACjB,GAAG,CAAC,IAAI,KAAK,MAAM;QACnB,yBAAyB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAC3E,CAAC;AACJ,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,YAAY,CAAC,GAAgC;IAC3D,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;AAChG,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,kBAAkB,CAAC,GAAgC;IACjE,OAAO,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;AACpG,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,GAAgC;IAC7D,OAAO,CACL,GAAG,KAAK,SAAS;QACjB,GAAG,CAAC,IAAI,KAAK,MAAM;QACnB,GAAG,CAAC,UAAU,KAAK,SAAS;QAC5B,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAC7B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * A set a model-facing sentence is allowed to NAME, after the role filter has
3
+ * run over it (9.86.0) — and the one fact a filtered list cannot be written
4
+ * without.
5
+ *
6
+ * ── OMIT, NEVER DENY ────────────────────────────────────────────────────
7
+ *
8
+ * A narrowing may take a name off a sentence. It may not turn that name's
9
+ * absence into a claim that the thing is gone: the graph, the dispatch map and
10
+ * the menu are all still holding it, and a model told "no skill was reachable"
11
+ * stops asking for the one it may not be told about. Omission costs nothing and
12
+ * is always true; the negative sentence is a denial of what the run holds.
13
+ *
14
+ * Every composer took plain arrays and branched on `length > 0`, so "the set
15
+ * was empty" and "the filter emptied it" produced the SAME sentence — one
16
+ * shape, two facts, in three separate places. `held` is that missing fact, and
17
+ * it is REQUIRED rather than optional on purpose: the compiler now asks every
18
+ * caller the question the call sites each forgot to answer.
19
+ *
20
+ * ── WHY THIS IS A LEAF AND NOT A HELPER IN THE GATE ─────────────────────
21
+ *
22
+ * It lived in `core/agent/stages/toolCalls.ts`, which put it on the wrong side
23
+ * of the skill-graph fence: `read_skill`'s DESCRIPTION is composed inside
24
+ * `src/lib/injection-engine/`, which may not import the agent loop, so the one
25
+ * surface the model reads to CHOOSE a skill could not use the fact its own
26
+ * refusals were being repaired with — and it went on printing "Nothing is
27
+ * reachable from here" over a graph whose only hop the role filter had removed.
28
+ * The same reason `src/lib/saidByPerson.ts` is a leaf: the writer and the
29
+ * recogniser share one rule, so they cannot drift.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const hidden = new Set(['beta']);
34
+ * const hops = spoken(['beta'], (id) => !hidden.has(id));
35
+ * // → { named: [], held: true } — the clause is DROPPED, not negated.
36
+ * ```
37
+ */
38
+ export interface SpokenIds {
39
+ /** The members this sentence may name — what survived the filter. */
40
+ readonly named: readonly string[];
41
+ /** Did the UNFILTERED set hold anything? `true` with an empty `named` is the
42
+ * filtered-to-empty case: the clause is omitted rather than negated. */
43
+ readonly held: boolean;
44
+ }
45
+ /**
46
+ * Apply the role filter to one set and keep both halves (9.86.0).
47
+ *
48
+ * `mayName` is the caller's visibility predicate — skill ids test membership of
49
+ * `scope.hiddenSkillIds`, tool names test whether every skill declaring them is
50
+ * hidden. Both questions have one answer shape, and this is it.
51
+ */
52
+ export declare function spoken(all: readonly string[], mayName: (id: string) => boolean): SpokenIds;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Apply the role filter to one set and keep both halves (9.86.0).
3
+ *
4
+ * `mayName` is the caller's visibility predicate — skill ids test membership of
5
+ * `scope.hiddenSkillIds`, tool names test whether every skill declaring them is
6
+ * hidden. Both questions have one answer shape, and this is it.
7
+ */
8
+ export function spoken(all, mayName) {
9
+ return { named: all.filter(mayName), held: all.length > 0 };
10
+ }
11
+ //# sourceMappingURL=spokenIds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spokenIds.js","sourceRoot":"","sources":["../../../src/lib/spokenIds.ts"],"names":[],"mappings":"AA6CA;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CAAC,GAAsB,EAAE,OAAgC;IAC7E,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;AAC9D,CAAC"}
@@ -1714,12 +1714,13 @@ function buildInspectToolCall(artifacts, reader) {
1714
1714
  const lines = [`TOOL CALL ${toolCallId} — ${facts.toolName ?? '(unnamed tool)'}`];
1715
1715
  lines.push(facts.runtimeStageId !== undefined
1716
1716
  ? `step: ${facts.runtimeStageId} — drill with trace_node('${facts.runtimeStageId}')`
1717
- : `step: ⚠ not resolvable — no event tail, and no committed step carries this call's ` +
1718
- `result (the turn may have ended before it landed).`);
1717
+ : `step: ⚠ not resolvable — no event tail, and no committed step carries the result ` +
1718
+ `of call '${toolCallId}' (the turn may have ended before it landed).`);
1719
1719
  lines.push(facts.proposedArgs !== undefined
1720
1720
  ? `proposed by the model: ${displayText(renderPreview(boundedPreview(facts.proposedArgs, TOOL_RESULT_PREVIEW_CHARS)))}`
1721
- : `proposed by the model: ⚠ not recorded — the assistant turn carrying this call is ` +
1722
- `not in the committed history (a window strategy may have folded it away).`);
1721
+ : `proposed by the model: ⚠ not recorded — the assistant turn carrying call ` +
1722
+ `'${toolCallId}' is not in the committed history (a window strategy may have ` +
1723
+ `folded it away).`);
1723
1724
  // Ran-with args: the ledger is the ONLY record of a rule rewriting
1724
1725
  // them. No ledger row means no rule changed anything — say that
1725
1726
  // plainly rather than leaving the reader to assume it.
@@ -1736,12 +1737,14 @@ function buildInspectToolCall(artifacts, reader) {
1736
1737
  lines.push('ran with: the proposed arguments, unchanged (rules looked and allowed them).');
1737
1738
  }
1738
1739
  else {
1739
- lines.push('ran with: the proposed arguments — no governance rule filed a row for this call.');
1740
+ lines.push(`ran with: the proposed arguments — no governance rule filed a row for call ` +
1741
+ `'${toolCallId}'.`);
1740
1742
  }
1741
1743
  lines.push(facts.result !== undefined
1742
1744
  ? `result: ${displayText(renderPreview(boundedPreview(facts.result, TOOL_RESULT_PREVIEW_CHARS), `get_value('${facts.runtimeStageId ?? '<step>'}', 'history') for the full turn`))}`
1743
- : `result: ⚠ no result recorded for this call in the committed history — it may have ` +
1744
- `been denied before it ran, or the turn ended (paused/failed) before it landed.`);
1745
+ : `result: ⚠ no result recorded for call '${toolCallId}' in the committed history — ` +
1746
+ `it may have been denied before it ran, or the turn ended (paused/failed) before ` +
1747
+ `it landed.`);
1745
1748
  // Outcome + duration: the event tail is the only clock a run has.
1746
1749
  const denial = rows.find((row) => row.outcome === 'deny');
1747
1750
  const end = eventsOf('agentfootprint.stream.tool_end').find((event) => event.payload.toolCallId === toolCallId);
@@ -1755,7 +1758,7 @@ function buildInspectToolCall(artifacts, reader) {
1755
1758
  outcome = 'error — the tool threw or returned a failure';
1756
1759
  }
1757
1760
  else if (checkIn && end === undefined) {
1758
- outcome = 'paused — a check-in asked a human and this call has no recorded end';
1761
+ outcome = `paused — a check-in asked a human and call '${toolCallId}' has no recorded end`;
1759
1762
  }
1760
1763
  else if (facts.result !== undefined) {
1761
1764
  outcome = 'ok';
@@ -1765,8 +1768,12 @@ function buildInspectToolCall(artifacts, reader) {
1765
1768
  }
1766
1769
  lines.push(`outcome: ${outcome}`);
1767
1770
  if (invalid) {
1768
- lines.push(`⚠ the arguments failed schema validation on this call — see the validation event / ` +
1769
- `the tool result, which carries the correction the model was given.`);
1771
+ // Anchored to the call by ID, not by "this call" (9.86.0): the line
1772
+ // lands in a tool result, and a model re-reading it three calls later
1773
+ // resolves "this call" to whichever call it is answering then.
1774
+ lines.push(`⚠ the arguments failed schema validation on call '${toolCallId}' — see the ` +
1775
+ `validation event / the tool result, which carries the correction the model was ` +
1776
+ `given.`);
1770
1777
  }
1771
1778
  if (artifacts.events === undefined) {
1772
1779
  lines.push(`duration: ⚠ unavailable — these artifacts carry no event tail. The commit log records ` +
@@ -1776,8 +1783,8 @@ function buildInspectToolCall(artifacts, reader) {
1776
1783
  lines.push(`duration: ${end.payload.durationMs}ms`);
1777
1784
  }
1778
1785
  else {
1779
- lines.push(`duration: ⚠ no tool_end event for this call in the retained tail (it may have been ` +
1780
- `dropped by the tail cap, or the call never finished).`);
1786
+ lines.push(`duration: ⚠ no tool_end event for call '${toolCallId}' in the retained tail (it may ` +
1787
+ `have been dropped by the tail cap, or the call never finished).`);
1781
1788
  }
1782
1789
  // THE DESCENT RUNG. The boundary marker below is honest for a tool
1783
1790
  // that called someone else's system, and needlessly honest for one
@@ -1934,7 +1941,7 @@ function buildInspectToolRun(artifacts, reader, options) {
1934
1941
  `INSIDE TOOL CALL ${toolCallId} — '${record.toolName}' ran a recorded flowchart ` +
1935
1942
  `(${record.steps} committed step(s), ${record.outcome}).`,
1936
1943
  body,
1937
- `next inside this call: inspect_tool_run({ toolCallId: '${toolCallId}', ` +
1944
+ `next inside call '${toolCallId}': inspect_tool_run({ toolCallId: '${toolCallId}', ` +
1938
1945
  `runtimeStageId: '<inner id>' }) opens a step · add 'key' for a value in full · ` +
1939
1946
  `'variable' asks why an inner value is what it is · 'find' searches this inner run.`,
1940
1947
  `⚠ the ids above are INNER ids — they name steps of ${record.toolName}'s own chart, not ` +
@@ -1964,15 +1971,18 @@ function unknownInnerRunMessage(toolCallId, lookup, reader) {
1964
1971
  const outer = reader.knownCalls().find((call) => call.id === toolCallId);
1965
1972
  if (outer === undefined) {
1966
1973
  lines.push(`⚠ the outer run does not record a call with that id either — check ` +
1967
- `inspect_tool_call('${toolCallId}') first; it names every id this run made.`);
1974
+ `inspect_tool_call('${toolCallId}') first; it names every id the outer run recorded.`);
1968
1975
  }
1969
1976
  else {
1970
1977
  lines.push(`That call ran '${outer.name}', which either does not keep records (only ` +
1971
1978
  `flowchartAsTool({ keepRecord: true }) does) or had this one dropped.`);
1972
1979
  }
1973
1980
  if (kept.length === 0) {
1974
- lines.push(`No inner runs are held right now. A tool that keeps records has simply not been called ` +
1975
- `yet in the turn this trace covers.`);
1981
+ // Past tense, anchored to the lookup that was answered (9.86.0). "Right
1982
+ // now" pointed at the moment of READING, and this string is a tool result
1983
+ // the model re-reads on every later call of the debugging turn.
1984
+ lines.push(`No inner run was held when inspect_tool_run('${toolCallId}') was answered. A tool that ` +
1985
+ `keeps records had not been called in the turn this trace covers.`);
1976
1986
  }
1977
1987
  else {
1978
1988
  const sample = kept
@@ -1984,9 +1994,13 @@ function unknownInnerRunMessage(toolCallId, lookup, reader) {
1984
1994
  '.');
1985
1995
  }
1986
1996
  if (lookup.dropped > 0) {
1987
- lines.push(`⚠ ${lookup.dropped} older record(s) were dropped to stay under the retention cap of ` +
1988
- `${lookup.limit} — this call may be one of them. Raise it with keepRecordLimit, or ask ` +
1989
- `sooner after the call.`);
1997
+ lines.push(
1998
+ // Named by id, not "this call" (9.86.1): the same repair the
1999
+ // schema-validation line above got in 9.86.0, on the arm the checker
2000
+ // could not see because its rule only knew `on this call`.
2001
+ `⚠ ${lookup.dropped} older record(s) were dropped to stay under the retention cap of ` +
2002
+ `${lookup.limit} — call '${toolCallId}' may be one of them. Raise it with ` +
2003
+ `keepRecordLimit, or ask sooner after the call.`);
1990
2004
  }
1991
2005
  return lines.join('\n');
1992
2006
  }