@stigmer/runner 3.15.3-dev.20260914100347 → 3.15.3-dev.20260916211208

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 (549) hide show
  1. package/README.md +1 -0
  2. package/dist/.build-fingerprint +1 -1
  3. package/dist/__test-utils__/approval-contract/types.d.ts +1 -1
  4. package/dist/__test-utils__/hermetic-activity.d.ts +61 -7
  5. package/dist/__test-utils__/hermetic-activity.js +100 -9
  6. package/dist/__test-utils__/hermetic-activity.js.map +1 -1
  7. package/dist/__test-utils__/model-registry-fixture.d.ts +22 -3
  8. package/dist/__test-utils__/model-registry-fixture.js +22 -7
  9. package/dist/__test-utils__/model-registry-fixture.js.map +1 -1
  10. package/dist/activities/execute-cursor/__test-utils__/contract-subject.d.ts +2 -2
  11. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +14 -11
  12. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -1
  13. package/dist/activities/execute-cursor/__test-utils__/fold.d.ts +61 -0
  14. package/dist/activities/execute-cursor/__test-utils__/fold.js +94 -0
  15. package/dist/activities/execute-cursor/__test-utils__/fold.js.map +1 -0
  16. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +1 -1
  17. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -1
  18. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +52 -14
  19. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +46 -12
  20. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
  21. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +21 -28
  22. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +27 -11
  23. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -1
  24. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.d.ts +70 -26
  25. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js +82 -32
  26. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js.map +1 -1
  27. package/dist/activities/execute-cursor/adapter.d.ts +8 -7
  28. package/dist/activities/execute-cursor/adapter.js +13 -9
  29. package/dist/activities/execute-cursor/adapter.js.map +1 -1
  30. package/dist/activities/execute-cursor/approval-policy.d.ts +10 -10
  31. package/dist/activities/execute-cursor/approval-policy.js +12 -23
  32. package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
  33. package/dist/activities/execute-cursor/approval-state.d.ts +35 -1
  34. package/dist/activities/execute-cursor/approval-state.js +65 -0
  35. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  36. package/dist/activities/execute-cursor/{message-translator.d.ts → boundary-rows.d.ts} +45 -341
  37. package/dist/activities/execute-cursor/boundary-rows.js +1018 -0
  38. package/dist/activities/execute-cursor/boundary-rows.js.map +1 -0
  39. package/dist/activities/execute-cursor/cursor-capabilities.d.ts +1 -1
  40. package/dist/activities/execute-cursor/cursor-capabilities.js +1 -1
  41. package/dist/activities/execute-cursor/cursor-event-recorder.d.ts +33 -14
  42. package/dist/activities/execute-cursor/cursor-event-recorder.js +43 -21
  43. package/dist/activities/execute-cursor/cursor-event-recorder.js.map +1 -1
  44. package/dist/activities/execute-cursor/prompt-builder.d.ts +3 -3
  45. package/dist/activities/execute-cursor/prompt-builder.js +4 -4
  46. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  47. package/dist/activities/execute-cursor/sdk-warmup.d.ts +15 -6
  48. package/dist/activities/execute-cursor/sdk-warmup.js +15 -6
  49. package/dist/activities/execute-cursor/sdk-warmup.js.map +1 -1
  50. package/dist/activities/execute-cursor/service-tier.js +1 -2
  51. package/dist/activities/execute-cursor/service-tier.js.map +1 -1
  52. package/dist/activities/execute-cursor/session-lifecycle.d.ts +38 -59
  53. package/dist/activities/execute-cursor/session-lifecycle.js +59 -96
  54. package/dist/activities/execute-cursor/session-lifecycle.js.map +1 -1
  55. package/dist/activities/execute-cursor/session-store.d.ts +100 -0
  56. package/dist/activities/execute-cursor/session-store.js +157 -0
  57. package/dist/activities/execute-cursor/session-store.js.map +1 -0
  58. package/dist/activities/execute-cursor/sub-agent-steps.d.ts +79 -0
  59. package/dist/activities/execute-cursor/sub-agent-steps.js +180 -0
  60. package/dist/activities/execute-cursor/sub-agent-steps.js.map +1 -0
  61. package/dist/activities/execute-cursor/tool-result.d.ts +49 -0
  62. package/dist/activities/execute-cursor/tool-result.js +130 -0
  63. package/dist/activities/execute-cursor/tool-result.js.map +1 -0
  64. package/dist/activities/execute-cursor/translator.d.ts +178 -0
  65. package/dist/activities/execute-cursor/translator.js +485 -0
  66. package/dist/activities/execute-cursor/translator.js.map +1 -0
  67. package/dist/activities/execute-cursor/turn-boundary.d.ts +15 -5
  68. package/dist/activities/execute-cursor/turn-boundary.js +10 -14
  69. package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
  70. package/dist/activities/execute-cursor/turn-settle.d.ts +11 -7
  71. package/dist/activities/execute-cursor/turn-settle.js +47 -34
  72. package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
  73. package/dist/activities/execute-cursor/turn-setup.d.ts +2 -2
  74. package/dist/activities/execute-cursor/turn-setup.js +5 -5
  75. package/dist/activities/execute-cursor/turn-setup.js.map +1 -1
  76. package/dist/activities/execute-cursor/turn-stream.d.ts +23 -14
  77. package/dist/activities/execute-cursor/turn-stream.js +41 -28
  78. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  79. package/dist/activities/execute-cursor/turn.d.ts +4 -4
  80. package/dist/activities/execute-cursor/turn.js +5 -5
  81. package/dist/activities/execute-cursor/usage-pricing.d.ts +2 -2
  82. package/dist/activities/execute-cursor/usage-pricing.js +2 -2
  83. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.d.ts +2 -2
  84. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js +2 -2
  85. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +16 -11
  86. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +22 -10
  87. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -1
  88. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js +1 -1
  89. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js.map +1 -1
  90. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.d.ts +2 -3
  91. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js +2 -3
  92. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js.map +1 -1
  93. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +12 -3
  94. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +18 -4
  95. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -1
  96. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.d.ts +10 -1
  97. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js +24 -11
  98. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js.map +1 -1
  99. package/dist/activities/execute-deep-agent/adapter.d.ts +1 -1
  100. package/dist/activities/execute-deep-agent/adapter.js +1 -1
  101. package/dist/activities/execute-deep-agent/approval-file-change.d.ts +19 -19
  102. package/dist/activities/execute-deep-agent/approval-file-change.js +16 -15
  103. package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -1
  104. package/dist/activities/execute-deep-agent/deep-agent-capabilities.d.ts +2 -2
  105. package/dist/activities/execute-deep-agent/deep-agent-capabilities.js +2 -2
  106. package/dist/activities/execute-deep-agent/hitl.d.ts +2 -2
  107. package/dist/activities/execute-deep-agent/hitl.js +2 -2
  108. package/dist/activities/execute-deep-agent/inline-publisher.d.ts +13 -3
  109. package/dist/activities/execute-deep-agent/inline-publisher.js +3 -3
  110. package/dist/activities/execute-deep-agent/inline-publisher.js.map +1 -1
  111. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +3 -3
  112. package/dist/activities/execute-deep-agent/prompt-builder.js +6 -7
  113. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  114. package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +16 -8
  115. package/dist/activities/execute-deep-agent/streaming-side-effects.js +20 -33
  116. package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
  117. package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +3 -3
  118. package/dist/activities/execute-deep-agent/subagent-transformer.js +1 -1
  119. package/dist/activities/execute-deep-agent/translator.d.ts +134 -0
  120. package/dist/activities/execute-deep-agent/translator.js +418 -0
  121. package/dist/activities/execute-deep-agent/translator.js.map +1 -0
  122. package/dist/activities/execute-deep-agent/turn-settle.d.ts +13 -7
  123. package/dist/activities/execute-deep-agent/turn-settle.js +34 -45
  124. package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -1
  125. package/dist/activities/execute-deep-agent/turn-setup.d.ts +8 -8
  126. package/dist/activities/execute-deep-agent/turn-setup.js +7 -7
  127. package/dist/activities/execute-deep-agent/turn-stream.d.ts +13 -10
  128. package/dist/activities/execute-deep-agent/turn-stream.js +44 -41
  129. package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -1
  130. package/dist/activities/execute-deep-agent/turn.d.ts +3 -3
  131. package/dist/activities/execute-deep-agent/turn.js +3 -3
  132. package/dist/config.d.ts +2 -2
  133. package/dist/harness/approval-decisions.d.ts +1 -1
  134. package/dist/harness/approval-decisions.js +1 -1
  135. package/dist/harness/capabilities.d.ts +21 -11
  136. package/dist/harness/capabilities.js +2 -2
  137. package/dist/harness/capture.d.ts +4 -4
  138. package/dist/harness/capture.js +4 -4
  139. package/dist/harness/persist-chokepoint.d.ts +3 -3
  140. package/dist/harness/persist-chokepoint.js +3 -3
  141. package/dist/harness/registry.d.ts +2 -2
  142. package/dist/harness/registry.js +2 -2
  143. package/dist/harness/run-turn.d.ts +6 -4
  144. package/dist/harness/run-turn.js +31 -9
  145. package/dist/harness/run-turn.js.map +1 -1
  146. package/dist/harness/stop-controller.d.ts +1 -1
  147. package/dist/harness/stop-controller.js +1 -1
  148. package/dist/harness/terminal-table.d.ts +7 -7
  149. package/dist/harness/terminal-table.js +7 -7
  150. package/dist/harness/transcript/builder.d.ts +182 -0
  151. package/dist/harness/transcript/builder.js +693 -0
  152. package/dist/harness/transcript/builder.js.map +1 -0
  153. package/dist/harness/transcript/events.d.ts +218 -0
  154. package/dist/harness/transcript/events.js +50 -0
  155. package/dist/harness/transcript/events.js.map +1 -0
  156. package/dist/harness/transcript/state.d.ts +110 -0
  157. package/dist/harness/transcript/state.js +148 -0
  158. package/dist/harness/transcript/state.js.map +1 -0
  159. package/dist/harness/turn-context.d.ts +54 -38
  160. package/dist/harness/turn-context.js +42 -43
  161. package/dist/harness/turn-context.js.map +1 -1
  162. package/dist/harness/types.d.ts +63 -22
  163. package/dist/harness/types.js +12 -11
  164. package/dist/harness/types.js.map +1 -1
  165. package/dist/harness/usage-accumulator.d.ts +2 -2
  166. package/dist/harness/usage-accumulator.js +2 -2
  167. package/dist/harness-adapters.d.ts +5 -4
  168. package/dist/harness-adapters.js +5 -4
  169. package/dist/harness-adapters.js.map +1 -1
  170. package/dist/middleware/approval-gate.d.ts +6 -0
  171. package/dist/middleware/approval-gate.js +7 -57
  172. package/dist/middleware/approval-gate.js.map +1 -1
  173. package/dist/middleware/cost-advisory.d.ts +3 -3
  174. package/dist/middleware/cost-advisory.js +3 -3
  175. package/dist/middleware/index.d.ts +1 -1
  176. package/dist/middleware/index.js +1 -1
  177. package/dist/runner-manager.js +1 -1
  178. package/dist/runner-manager.js.map +1 -1
  179. package/dist/shared/approval-policy.d.ts +53 -0
  180. package/dist/shared/approval-policy.js +76 -0
  181. package/dist/shared/approval-policy.js.map +1 -1
  182. package/dist/shared/args-preview.d.ts +45 -22
  183. package/dist/shared/args-preview.js +51 -41
  184. package/dist/shared/args-preview.js.map +1 -1
  185. package/dist/shared/attachment-resolver.d.ts +4 -4
  186. package/dist/shared/attachment-resolver.js +4 -4
  187. package/dist/shared/attachment-vision.d.ts +2 -1
  188. package/dist/shared/attachment-vision.js.map +1 -1
  189. package/dist/shared/attachment-zip.d.ts +2 -2
  190. package/dist/shared/attachment-zip.js +2 -2
  191. package/dist/shared/cost-guard.d.ts +2 -2
  192. package/dist/shared/cost-guard.js +2 -2
  193. package/dist/shared/exact-apply.d.ts +1 -1
  194. package/dist/shared/exact-apply.js +1 -1
  195. package/dist/shared/execution-context.d.ts +2 -2
  196. package/dist/shared/execution-context.js +2 -2
  197. package/dist/shared/extract-structured-output.d.ts +2 -2
  198. package/dist/shared/extract-structured-output.js +2 -2
  199. package/dist/shared/filereview/cas-touched.d.ts +2 -2
  200. package/dist/shared/filereview/cas-touched.js +2 -2
  201. package/dist/shared/heartbeat.d.ts +1 -1
  202. package/dist/shared/heartbeat.js +1 -1
  203. package/dist/shared/llm-backend.d.ts +0 -4
  204. package/dist/shared/llm-backend.js +0 -4
  205. package/dist/shared/llm-backend.js.map +1 -1
  206. package/dist/shared/model-error.d.ts +1 -2
  207. package/dist/shared/model-error.js +1 -2
  208. package/dist/shared/model-error.js.map +1 -1
  209. package/dist/shared/persist-decision.d.ts +18 -24
  210. package/dist/shared/persist-decision.js +19 -11
  211. package/dist/shared/persist-decision.js.map +1 -1
  212. package/dist/shared/prompt-sections.d.ts +4 -4
  213. package/dist/shared/prompt-sections.js +4 -4
  214. package/dist/shared/skill-resolver.d.ts +3 -3
  215. package/dist/shared/skill-resolver.js +3 -3
  216. package/dist/shared/status-offload.d.ts +1 -1
  217. package/dist/shared/status-offload.js +2 -2
  218. package/dist/shared/status-offload.js.map +1 -1
  219. package/dist/shared/streaming-scheduler.d.ts +2 -7
  220. package/dist/shared/streaming-scheduler.js +6 -14
  221. package/dist/shared/streaming-scheduler.js.map +1 -1
  222. package/dist/shared/subagent-rows.d.ts +2 -2
  223. package/dist/shared/subagent-rows.js +2 -2
  224. package/dist/shared/todos.d.ts +3 -3
  225. package/dist/shared/todos.js +3 -3
  226. package/dist/shared/tool-row.d.ts +19 -1
  227. package/dist/shared/tool-row.js +36 -2
  228. package/dist/shared/tool-row.js.map +1 -1
  229. package/dist/shared/worker-shutdown.d.ts +1 -1
  230. package/dist/shared/worker-shutdown.js +1 -1
  231. package/dist/shared/workspace/session-provision.d.ts +1 -1
  232. package/dist/shared/workspace/session-provision.js +1 -1
  233. package/dist/shared/workspace/sources/empty.d.ts +1 -1
  234. package/dist/shared/workspace/sources/empty.js +1 -2
  235. package/dist/shared/workspace/sources/empty.js.map +1 -1
  236. package/dist/shared/workspace/sources/git.js +4 -4
  237. package/dist/shared/workspace/sources/git.js.map +1 -1
  238. package/dist/shared/workspace/sources/local-path.js +6 -6
  239. package/dist/shared/workspace/sources/local-path.js.map +1 -1
  240. package/dist/shared/workspace/stigmer-link.d.ts +1 -1
  241. package/dist/shared/workspace/stigmer-link.js +1 -1
  242. package/dist/shared/workspace/types.d.ts +2 -5
  243. package/dist/shared/workspace/types.js +0 -6
  244. package/dist/shared/workspace/types.js.map +1 -1
  245. package/dist/shared/workspace/writeback-coordinator.d.ts +17 -4
  246. package/dist/shared/workspace/writeback-coordinator.js +7 -9
  247. package/dist/shared/workspace/writeback-coordinator.js.map +1 -1
  248. package/package.json +5 -5
  249. package/src/__test-utils__/__tests__/execution-record-barrier.test.ts +70 -0
  250. package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +35 -1
  251. package/src/__test-utils__/approval-contract/contract.ts +1 -1
  252. package/src/__test-utils__/approval-contract/types.ts +1 -1
  253. package/src/__test-utils__/harness-boot-order-child.ts +1 -1
  254. package/src/__test-utils__/harness-contract/contract.ts +8 -8
  255. package/src/__test-utils__/harness-contract/recording-sink.ts +11 -1
  256. package/src/__test-utils__/harness-contract/runtime-contract.ts +52 -16
  257. package/src/__test-utils__/harness-contract/scripted-adapter.ts +47 -43
  258. package/src/__test-utils__/hermetic-activity.ts +113 -9
  259. package/src/__test-utils__/model-registry-fixture.ts +31 -7
  260. package/src/__test-utils__/module-specifiers.ts +32 -3
  261. package/src/__tests__/harness-boot-order.test.ts +1 -1
  262. package/src/__tests__/harness-contract.test.ts +1 -1
  263. package/src/__tests__/runner-manager.test.ts +1 -1
  264. package/src/activities/execute-cursor/__test-utils__/__tests__/scripted-double.test.ts +32 -8
  265. package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +12 -10
  266. package/src/activities/execute-cursor/__test-utils__/fold.ts +116 -0
  267. package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +1 -1
  268. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +72 -19
  269. package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +35 -29
  270. package/src/activities/execute-cursor/__test-utils__/scripted-sdk.ts +94 -38
  271. package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +2 -1
  272. package/src/activities/execute-cursor/__tests__/approval-state.test.ts +14 -21
  273. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +3 -3
  274. package/src/activities/execute-cursor/__tests__/coarse-fingerprint.test.ts +2 -1
  275. package/src/activities/execute-cursor/__tests__/cursor-baseurl-routing.test.ts +10 -8
  276. package/src/activities/execute-cursor/__tests__/cursor-event-recorder.test.ts +142 -0
  277. package/src/activities/execute-cursor/__tests__/cursor-fetch-interceptor-bypass.test.ts +24 -12
  278. package/src/activities/execute-cursor/__tests__/cursor-generate-image-live.test.ts +7 -2
  279. package/src/activities/execute-cursor/__tests__/cursor-hook-protocol-live.test.ts +163 -0
  280. package/src/activities/execute-cursor/__tests__/cursor-sdk-auth-smoke.test.ts +23 -20
  281. package/src/activities/execute-cursor/__tests__/cursor-transcript-live.test.ts +298 -0
  282. package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +4 -2
  283. package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +1 -1
  284. package/src/activities/execute-cursor/__tests__/hermetic/deny-and-retry.test.ts +5 -2
  285. package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +5 -2
  286. package/src/activities/execute-cursor/__tests__/hermetic/goldens/mcp-tool-call.status.json +71 -0
  287. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-task-note.status.json +73 -0
  288. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.error-delta.status.json +78 -0
  289. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.output-first.status.json +72 -0
  290. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.status.json +72 -0
  291. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sub-agent-delegation.status.json +109 -0
  292. package/src/activities/execute-cursor/__tests__/hermetic/goldens/thinking-turn.status.json +78 -0
  293. package/src/activities/execute-cursor/__tests__/hermetic/goldens/todo-write.status.json +119 -0
  294. package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-error.status.json +68 -0
  295. package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-only-step.status.json +67 -0
  296. package/src/activities/execute-cursor/__tests__/hermetic/goldens/unattributed-hook-block.status.json +1 -1
  297. package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +10 -7
  298. package/src/activities/execute-cursor/__tests__/hermetic/mcp-tool-call.test.ts +146 -0
  299. package/src/activities/execute-cursor/__tests__/hermetic/pause-vs-shutdown.test.ts +8 -5
  300. package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +6 -2
  301. package/src/activities/execute-cursor/__tests__/hermetic/recovery-fresh-agent.test.ts +4 -1
  302. package/src/activities/execute-cursor/__tests__/hermetic/run-wait-arms.test.ts +6 -2
  303. package/src/activities/execute-cursor/__tests__/hermetic/sdk-task-note.test.ts +122 -0
  304. package/src/activities/execute-cursor/__tests__/hermetic/shell-output-delta.test.ts +276 -0
  305. package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +12 -9
  306. package/src/activities/execute-cursor/__tests__/hermetic/sub-agent-delegation.test.ts +196 -0
  307. package/src/activities/execute-cursor/__tests__/hermetic/thinking-turn.test.ts +145 -0
  308. package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +4 -1
  309. package/src/activities/execute-cursor/__tests__/hermetic/todo-write.test.ts +165 -0
  310. package/src/activities/execute-cursor/__tests__/hermetic/tool-call.test.ts +7 -4
  311. package/src/activities/execute-cursor/__tests__/hermetic/tool-error.test.ts +138 -0
  312. package/src/activities/execute-cursor/__tests__/hermetic/tool-only-step.test.ts +130 -0
  313. package/src/activities/execute-cursor/__tests__/hermetic/unattributed-hook-block.test.ts +17 -2
  314. package/src/activities/execute-cursor/__tests__/hermetic/workspace-lock-timeout.test.ts +5 -2
  315. package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +43 -60
  316. package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +23 -28
  317. package/src/activities/execute-cursor/__tests__/hook-script.test.ts +2 -1
  318. package/src/activities/execute-cursor/__tests__/http2-interceptor.test.ts +1 -1
  319. package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +5 -5
  320. package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +11 -13
  321. package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +8 -11
  322. package/src/activities/execute-cursor/__tests__/session-lifecycle.test.ts +86 -58
  323. package/src/activities/execute-cursor/__tests__/session-store.test.ts +220 -0
  324. package/src/activities/execute-cursor/__tests__/tool-result-image.test.ts +8 -22
  325. package/src/activities/execute-cursor/__tests__/translator.test.ts +594 -0
  326. package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +8 -5
  327. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +87 -63
  328. package/src/activities/execute-cursor/adapter.ts +13 -9
  329. package/src/activities/execute-cursor/approval-policy.ts +12 -24
  330. package/src/activities/execute-cursor/approval-state.ts +66 -1
  331. package/src/activities/execute-cursor/boundary-rows.ts +1132 -0
  332. package/src/activities/execute-cursor/cursor-capabilities.ts +1 -1
  333. package/src/activities/execute-cursor/cursor-event-recorder.ts +57 -28
  334. package/src/activities/execute-cursor/fetch-interceptor.ts +1 -1
  335. package/src/activities/execute-cursor/http2-interceptor.ts +1 -1
  336. package/src/activities/execute-cursor/prompt-builder.ts +6 -6
  337. package/src/activities/execute-cursor/sdk-warmup.ts +15 -6
  338. package/src/activities/execute-cursor/service-tier.ts +1 -2
  339. package/src/activities/execute-cursor/session-lifecycle.ts +63 -109
  340. package/src/activities/execute-cursor/session-store.ts +187 -0
  341. package/src/activities/execute-cursor/sub-agent-steps.ts +188 -0
  342. package/src/activities/execute-cursor/tool-result.ts +128 -0
  343. package/src/activities/execute-cursor/translator.ts +541 -0
  344. package/src/activities/execute-cursor/turn-boundary.ts +21 -14
  345. package/src/activities/execute-cursor/turn-settle.ts +46 -34
  346. package/src/activities/execute-cursor/turn-setup.ts +5 -5
  347. package/src/activities/execute-cursor/turn-stream.ts +49 -46
  348. package/src/activities/execute-cursor/turn.ts +5 -5
  349. package/src/activities/execute-cursor/usage-pricing.ts +2 -2
  350. package/src/activities/execute-deep-agent/__test-utils__/contract-subject.ts +2 -2
  351. package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +23 -11
  352. package/src/activities/execute-deep-agent/__test-utils__/hitl-script.ts +1 -1
  353. package/src/activities/execute-deep-agent/__test-utils__/scripted-model-module.ts +2 -3
  354. package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +25 -4
  355. package/src/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.ts +25 -11
  356. package/src/activities/execute-deep-agent/__tests__/adapter-graph-is-sdk-free.test.ts +1 -1
  357. package/src/activities/execute-deep-agent/__tests__/adapter-is-temporal-free.test.ts +1 -1
  358. package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +6 -17
  359. package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +25 -8
  360. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn1.status.json +2 -7
  361. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn2.status.json +4 -14
  362. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve.turn2.status.json +1 -5
  363. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +4 -7
  364. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/gate.turn1.status.json +1 -5
  365. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +2 -9
  366. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +2 -9
  367. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.after-tool.status.json +1 -4
  368. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.mid-tool.status.json +1 -4
  369. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/platform-stop.status.json +1 -4
  370. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +109 -76
  371. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/reject.turn2.status.json +1 -5
  372. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn2.status.json +2 -10
  373. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn3.status.json +2 -10
  374. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/skip.turn2.status.json +1 -5
  375. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +3 -6
  376. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +1 -4
  377. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/worker-shutdown.status.json +1 -4
  378. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/write-todos.status.json +92 -0
  379. package/src/activities/execute-deep-agent/__tests__/hermetic/harness-contract.test.ts +3 -3
  380. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-approve-all-lease.test.ts +9 -5
  381. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-round-trips.test.ts +3 -3
  382. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts +3 -3
  383. package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +7 -6
  384. package/src/activities/execute-deep-agent/__tests__/hermetic/pause-vs-shutdown.test.ts +10 -11
  385. package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +4 -4
  386. package/src/activities/execute-deep-agent/__tests__/hermetic/platform-stop.test.ts +9 -8
  387. package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +21 -13
  388. package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +2 -2
  389. package/src/activities/execute-deep-agent/__tests__/hermetic/structured-output.test.ts +7 -7
  390. package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +28 -12
  391. package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +21 -21
  392. package/src/activities/execute-deep-agent/__tests__/hermetic/workspace-lock-timeout.test.ts +5 -5
  393. package/src/activities/execute-deep-agent/__tests__/hermetic/write-todos.test.ts +160 -0
  394. package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +35 -30
  395. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +3 -4
  396. package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +12 -10
  397. package/src/activities/execute-deep-agent/__tests__/scripted-model.test.ts +13 -3
  398. package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +26 -18
  399. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +1 -1
  400. package/src/activities/execute-deep-agent/__tests__/{subagent-tracker.test.ts → translator-subagents.test.ts} +76 -57
  401. package/src/activities/execute-deep-agent/__tests__/{v3-status-builder.test.ts → translator-through-builder.test.ts} +213 -299
  402. package/src/activities/execute-deep-agent/__tests__/translator.test.ts +505 -0
  403. package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +11 -29
  404. package/src/activities/execute-deep-agent/adapter.ts +1 -1
  405. package/src/activities/execute-deep-agent/approval-file-change.ts +20 -22
  406. package/src/activities/execute-deep-agent/deep-agent-capabilities.ts +2 -2
  407. package/src/activities/execute-deep-agent/hitl.ts +2 -2
  408. package/src/activities/execute-deep-agent/inline-publisher.ts +16 -5
  409. package/src/activities/execute-deep-agent/prompt-builder.ts +6 -7
  410. package/src/activities/execute-deep-agent/streaming-side-effects.ts +22 -31
  411. package/src/activities/execute-deep-agent/subagent-transformer.ts +3 -3
  412. package/src/activities/execute-deep-agent/translator.ts +463 -0
  413. package/src/activities/execute-deep-agent/turn-settle.ts +35 -43
  414. package/src/activities/execute-deep-agent/turn-setup.ts +8 -8
  415. package/src/activities/execute-deep-agent/turn-stream.ts +53 -51
  416. package/src/activities/execute-deep-agent/turn.ts +3 -3
  417. package/src/config.ts +2 -2
  418. package/src/harness/README.md +335 -0
  419. package/src/harness/__tests__/approval-decisions.test.ts +2 -2
  420. package/src/harness/__tests__/capture.test.ts +3 -3
  421. package/src/harness/__tests__/import-direction.test.ts +3 -2
  422. package/src/harness/__tests__/mount-skills.test.ts +4 -1
  423. package/src/harness/__tests__/readme-index.test.ts +339 -0
  424. package/src/harness/__tests__/run-turn.test.ts +131 -6
  425. package/src/harness/__tests__/transcript-is-engine-free.test.ts +83 -0
  426. package/src/harness/__tests__/transcript-writers.test.ts +191 -0
  427. package/src/harness/__tests__/turn-attachments-vision.test.ts +5 -2
  428. package/src/harness/__tests__/turn-context.test.ts +5 -5
  429. package/src/harness/approval-decisions.ts +1 -1
  430. package/src/harness/capabilities.ts +21 -11
  431. package/src/harness/capture.ts +4 -4
  432. package/src/harness/persist-chokepoint.ts +3 -3
  433. package/src/harness/registry.ts +2 -2
  434. package/src/harness/run-turn.ts +33 -9
  435. package/src/harness/stop-controller.ts +1 -1
  436. package/src/harness/terminal-table.ts +7 -7
  437. package/src/harness/transcript/__tests__/builder.test.ts +975 -0
  438. package/src/harness/transcript/__tests__/state.test.ts +143 -0
  439. package/src/harness/transcript/builder.ts +755 -0
  440. package/src/harness/transcript/events.ts +262 -0
  441. package/src/harness/transcript/state.ts +167 -0
  442. package/src/harness/turn-context.ts +61 -46
  443. package/src/harness/types.ts +64 -22
  444. package/src/harness/usage-accumulator.ts +2 -2
  445. package/src/harness-adapters.ts +5 -4
  446. package/src/middleware/__tests__/cost-advisory.test.ts +2 -2
  447. package/src/middleware/approval-gate.ts +7 -74
  448. package/src/middleware/cost-advisory.ts +3 -3
  449. package/src/middleware/index.ts +1 -1
  450. package/src/runner-manager.ts +1 -1
  451. package/src/shared/__tests__/approval-policy.test.ts +45 -0
  452. package/src/shared/__tests__/args-preview.test.ts +40 -20
  453. package/src/shared/__tests__/attachment-naming.test.ts +1 -1
  454. package/src/shared/__tests__/attachment-resolver.test.ts +5 -5
  455. package/src/shared/__tests__/attachment-zip.test.ts +1 -1
  456. package/src/shared/__tests__/blueprint-resolver.test.ts +1 -1
  457. package/src/shared/__tests__/cost-guard.test.ts +1 -1
  458. package/src/shared/__tests__/exact-apply.test.ts +2 -1
  459. package/src/shared/__tests__/persist-decision.test.ts +19 -33
  460. package/src/shared/__tests__/prompt-sections.test.ts +1 -1
  461. package/src/shared/__tests__/stamp-flowed-rows.test.ts +1 -1
  462. package/src/shared/__tests__/status-offload.test.ts +1 -1
  463. package/src/shared/__tests__/streaming-scheduler.test.ts +8 -9
  464. package/src/shared/__tests__/todos.test.ts +1 -1
  465. package/src/shared/__tests__/tool-row.test.ts +1 -1
  466. package/src/shared/approval-policy.ts +95 -0
  467. package/src/shared/args-preview.ts +51 -42
  468. package/src/shared/attachment-resolver.ts +4 -4
  469. package/src/shared/attachment-vision.ts +2 -1
  470. package/src/shared/attachment-zip.ts +2 -2
  471. package/src/shared/cost-guard.ts +2 -2
  472. package/src/shared/exact-apply.ts +1 -1
  473. package/src/shared/execution-context.ts +2 -2
  474. package/src/shared/extract-structured-output.ts +2 -2
  475. package/src/shared/filereview/__tests__/capture.test.ts +9 -5
  476. package/src/shared/filereview/__tests__/git-substrate.test.ts +4 -1
  477. package/src/shared/filereview/__tests__/proxy-reconcile.test.ts +3 -3
  478. package/src/shared/filereview/cas-touched.ts +2 -2
  479. package/src/shared/heartbeat.ts +1 -1
  480. package/src/shared/llm-backend.ts +0 -4
  481. package/src/shared/model-error.ts +1 -2
  482. package/src/shared/persist-decision.ts +19 -28
  483. package/src/shared/prompt-sections.ts +4 -4
  484. package/src/shared/skill-resolver.ts +3 -3
  485. package/src/shared/status-offload.ts +2 -2
  486. package/src/shared/streaming-scheduler.ts +8 -13
  487. package/src/shared/subagent-rows.ts +2 -2
  488. package/src/shared/todos.ts +3 -3
  489. package/src/shared/tool-row.ts +38 -2
  490. package/src/shared/worker-shutdown.ts +1 -1
  491. package/src/shared/workspace/__tests__/git-source.test.ts +3 -3
  492. package/src/shared/workspace/__tests__/provisioner.test.ts +5 -5
  493. package/src/shared/workspace/__tests__/session-provision.test.ts +2 -2
  494. package/src/shared/workspace/__tests__/writeback-coordinator.integration.test.ts +8 -9
  495. package/src/shared/workspace/__tests__/writeback-coordinator.test.ts +25 -25
  496. package/src/shared/workspace/provisioner.ts +1 -1
  497. package/src/shared/workspace/session-provision.ts +1 -1
  498. package/src/shared/workspace/sources/empty.ts +2 -2
  499. package/src/shared/workspace/sources/git.ts +3 -4
  500. package/src/shared/workspace/sources/local-path.ts +5 -6
  501. package/src/shared/workspace/stigmer-link.ts +1 -1
  502. package/src/shared/workspace/types.ts +2 -5
  503. package/src/shared/workspace/writeback-coordinator.ts +23 -12
  504. package/dist/activities/execute-cursor/delta-enricher.d.ts +0 -87
  505. package/dist/activities/execute-cursor/delta-enricher.js +0 -265
  506. package/dist/activities/execute-cursor/delta-enricher.js.map +0 -1
  507. package/dist/activities/execute-cursor/message-translator.js +0 -2040
  508. package/dist/activities/execute-cursor/message-translator.js.map +0 -1
  509. package/dist/activities/execute-cursor/todo-tracker.d.ts +0 -40
  510. package/dist/activities/execute-cursor/todo-tracker.js +0 -80
  511. package/dist/activities/execute-cursor/todo-tracker.js.map +0 -1
  512. package/dist/activities/execute-deep-agent/execution-state.d.ts +0 -54
  513. package/dist/activities/execute-deep-agent/execution-state.js +0 -68
  514. package/dist/activities/execute-deep-agent/execution-state.js.map +0 -1
  515. package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +0 -65
  516. package/dist/activities/execute-deep-agent/status-builder-shared.js +0 -90
  517. package/dist/activities/execute-deep-agent/status-builder-shared.js.map +0 -1
  518. package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +0 -113
  519. package/dist/activities/execute-deep-agent/subagent-tracker.js +0 -400
  520. package/dist/activities/execute-deep-agent/subagent-tracker.js.map +0 -1
  521. package/dist/activities/execute-deep-agent/v3-events.d.ts +0 -102
  522. package/dist/activities/execute-deep-agent/v3-events.js +0 -35
  523. package/dist/activities/execute-deep-agent/v3-events.js.map +0 -1
  524. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.d.ts +0 -15
  525. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js +0 -235
  526. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js.map +0 -1
  527. package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +0 -111
  528. package/dist/activities/execute-deep-agent/v3-status-builder.js +0 -457
  529. package/dist/activities/execute-deep-agent/v3-status-builder.js.map +0 -1
  530. package/dist/shared/execution-status-writer.d.ts +0 -31
  531. package/dist/shared/execution-status-writer.js +0 -43
  532. package/dist/shared/execution-status-writer.js.map +0 -1
  533. package/src/activities/execute-cursor/__tests__/delta-enricher.test.ts +0 -310
  534. package/src/activities/execute-cursor/__tests__/message-translator.test.ts +0 -1033
  535. package/src/activities/execute-cursor/__tests__/todo-tracker.test.ts +0 -498
  536. package/src/activities/execute-cursor/delta-enricher.ts +0 -307
  537. package/src/activities/execute-cursor/message-translator.ts +0 -2319
  538. package/src/activities/execute-cursor/todo-tracker.ts +0 -91
  539. package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +0 -148
  540. package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +0 -154
  541. package/src/activities/execute-deep-agent/__tests__/status-builder-shared.test.ts +0 -47
  542. package/src/activities/execute-deep-agent/__tests__/v3-protocol-normalizer.test.ts +0 -324
  543. package/src/activities/execute-deep-agent/execution-state.ts +0 -78
  544. package/src/activities/execute-deep-agent/status-builder-shared.ts +0 -142
  545. package/src/activities/execute-deep-agent/subagent-tracker.ts +0 -479
  546. package/src/activities/execute-deep-agent/v3-events.ts +0 -153
  547. package/src/activities/execute-deep-agent/v3-protocol-normalizer.ts +0 -264
  548. package/src/activities/execute-deep-agent/v3-status-builder.ts +0 -565
  549. package/src/shared/execution-status-writer.ts +0 -56
@@ -1,5 +1,9 @@
1
1
  /**
2
- * @regression file-hitl-phase0 — pins file-edit HITL fixes #1, #2, #3, #5 (see _projects/2026-06/20260630.01.file-change-hitl-redesign/tasks/T01_3_regression-manifest.md)
2
+ * @regression file-hitl-phase0 — pins four rules of the file-edit gate: one
3
+ * approval gate per turn (a distinct co-pending sibling defers to SKIPPED);
4
+ * decisions bind to the active turn's ledger, never a stale one; the executed
5
+ * capture supersedes the model's proposal; the hook-captured input is
6
+ * authoritative over the streamed snapshot.
3
7
  *
4
8
  * Unit tests for the Cursor-harness HITL denial-ledger flow.
5
9
  *
@@ -61,11 +65,12 @@ import {
61
65
  reconcileDeniedToolCalls,
62
66
  clearProvisionalPostDenialNarration,
63
67
  collapseRedundantToolCallTwins,
64
- toolCallIdentityToken,
65
68
  detectUnattributedHookBlocks,
66
69
  stampUnattendedSkippedToolCalls,
67
70
  HOOK_BLOCK_ERROR_MARKERS,
68
- } from "../message-translator.js";
71
+ } from "../boundary-rows.js";
72
+ import { builderOver } from "../__test-utils__/fold.js";
73
+ import { toolCallIdentityToken } from "../approval-state.js";
69
74
  import { mockWorkspaceBackend } from "../../../__test-utils__/mock-workspace.js";
70
75
  import type { WorkspaceBackend } from "../../../shared/workspace/types.js";
71
76
  import { generateHookScript } from "../hook-script.js";
@@ -240,7 +245,7 @@ describe("reconcileDeniedToolCalls", () => {
240
245
  });
241
246
  const messages = [aiMessageWith([tc])];
242
247
 
243
- const reconciled = await reconcileDeniedToolCalls(messages, [
248
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages), [
244
249
  { toolName: "Write", token: grantToken("write", "gated.txt") },
245
250
  ]);
246
251
 
@@ -279,7 +284,7 @@ describe("reconcileDeniedToolCalls", () => {
279
284
  ]);
280
285
 
281
286
  // MCP tools are keyed name-only (their name is consistent across layers).
282
- await reconcileDeniedToolCalls(messages, [
287
+ await reconcileDeniedToolCalls(messages, builderOver(messages), [
283
288
  { toolName: "apply_x", token: grantToken("apply_x", "") },
284
289
  ], policies);
285
290
 
@@ -302,7 +307,7 @@ describe("reconcileDeniedToolCalls", () => {
302
307
  });
303
308
  const messages = [aiMessageWith([denied, allowed])];
304
309
 
305
- const reconciled = await reconcileDeniedToolCalls(messages, [
310
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages), [
306
311
  { toolName: "Write", token: grantToken("write", "gated.txt") },
307
312
  ]);
308
313
 
@@ -323,7 +328,7 @@ describe("reconcileDeniedToolCalls", () => {
323
328
  const second = toolCall({ id: "c2", name: "edit", args: { path: "gated.txt" } });
324
329
  const messages = [aiMessageWith([first, second])];
325
330
 
326
- const reconciled = await reconcileDeniedToolCalls(messages, [
331
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages), [
327
332
  { toolName: "Write", token: grantToken("write", "gated.txt") },
328
333
  ]);
329
334
 
@@ -344,7 +349,7 @@ describe("reconcileDeniedToolCalls", () => {
344
349
  it("synthesizes a WAITING_APPROVAL tool call when a denial produced no stream event", async () => {
345
350
  const messages = [aiMessageWith([])];
346
351
 
347
- const reconciled = await reconcileDeniedToolCalls(messages, [
352
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages), [
348
353
  { toolName: "Shell", token: grantToken("shell", "rm -rf build") },
349
354
  ]);
350
355
 
@@ -363,7 +368,7 @@ describe("reconcileDeniedToolCalls", () => {
363
368
  it("is a no-op when the ledger is empty", async () => {
364
369
  const tc = toolCall({ id: "c1", status: ToolCallStatus.TOOL_CALL_COMPLETED });
365
370
  const messages = [aiMessageWith([tc])];
366
- expect(await reconcileDeniedToolCalls(messages, [])).toEqual([]);
371
+ expect(await reconcileDeniedToolCalls(messages, builderOver(messages), [])).toEqual([]);
367
372
  expect(tc.status).toBe(ToolCallStatus.TOOL_CALL_COMPLETED);
368
373
  });
369
374
  });
@@ -391,8 +396,7 @@ describe("reconcileDeniedToolCalls — duplicate denial-twin collapse", () => {
391
396
  });
392
397
  const messages = [aiMessageWith([gate, twin])];
393
398
 
394
- const reconciled = await reconcileDeniedToolCalls(
395
- messages,
399
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
396
400
  [{ toolName: "Write", token: grantToken("write", "notes.md") }],
397
401
  undefined,
398
402
  rootBackend(),
@@ -432,8 +436,7 @@ describe("reconcileDeniedToolCalls — duplicate denial-twin collapse", () => {
432
436
  });
433
437
  const messages = [aiMessageWith([gate, twin])];
434
438
 
435
- const reconciled = await reconcileDeniedToolCalls(
436
- messages,
439
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
437
440
  [{ toolName: "Shell", token: grantToken("shell", "rm -rf build") }],
438
441
  undefined,
439
442
  rootBackend(),
@@ -470,8 +473,7 @@ describe("reconcileDeniedToolCalls — duplicate denial-twin collapse", () => {
470
473
  });
471
474
  const messages = [aiMessageWith([gateA, gateB])];
472
475
 
473
- const reconciled = await reconcileDeniedToolCalls(
474
- messages,
476
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
475
477
  [
476
478
  // The hook records the content-exact token for an edit (its primary token).
477
479
  { toolName: "Write", token: toolCallIdentityToken(gateA) },
@@ -508,8 +510,7 @@ describe("reconcileDeniedToolCalls — duplicate denial-twin collapse", () => {
508
510
  });
509
511
  const messages = [aiMessageWith([gate, twin])];
510
512
 
511
- await reconcileDeniedToolCalls(
512
- messages,
513
+ await reconcileDeniedToolCalls(messages, builderOver(messages),
513
514
  [{ toolName: "Write", token: grantToken("write", "notes.md") }],
514
515
  undefined,
515
516
  rootBackend(),
@@ -552,8 +553,7 @@ describe("reconcileDeniedToolCalls — one gate per turn (deny-only workaround)"
552
553
  });
553
554
  const messages = [aiMessageWith([edit, shell])];
554
555
 
555
- const reconciled = await reconcileDeniedToolCalls(
556
- messages,
556
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
557
557
  [
558
558
  { toolName: "Write", token: grantToken("write", "notes.md") },
559
559
  { toolName: "Shell", token: grantToken("shell", "cat > notes.md") },
@@ -595,8 +595,7 @@ describe("reconcileDeniedToolCalls — one gate per turn (deny-only workaround)"
595
595
  });
596
596
  const messages = [aiMessageWith([edit]), aiMessageWith([shell])];
597
597
 
598
- const reconciled = await reconcileDeniedToolCalls(
599
- messages,
598
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
600
599
  [
601
600
  { toolName: "Write", token: grantToken("write", "notes.md") },
602
601
  { toolName: "Shell", token: grantToken("shell", "cat > notes.md") },
@@ -631,8 +630,7 @@ describe("reconcileDeniedToolCalls — one gate per turn (deny-only workaround)"
631
630
  });
632
631
  const messages = [aiMessageWith([shell, edit])];
633
632
 
634
- const reconciled = await reconcileDeniedToolCalls(
635
- messages,
633
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
636
634
  [
637
635
  { toolName: "Shell", token: toolCallIdentityToken(shell) },
638
636
  { toolName: "Write", token: toolCallIdentityToken(edit) },
@@ -666,8 +664,7 @@ describe("reconcileDeniedToolCalls — one gate per turn (deny-only workaround)"
666
664
  });
667
665
  const messages = [aiMessageWith([mcp, edit])];
668
666
 
669
- const reconciled = await reconcileDeniedToolCalls(
670
- messages,
667
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
671
668
  [
672
669
  { toolName: "fetch", token: toolCallIdentityToken(mcp) },
673
670
  { toolName: "Write", token: toolCallIdentityToken(edit) },
@@ -692,8 +689,7 @@ describe("reconcileDeniedToolCalls — one gate per turn (deny-only workaround)"
692
689
  });
693
690
  const messages = [aiMessageWith([edit])];
694
691
 
695
- const reconciled = await reconcileDeniedToolCalls(
696
- messages,
692
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
697
693
  [{ toolName: "Write", token: grantToken("write", "notes.md") }],
698
694
  undefined,
699
695
  rootBackend(),
@@ -725,8 +721,7 @@ describe("reconcileDeniedToolCalls — one gate per turn (deny-only workaround)"
725
721
  });
726
722
  const messages = [aiMessageWith([edit, shell])];
727
723
 
728
- const reconciled = await reconcileDeniedToolCalls(
729
- messages,
724
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
730
725
  [
731
726
  { toolName: "Write", token: grantToken("write", "notes.md") },
732
727
  { toolName: "Shell", token: grantToken("shell", "cat > notes.md") },
@@ -801,8 +796,7 @@ describe("reconcileDeniedToolCalls — interrupted non-terminal rows (raced work
801
796
  ];
802
797
 
803
798
  // Only the anchor's denial is in the ledger — the workaround's raced it.
804
- const reconciled = await reconcileDeniedToolCalls(
805
- messages,
799
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
806
800
  [{ toolName: "Shell", token: toolCallIdentityToken(anchor) }],
807
801
  undefined,
808
802
  rootBackend(),
@@ -848,8 +842,7 @@ describe("reconcileDeniedToolCalls — interrupted non-terminal rows (raced work
848
842
  create(AgentMessageSchema, { type: MessageType.MESSAGE_AI, content: "trailing reaction" }),
849
843
  ];
850
844
 
851
- const reconciled = await reconcileDeniedToolCalls(
852
- messages,
845
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
853
846
  [{ toolName: "Shell", token: toolCallIdentityToken(anchor) }],
854
847
  undefined,
855
848
  rootBackend(),
@@ -1066,8 +1059,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
1066
1059
  });
1067
1060
  const messages = [aiMessageWith([tc])];
1068
1061
 
1069
- await reconcileDeniedToolCalls(
1070
- messages,
1062
+ await reconcileDeniedToolCalls(messages, builderOver(messages),
1071
1063
  [{
1072
1064
  toolName: "Write",
1073
1065
  token: grantToken("write", "src/new.ts"),
@@ -1097,8 +1089,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
1097
1089
  });
1098
1090
  const messages = [aiMessageWith([tc])];
1099
1091
 
1100
- await reconcileDeniedToolCalls(
1101
- messages,
1092
+ await reconcileDeniedToolCalls(messages, builderOver(messages),
1102
1093
  [{
1103
1094
  toolName: "Write",
1104
1095
  token: grantToken("write", ".env"),
@@ -1122,8 +1113,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
1122
1113
  });
1123
1114
  const messages = [aiMessageWith([tc])];
1124
1115
 
1125
- await reconcileDeniedToolCalls(
1126
- messages,
1116
+ await reconcileDeniedToolCalls(messages, builderOver(messages),
1127
1117
  [{
1128
1118
  toolName: "StrReplace",
1129
1119
  token: grantToken("write", "src/app.ts"),
@@ -1147,8 +1137,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
1147
1137
  });
1148
1138
  const messages = [aiMessageWith([tc])];
1149
1139
 
1150
- await reconcileDeniedToolCalls(
1151
- messages,
1140
+ await reconcileDeniedToolCalls(messages, builderOver(messages),
1152
1141
  [{
1153
1142
  toolName: "EditNotebook",
1154
1143
  token: grantToken("write", "nb.ipynb"),
@@ -1170,8 +1159,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
1170
1159
  });
1171
1160
  const messages = [aiMessageWith([tc])];
1172
1161
 
1173
- await reconcileDeniedToolCalls(
1174
- messages,
1162
+ await reconcileDeniedToolCalls(messages, builderOver(messages),
1175
1163
  [{
1176
1164
  toolName: "Shell",
1177
1165
  token: grantToken("shell", "rm -rf build"),
@@ -1190,8 +1178,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
1190
1178
  // proposed content from the captured input, not a bare {path}.
1191
1179
  const messages = [aiMessageWith([])];
1192
1180
 
1193
- const reconciled = await reconcileDeniedToolCalls(
1194
- messages,
1181
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
1195
1182
  [{
1196
1183
  toolName: "Write",
1197
1184
  token: grantToken("write", "ghost.md"),
@@ -1217,8 +1204,7 @@ describe("reconcileDeniedToolCalls — authoritative hook input overlay", () =>
1217
1204
  });
1218
1205
  const messages = [aiMessageWith([tc])];
1219
1206
 
1220
- await reconcileDeniedToolCalls(
1221
- messages,
1207
+ await reconcileDeniedToolCalls(messages, builderOver(messages),
1222
1208
  [{
1223
1209
  toolName: "Write",
1224
1210
  token: grantToken("write", "big.ts"),
@@ -1259,8 +1245,7 @@ describe("reconcileDeniedToolCalls — normalized-path fallback (abs/rel drift)"
1259
1245
  });
1260
1246
  const messages = [aiMessageWith([streamed])];
1261
1247
 
1262
- const reconciled = await reconcileDeniedToolCalls(
1263
- messages,
1248
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
1264
1249
  [{ toolName: "Write", token: grantToken("write", "/root/notes.md") }],
1265
1250
  undefined,
1266
1251
  rootBackend(),
@@ -1288,8 +1273,7 @@ describe("reconcileDeniedToolCalls — normalized-path fallback (abs/rel drift)"
1288
1273
  });
1289
1274
  const messages = [aiMessageWith([streamed])];
1290
1275
 
1291
- await reconcileDeniedToolCalls(
1292
- messages,
1276
+ await reconcileDeniedToolCalls(messages, builderOver(messages),
1293
1277
  [{ toolName: "Write", token: grantToken("write", "/root/src/app.ts") }],
1294
1278
  undefined,
1295
1279
  rootBackend(),
@@ -1304,8 +1288,7 @@ describe("reconcileDeniedToolCalls — normalized-path fallback (abs/rel drift)"
1304
1288
  // The genuine no-stream-event denial (rare) must still surface a gate.
1305
1289
  const messages = [aiMessageWith([])];
1306
1290
 
1307
- const reconciled = await reconcileDeniedToolCalls(
1308
- messages,
1291
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
1309
1292
  [{ toolName: "Write", token: grantToken("write", "/root/ghost.md") }],
1310
1293
  undefined,
1311
1294
  rootBackend(),
@@ -1327,8 +1310,7 @@ describe("reconcileDeniedToolCalls — normalized-path fallback (abs/rel drift)"
1327
1310
  });
1328
1311
  const messages = [aiMessageWith([streamed])];
1329
1312
 
1330
- const reconciled = await reconcileDeniedToolCalls(
1331
- messages,
1313
+ const reconciled = await reconcileDeniedToolCalls(messages, builderOver(messages),
1332
1314
  [{ toolName: "Write", token: grantToken("write", "/root/notes.md") }],
1333
1315
  undefined,
1334
1316
  rootBackend(),
@@ -1566,7 +1548,7 @@ describe("first-denial stop contract", () => {
1566
1548
  expect(messages.some((m) => m.content.includes("try the shell"))).toBe(false);
1567
1549
 
1568
1550
  // Phase 12 reconcile + redact on the stopped transcript yields the clean shape.
1569
- const denied = await reconcileDeniedToolCalls(messages, await readDenialLedger(ws));
1551
+ const denied = await reconcileDeniedToolCalls(messages, builderOver(messages), await readDenialLedger(ws));
1570
1552
  expect(denied).toHaveLength(1);
1571
1553
  expect(edit.status).toBe(ToolCallStatus.TOOL_CALL_WAITING_APPROVAL);
1572
1554
  const redacted = clearProvisionalPostDenialNarration(messages, denied);
@@ -1610,7 +1592,8 @@ describe("first-denial stop contract", () => {
1610
1592
  expect(cancelled).toBe(false);
1611
1593
  expect(consumed).toBe(3); // the whole turn is consumed
1612
1594
  // And the boundary reconcile manufactures no gate from it either.
1613
- const denied = await reconcileDeniedToolCalls([], await readDenialLedger(ws));
1595
+ const messages: AgentMessage[] = [];
1596
+ const denied = await reconcileDeniedToolCalls(messages, builderOver(messages), await readDenialLedger(ws));
1614
1597
  expect(denied).toEqual([]);
1615
1598
  });
1616
1599
 
@@ -1641,7 +1624,7 @@ describe("first-denial stop contract", () => {
1641
1624
 
1642
1625
  // Phase 12 on the stopped transcript: the anchor gates, and the one raced
1643
1626
  // reaction message is blanked by the trim backstop.
1644
- const denied = await reconcileDeniedToolCalls(messages, await readDenialLedger(ws), undefined, rootBackend());
1627
+ const denied = await reconcileDeniedToolCalls(messages, builderOver(messages), await readDenialLedger(ws), undefined, rootBackend());
1645
1628
  expect(denied).toHaveLength(1);
1646
1629
  expect(shell.status).toBe(ToolCallStatus.TOOL_CALL_WAITING_APPROVAL);
1647
1630
  const redacted = clearProvisionalPostDenialNarration(messages, denied);
@@ -1812,7 +1795,7 @@ describe("reconcileDeniedToolCalls — non-approval kinds never gate", () => {
1812
1795
  error: "blocked by a hook", args: { path: ".env" },
1813
1796
  });
1814
1797
  const messages = [aiMessageWith([secretRow])];
1815
- const denied = await reconcileDeniedToolCalls(messages, [
1798
+ const denied = await reconcileDeniedToolCalls(messages, builderOver(messages), [
1816
1799
  { toolName: "Write", token: toolCallIdentityToken(secretRow), kind: "secret" },
1817
1800
  { toolName: "Write", token: grantToken("write", "app.log"), kind: "capture-error" },
1818
1801
  { toolName: "Shell", token: grantToken("shell", "make"), kind: "fail-closed" },
@@ -1834,7 +1817,7 @@ describe("reconcileDeniedToolCalls — non-approval kinds never gate", () => {
1834
1817
  error: "blocked by a hook", args: { path: ".env" },
1835
1818
  });
1836
1819
  const messages = [aiMessageWith([gated, secretRow])];
1837
- const denied = await reconcileDeniedToolCalls(messages, [
1820
+ const denied = await reconcileDeniedToolCalls(messages, builderOver(messages), [
1838
1821
  // Ledger order puts the secret FIRST: the anchor must still be the first
1839
1822
  // APPROVAL entry, never a non-approval kind.
1840
1823
  { toolName: "Write", token: toolCallIdentityToken(secretRow), kind: "secret" },
@@ -19,7 +19,7 @@
19
19
  * watchdog failed the run ("approval propagation is broken").
20
20
  *
21
21
  * The fix (seed the transcript on resume + reconcile re-runs by canonical
22
- * identity in MessageAccumulator) makes the resume status a strict superset:
22
+ * identity in the Cursor translator) makes the resume status a strict superset:
23
23
  * the committed ids survive, the re-runs reconcile in place, and the genuinely
24
24
  * new gated tool is appended. The guard then accepts it.
25
25
  *
@@ -27,13 +27,14 @@
27
27
  * (nonTerminalTranscriptRegression): a from-empty rebuild is REJECTED (the bug),
28
28
  * a seeded rebuild is ACCEPTED (the fix).
29
29
  *
30
- * This exercises the MessageAccumulator + denial-reconciliation directly — the
30
+ * This exercises the translator + builder + denial-reconciliation directly — the
31
31
  * unit that owns the resume emitter — rather than the full Temporal activity,
32
32
  * keeping the reproduction hermetic and pinned to the exact code under change.
33
33
  */
34
34
 
35
35
  import { describe, it, expect } from "vitest";
36
36
  import { create, clone } from "@bufbuild/protobuf";
37
+ import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
37
38
  import {
38
39
  AgentMessageSchema,
39
40
  ToolCallSchema,
@@ -47,12 +48,9 @@ import {
47
48
  ToolCallStatus,
48
49
  } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
49
50
  import type { SDKMessage } from "@cursor/sdk";
50
- import {
51
- MessageAccumulator,
52
- reconcileDeniedToolCalls,
53
- clearProvisionalPostDenialNarration,
54
- buildToolCallProto,
55
- } from "../message-translator.js";
51
+ import { reconcileDeniedToolCalls, clearProvisionalPostDenialNarration } from "../boundary-rows.js";
52
+ import { CursorFold, builderOver } from "../__test-utils__/fold.js";
53
+ import { TranscriptBuilder } from "../../../harness/transcript/builder.js";
56
54
  import {
57
55
  grantToken,
58
56
  buildApprovalGrants,
@@ -213,11 +211,9 @@ describe("Cursor HITL resume — append-only transcript", () => {
213
211
  const committed = persistedRunOneMessages();
214
212
 
215
213
  // Pre-fix behavior: status.messages starts empty on resume, so the
216
- // accumulator can never reconcile onto the committed calls.
214
+ // translator can never reconcile onto the committed calls.
217
215
  const fromEmpty: AgentMessage[] = [];
218
- const acc = new MessageAccumulator(fromEmpty, {});
219
- for (const event of resumeEvents()) acc.processEvent(event);
220
- acc.finalize();
216
+ new CursorFold({ messages: fromEmpty }).events(...resumeEvents()).finalize();
221
217
 
222
218
  // The committed ids are absent — exactly what trips the backend guard.
223
219
  const ids = new Set(allToolCalls(fromEmpty).map((tc) => tc.id));
@@ -233,15 +229,13 @@ describe("Cursor HITL resume — append-only transcript", () => {
233
229
  const committed = persistedRunOneMessages();
234
230
 
235
231
  // Post-fix behavior: index.ts seeds status.messages from the persisted
236
- // execution (cloned) before constructing the accumulator.
232
+ // execution (cloned) before constructing the translator and the builder.
237
233
  const seeded = committed.map((m) => clone(AgentMessageSchema, m));
238
- const acc = new MessageAccumulator(seeded, {});
239
- for (const event of resumeEvents()) acc.processEvent(event);
240
- acc.finalize();
234
+ new CursorFold({ messages: seeded }).events(...resumeEvents()).finalize();
241
235
 
242
236
  // Post-stream denial overlay (the activity's Phase 12): only `click` is in
243
237
  // the ledger, so only it flips to WAITING_APPROVAL.
244
- const denied = await reconcileDeniedToolCalls(seeded, clickDenialLedger());
238
+ const denied = await reconcileDeniedToolCalls(seeded, builderOver(seeded), clickDenialLedger());
245
239
  const redacted = clearProvisionalPostDenialNarration(seeded, denied);
246
240
 
247
241
  const tools = allToolCalls(seeded);
@@ -282,9 +276,11 @@ describe("Cursor HITL resume — append-only transcript", () => {
282
276
 
283
277
  it("FIX: a sub-agent's gated tool also survives resume (the seeded sub-agent rows are wrapped by reference and indexed)", () => {
284
278
  // Sub-agent parity: the runtime seeds `status.subAgentExecutions` on a
285
- // resume (`seedFromPersistedStatus`) and the accumulator wraps that very
286
- // array, exactly as it wraps `status.messages`, so the seeded row is
287
- // retained, indexed by id, and a resumed update lands on it in place.
279
+ // resume (`seedFromPersistedStatus`, through the builder's `seed()`) and
280
+ // the builder holds that very array, exactly as it holds
281
+ // `status.messages`, so the seeded row is retained, indexed by id, and a
282
+ // resumed update lands on it in place. This arm hands the seeded status
283
+ // to the constructor, which indexes by the same routine `seed()` does.
288
284
  const seededSub = create(SubAgentExecutionSchema, {
289
285
  id: "sub_1",
290
286
  name: "researcher",
@@ -292,11 +288,12 @@ describe("Cursor HITL resume — append-only transcript", () => {
292
288
  });
293
289
  const statusRows = [seededSub];
294
290
 
295
- const acc = new MessageAccumulator([], { subAgentExecutions: statusRows });
296
- acc.finalize();
291
+ const status = create(AgentExecutionStatusSchema, {});
292
+ status.subAgentExecutions = statusRows;
293
+ new TranscriptBuilder("exec-resume", status).finalize();
297
294
 
298
- expect(acc.subAgentExecutions, "the status's own array, not a copy").toBe(statusRows);
299
- expect(acc.subAgentExecutions.some((s) => s.id === "sub_1")).toBe(true);
295
+ expect(status.subAgentExecutions, "the status's own array, not a copy").toBe(statusRows);
296
+ expect(status.subAgentExecutions.some((s) => s.id === "sub_1")).toBe(true);
300
297
  });
301
298
 
302
299
  it("FIX: the approved tools are ALLOWED by the hook on resume — not re-denied (the loop's source)", () => {
@@ -404,12 +401,10 @@ describe("Cursor HITL resume — two approvals then clean completion (no loop)",
404
401
  const committed = committedBuiltInApprovals();
405
402
  const seeded = committed.map((m) => clone(AgentMessageSchema, m));
406
403
 
407
- const acc = new MessageAccumulator(seeded, {});
408
- for (const event of builtInResumeEvents()) acc.processEvent(event);
409
- acc.finalize();
404
+ new CursorFold({ messages: seeded }).events(...builtInResumeEvents()).finalize();
410
405
 
411
406
  // The hook allowed both (no denials this turn), so the overlay adds nothing.
412
- const denied = await reconcileDeniedToolCalls(seeded, []);
407
+ const denied = await reconcileDeniedToolCalls(seeded, builderOver(seeded), []);
413
408
  expect(denied).toHaveLength(0);
414
409
 
415
410
  const tools = allToolCalls(seeded);
@@ -1,5 +1,6 @@
1
1
  /**
2
- * @regression file-hitl-phase0 — pins file-edit HITL fix #2 (see _projects/2026-06/20260630.01.file-change-hitl-redesign/tasks/T01_3_regression-manifest.md)
2
+ * @regression file-hitl-phase0 — pins that decisions bind to the active turn's
3
+ * denial ledger, never a stale one, and that a resume respects its order.
3
4
  *
4
5
  * Behavior tests for the generated preToolUse bash hook.
5
6
  *
@@ -312,7 +312,7 @@ describe("http2-interceptor", () => {
312
312
  });
313
313
  });
314
314
 
315
- describe("the token ref is read per request (the root rotates it in place; Q-S2-7)", () => {
315
+ describe("the token ref is read per request (the root rotates it in place)", () => {
316
316
  let mock: ReturnType<typeof createMockConnect>;
317
317
  let proxyTokenRef: { current: string | null };
318
318
 
@@ -2,12 +2,12 @@
2
2
  * The Cursor prompt, whole, as goldens — one per shape `buildPrompt` selects.
3
3
  *
4
4
  * `build-prompt.test.ts` pins every branch with `toContain`; the hermetic
5
- * goldens are status JSON and never see a prompt. So until S3 M5 no test
5
+ * goldens are status JSON and never see a prompt. So until #1096 no test
6
6
  * pinned a rendered Cursor prompt byte for byte. These goldens are the
7
7
  * photograph taken BEFORE the shared prompt glue moved into
8
- * `shared/prompt-sections.ts` (S3 M5, Q-M5-1), so the move could be proven
8
+ * `shared/prompt-sections.ts` (#1096), so the move could be proven
9
9
  * byte-identical except where a ruling says otherwise — the same discipline
10
- * M0 applied to the activity's status.
10
+ * the hermetic net applied to the activity's status (#1048).
11
11
  *
12
12
  * The shapes (`buildPrompt`'s four, plus the two per-execution directives):
13
13
  * the enhanced prompt on a first execution with every section populated
@@ -22,7 +22,7 @@
22
22
  * and the HITL recovery on a fresh agent mid-HITL.
23
23
  *
24
24
  * Rulings that moved a golden are quoted here:
25
- * - Q-M5-3 (2026-09-14, owner: A). Every `<input_files>` bullet gained the
25
+ * - 2026-09-14 (#1096). Every `<input_files>` bullet gained the
26
26
  * file's size — `- \`.stigmer/inputs/spec.pdf\`` became
27
27
  * `- \`.stigmer/inputs/spec.pdf\` (204800 bytes)` — in the four goldens
28
28
  * that carry attachments (`enhanced.everything`, `enhanced.plan-mode`,
@@ -176,7 +176,7 @@ function everything(reason: AgentResolutionReason, overrides: Partial<BuildPromp
176
176
  // Goldens
177
177
  // ---------------------------------------------------------------------------
178
178
 
179
- describe("Cursor prompt goldens (S3 M5, Q-M5-1)", () => {
179
+ describe("Cursor prompt goldens", () => {
180
180
  it("the enhanced prompt on a first execution, every section populated", async () => {
181
181
  const prompt = buildPrompt(everything("created_first_execution"));
182
182
  await expect(prompt).toMatchFileSnapshot("./goldens/prompt.enhanced.everything.prompt.md");
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * A later, same-identity proposal is a NEW act: it never lands on a row the
3
- * user already decided (S2 M4 finding F9).
3
+ * user already decided (found by the contract kit in #1070).
4
4
  *
5
5
  * The defect the harness contract kit found against this adapter: within one
6
6
  * execution, after the user APPROVED `edit a.txt` and the resumed agent ran
@@ -11,11 +11,11 @@
11
11
  * one — flipped it back to WAITING_APPROVAL with its APPROVE still on it and
12
12
  * wiped its result; the actual streamed call was hidden as a twin. On the next
13
13
  * invocation `approvalDecisionsOf` read that row as a decision and the new,
14
- * never-approved proposal ran under the old approval. The accumulator had the
14
+ * never-approved proposal ran under the old approval. The stream fold had the
15
15
  * sibling flaw: a re-issue after a SKIP or REJECT was reconciled onto the
16
16
  * declined row by identity, inheriting its decision.
17
17
  *
18
- * The rule, in `message-translator.ts`: a row the server has adjudicated
18
+ * The rule, in `boundary-rows.ts` and the translator's seeded-row match: a row the server has adjudicated
19
19
  * (`isAdjudicatedRow`) is never the home of THIS turn's denial and never a
20
20
  * twin to collapse; a row the user DECLINED (`isDeclinedRow`) is never the
21
21
  * home of a later same-identity call. The approved re-issue (the
@@ -36,7 +36,9 @@ import { ApprovalAction, MessageType, ToolCallStatus } from "@stigmer/protos/ai/
36
36
  import type { SDKMessage } from "@cursor/sdk";
37
37
 
38
38
  import { approvalDecisionsOf } from "../../../harness/approval-decisions.js";
39
- import { MessageAccumulator, reconcileDeniedToolCalls, toolCallIdentityToken } from "../message-translator.js";
39
+ import { reconcileDeniedToolCalls } from "../boundary-rows.js";
40
+ import { CursorFold, builderOver } from "../__test-utils__/fold.js";
41
+ import { toolCallIdentityToken } from "../approval-state.js";
40
42
  import type { DeniedLedgerEntry } from "../approval-state.js";
41
43
 
42
44
  const PATH = "/work/a.txt";
@@ -83,12 +85,9 @@ function allToolCalls(messages: AgentMessage[]): ToolCall[] {
83
85
 
84
86
  /** The later turn: the model proposes the same edit under a fresh id, the hook denies it, the turn boundary reconciles. */
85
87
  async function laterTurnProposesSameEdit(seeded: AgentMessage[]): Promise<ToolCall[]> {
86
- const acc = new MessageAccumulator(seeded, {});
87
- acc.processEvent(toolCallEvent(LATER_ID, "running"));
88
- acc.processEvent(toolCallEvent(LATER_ID, "error", "Blocked by hook"));
89
- acc.finalize();
88
+ new CursorFold({ messages: seeded }).events(toolCallEvent(LATER_ID, "running"), toolCallEvent(LATER_ID, "error", "Blocked by hook")).finalize();
90
89
  const ledger: DeniedLedgerEntry[] = [{ toolName: "Write", token: toolCallIdentityToken(allToolCalls(seeded).find((tc) => tc.id === LATER_ID)!) }];
91
- return reconcileDeniedToolCalls(seeded, ledger);
90
+ return reconcileDeniedToolCalls(seeded, builderOver(seeded), ledger);
92
91
  }
93
92
 
94
93
  function decisionsTheRuntimeWouldRead(messages: AgentMessage[]): ReadonlyMap<string, ApprovalAction> {
@@ -158,10 +157,9 @@ describe("a later same-identity proposal never lands on a decided row (F9)", ()
158
157
  }),
159
158
  ];
160
159
 
161
- const acc = new MessageAccumulator(seeded, {});
162
- acc.processEvent(toolCallEvent(`${FIRST_ID}_RESUME`, "running"));
163
- acc.processEvent(toolCallEvent(`${FIRST_ID}_RESUME`, "completed", RESULT_OF_FIRST));
164
- acc.finalize();
160
+ new CursorFold({ messages: seeded })
161
+ .events(toolCallEvent(`${FIRST_ID}_RESUME`, "running"), toolCallEvent(`${FIRST_ID}_RESUME`, "completed", RESULT_OF_FIRST))
162
+ .finalize();
165
163
 
166
164
  const tools = allToolCalls(seeded);
167
165
  expect(tools.map((tc) => tc.id), "one row, the committed id").toEqual([FIRST_ID]);
@@ -1,5 +1,6 @@
1
1
  /**
2
- * @regression file-hitl-phase0 — pins file-edit HITL fix #2 (see _projects/2026-06/20260630.01.file-change-hitl-redesign/tasks/T01_3_regression-manifest.md)
2
+ * @regression file-hitl-phase0 — pins that decisions bind to the active turn's
3
+ * denial ledger, never a stale one, and that a resume respects its order.
3
4
  *
4
5
  * Cursor analog of execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts:
5
6
  * two SEQUENTIAL approval gates across a resume, on the Cursor deny-and-reconcile
@@ -21,7 +22,7 @@
21
22
  * for the first time — and the REAL bash hook must ALLOW A's re-issue while
22
23
  * DENYING B, the out-of-process half the native gate has no equivalent for.
23
24
  *
24
- * Exercises the MessageAccumulator + denial reconciliation (the unit that owns
25
+ * Exercises the translator + builder + denial reconciliation (the units that own
25
26
  * the Cursor resume emitter) plus the generated hook, keeping the reproduction
26
27
  * hermetic and pinned to the exact code under change.
27
28
  */
@@ -40,11 +41,9 @@ import {
40
41
  } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
41
42
  import type { SDKMessage } from "@cursor/sdk";
42
43
 
43
- import {
44
- MessageAccumulator,
45
- reconcileDeniedToolCalls,
46
- toolCallIdentityToken,
47
- } from "../message-translator.js";
44
+ import { reconcileDeniedToolCalls } from "../boundary-rows.js";
45
+ import { CursorFold, builderOver } from "../__test-utils__/fold.js";
46
+ import { toolCallIdentityToken } from "../approval-state.js";
48
47
  import {
49
48
  buildApprovalGrants,
50
49
  buildApprovalState,
@@ -139,16 +138,14 @@ describe("Cursor sequential gates A->B across resume", () => {
139
138
  const committed = approvedGateA();
140
139
  const seeded = committed.map((m) => clone(AgentMessageSchema, m));
141
140
 
142
- const acc = new MessageAccumulator(seeded, {});
143
- for (const event of resumeIntoGateB()) acc.processEvent(event);
144
- acc.finalize();
141
+ new CursorFold({ messages: seeded }).events(...resumeIntoGateB()).finalize();
145
142
 
146
143
  // Gate B was denied this turn; its identity comes off the reconciled call.
147
144
  const bCall = allToolCalls(seeded).find((tc) => tc.name === "shell")!;
148
145
  const ledger: DeniedLedgerEntry[] = [
149
146
  { toolName: "shell", token: toolCallIdentityToken(bCall) },
150
147
  ];
151
- await reconcileDeniedToolCalls(seeded, ledger);
148
+ await reconcileDeniedToolCalls(seeded, builderOver(seeded), ledger);
152
149
 
153
150
  const tools = allToolCalls(seeded);
154
151
  const byId = new Map(tools.map((tc) => [tc.id, tc]));