@sema-agent/core 7.51.2 → 7.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/CHANGELOG.md +504 -2
  2. package/dist/agents/agent-transcript-tool.d.ts +1 -1
  3. package/dist/agents/cascade.js +4 -0
  4. package/dist/agents/cumulative-stats.d.ts +3 -0
  5. package/dist/agents/cumulative-stats.js +3 -0
  6. package/dist/agents/list-agents-tool.d.ts +1 -1
  7. package/dist/agents/read-inbox-tool.d.ts +1 -1
  8. package/dist/agents/repair-loop.js +4 -0
  9. package/dist/agents/send-message-tool.d.ts +11 -16
  10. package/dist/agents/send-message-tool.js +11 -13
  11. package/dist/agents/subagent.js +6 -4
  12. package/dist/agents/tool-filter.d.ts +40 -13
  13. package/dist/agents/tool-filter.js +28 -14
  14. package/dist/bench/metrics.d.ts +1 -0
  15. package/dist/brain/anthropic.js +16 -12
  16. package/dist/brain/model-presets.d.ts +4 -5
  17. package/dist/brain/model-presets.js +4 -4
  18. package/dist/brain/open-responses.js +16 -12
  19. package/dist/brain/openai.js +16 -12
  20. package/dist/brain/request-params.d.ts +12 -33
  21. package/dist/brain/request-params.js +5 -2
  22. package/dist/brain/request-route.d.ts +9 -8
  23. package/dist/brain/request-route.js +1 -0
  24. package/dist/brain/route-adjudicator.d.ts +117 -47
  25. package/dist/brain/route-adjudicator.js +171 -42
  26. package/dist/brain/route-conformance.js +2 -2
  27. package/dist/brain/status-sink.d.ts +18 -0
  28. package/dist/brain/status-sink.js +7 -0
  29. package/dist/core/allow-entry.d.ts +40 -8
  30. package/dist/core/allow-entry.js +23 -16
  31. package/dist/core/auto-compaction.d.ts +23 -20
  32. package/dist/core/auto-compaction.js +37 -16
  33. package/dist/core/auto-promote.d.ts +2 -1
  34. package/dist/core/auto-promote.js +2 -2
  35. package/dist/core/caller-tool-name.d.ts +9 -0
  36. package/dist/core/caller-tool-name.js +13 -0
  37. package/dist/core/checkpoint-requirements.d.ts +7 -1
  38. package/dist/core/checkpoint-requirements.js +2 -0
  39. package/dist/core/checkpoint-store.d.ts +36 -12
  40. package/dist/core/checkpoint-store.js +1 -1
  41. package/dist/core/child-clamp-seats.d.ts +6 -0
  42. package/dist/core/child-clamp-seats.js +2 -1
  43. package/dist/core/credential-vocabulary.d.ts +33 -8
  44. package/dist/core/credential-vocabulary.js +32 -7
  45. package/dist/core/decision-receipt.d.ts +2 -2
  46. package/dist/core/delegation-frames.d.ts +9 -2
  47. package/dist/core/delegation-name.d.ts +18 -0
  48. package/dist/core/delegation-name.js +47 -0
  49. package/dist/core/engine-capabilities.d.ts +8 -1
  50. package/dist/core/engine-capabilities.js +1 -1
  51. package/dist/core/engine-notice.d.ts +36 -19
  52. package/dist/core/frontmatter-fence.d.ts +10 -0
  53. package/dist/core/frontmatter-fence.js +6 -0
  54. package/dist/core/gate-fold.js +5 -23
  55. package/dist/core/gate-lanes.js +356 -270
  56. package/dist/core/governance-codes.d.ts +9 -4
  57. package/dist/core/governance-codes.js +9 -3
  58. package/dist/core/hooks.d.ts +276 -734
  59. package/dist/core/hooks.js +97 -192
  60. package/dist/{tools/fs → core}/image-admission.d.ts +21 -3
  61. package/dist/{tools/fs → core}/image-admission.js +24 -6
  62. package/dist/core/mcp-connection-pool.d.ts +4 -1
  63. package/dist/core/mcp-connection-pool.js +7 -2
  64. package/dist/core/mcp-probe.d.ts +12 -9
  65. package/dist/core/mcp-probe.js +2 -2
  66. package/dist/core/mcp-server-spec.d.ts +16 -0
  67. package/dist/core/mcp.d.ts +11 -7
  68. package/dist/core/mcp.js +11 -5
  69. package/dist/core/memory-engine/data-plane.js +5 -1
  70. package/dist/core/memory-engine/distiller.js +16 -2
  71. package/dist/core/memory-engine/engine.d.ts +8 -11
  72. package/dist/core/memory-engine/engine.js +9 -5
  73. package/dist/core/memory-engine/frontmatter.d.ts +6 -0
  74. package/dist/core/memory-engine/frontmatter.js +19 -16
  75. package/dist/core/memory.d.ts +2 -2
  76. package/dist/core/mode-policy.d.ts +4 -0
  77. package/dist/core/mode-policy.js +7 -5
  78. package/dist/core/model-seat.d.ts +4 -1
  79. package/dist/core/mods/dollar.d.ts +109 -0
  80. package/dist/core/mods/dollar.js +154 -0
  81. package/dist/core/mods/host.d.ts +23 -0
  82. package/dist/core/mods/host.js +21 -0
  83. package/dist/core/mods/kernel/budget.d.ts +43 -0
  84. package/dist/core/mods/kernel/budget.js +83 -0
  85. package/dist/core/mods/kernel/dispatch.d.ts +100 -0
  86. package/dist/core/mods/kernel/dispatch.js +701 -0
  87. package/dist/core/mods/kernel/events.d.ts +242 -0
  88. package/dist/core/mods/kernel/events.js +210 -0
  89. package/dist/core/mods/kernel/index.d.ts +6 -0
  90. package/dist/core/mods/kernel/index.js +5 -0
  91. package/dist/core/mods/kernel/receive.d.ts +65 -0
  92. package/dist/core/mods/kernel/receive.js +123 -0
  93. package/dist/core/mods/kernel/registration.d.ts +131 -0
  94. package/dist/core/mods/kernel/registration.js +102 -0
  95. package/dist/core/mods/kernel/site-rules.d.ts +84 -0
  96. package/dist/core/mods/kernel/site-rules.js +104 -0
  97. package/dist/core/mods/stations.d.ts +350 -0
  98. package/dist/core/mods/stations.js +444 -0
  99. package/dist/core/own-property-receipt.js +11 -23
  100. package/dist/core/parent-spec-seat.d.ts +18 -7
  101. package/dist/core/parent-spec-seat.js +6 -2
  102. package/dist/core/path-identity.js +2 -1
  103. package/dist/core/permission-rule-syntax.d.ts +15 -0
  104. package/dist/core/permission-rule-syntax.js +24 -16
  105. package/dist/core/permission-rules.d.ts +7 -1
  106. package/dist/core/permission-rules.js +26 -15
  107. package/dist/core/prompt-section-seat.d.ts +15 -27
  108. package/dist/core/prompt-section-seat.js +73 -40
  109. package/dist/core/protocol-http-auth.d.ts +3 -1
  110. package/dist/core/protocol-http-auth.js +2 -0
  111. package/dist/core/reminder-mint.d.ts +2 -2
  112. package/dist/core/remote-env.d.ts +24 -12
  113. package/dist/core/remote-env.js +1 -0
  114. package/dist/core/resume-startup-cause.d.ts +16 -1
  115. package/dist/core/resume-startup-cause.js +4 -1
  116. package/dist/core/retired-keys.d.ts +4 -0
  117. package/dist/core/retired-keys.js +3 -0
  118. package/dist/core/runner/announce-once-ledger.d.ts +31 -1
  119. package/dist/core/runner/announce-once-ledger.js +22 -0
  120. package/dist/core/runner/assemble-result.d.ts +9 -0
  121. package/dist/core/runner/assemble-result.js +3 -1
  122. package/dist/core/runner/call-hook-stations.d.ts +23 -27
  123. package/dist/core/runner/call-hook-stations.js +58 -42
  124. package/dist/core/runner/caller-stop-gate.d.ts +25 -0
  125. package/dist/core/runner/caller-stop-gate.js +7 -0
  126. package/dist/core/runner/compaction-seams.d.ts +8 -22
  127. package/dist/core/runner/compaction-seams.js +28 -53
  128. package/dist/core/runner/construction-doors.js +11 -1
  129. package/dist/core/runner/contracts.d.ts +85 -83
  130. package/dist/core/runner/credential-origin-seat.d.ts +2 -0
  131. package/dist/core/runner/credential-origin-seat.js +19 -0
  132. package/dist/core/runner/extra-body-dropped-seat.d.ts +2 -6
  133. package/dist/core/runner/gate-exit.d.ts +47 -36
  134. package/dist/core/runner/gate-exit.js +8 -2
  135. package/dist/core/runner/image.js +1 -2
  136. package/dist/core/runner/inline-image.js +1 -1
  137. package/dist/core/runner/notice-seat-input.d.ts +11 -0
  138. package/dist/core/runner/notice-seat-input.js +1 -0
  139. package/dist/core/runner/person-path-rows.js +1 -0
  140. package/dist/core/runner/prepare-acquire-reconcile.js +5 -1
  141. package/dist/core/runner/prepare-ask-lane.d.ts +5 -7
  142. package/dist/core/runner/prepare-ask-lane.js +6 -15
  143. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
  144. package/dist/core/runner/prepare-caps-and-workflow.js +25 -8
  145. package/dist/core/runner/prepare-config-doors.d.ts +5 -0
  146. package/dist/core/runner/prepare-config-doors.js +9 -0
  147. package/dist/core/runner/prepare-defer-classify.js +3 -4
  148. package/dist/core/runner/prepare-gate-stations.d.ts +8 -11
  149. package/dist/core/runner/prepare-gate-stations.js +11 -10
  150. package/dist/core/runner/prepare-inherited-gate.d.ts +8 -12
  151. package/dist/core/runner/prepare-inherited-gate.js +8 -21
  152. package/dist/core/runner/prepare-memory-engine-session.js +1 -1
  153. package/dist/core/runner/prepare-park-ask.js +10 -14
  154. package/dist/core/runner/prepare-policy-chain.d.ts +17 -15
  155. package/dist/core/runner/prepare-policy-chain.js +95 -100
  156. package/dist/core/runner/prepare-project-context.js +7 -10
  157. package/dist/core/runner/prepare-prompt-assembly.d.ts +45 -40
  158. package/dist/core/runner/prepare-prompt-assembly.js +134 -101
  159. package/dist/core/runner/prepare-prompt-inputs.d.ts +18 -19
  160. package/dist/core/runner/prepare-prompt-inputs.js +5 -7
  161. package/dist/core/runner/prepare-protocol-tools.d.ts +6 -4
  162. package/dist/core/runner/prepare-protocol-tools.js +2 -2
  163. package/dist/core/runner/prepare-safety-scan.js +6 -10
  164. package/dist/core/runner/prepare-suspend-saga.d.ts +6 -0
  165. package/dist/core/runner/prepare-suspend-saga.js +7 -5
  166. package/dist/core/runner/prepare-task.js +33 -15
  167. package/dist/core/runner/prepare-turn-wiring.d.ts +13 -15
  168. package/dist/core/runner/prepare-turn-wiring.js +29 -27
  169. package/dist/core/runner/prepare-wiring-manifest.d.ts +5 -6
  170. package/dist/core/runner/prepare-wiring-manifest.js +7 -7
  171. package/dist/core/runner/resume-apply.d.ts +5 -2
  172. package/dist/core/runner/resume-apply.js +24 -42
  173. package/dist/core/runner/resume-checkpoint-screen.d.ts +1 -0
  174. package/dist/core/runner/resume-checkpoint-screen.js +9 -1
  175. package/dist/core/runner/resume-preflight.js +38 -16
  176. package/dist/core/runner/retired-runner-deps.js +3 -1
  177. package/dist/core/runner/run-brain-sinks.d.ts +3 -2
  178. package/dist/core/runner/run-brain-sinks.js +5 -1
  179. package/dist/core/runner/run-compaction-machinery.d.ts +7 -1
  180. package/dist/core/runner/run-compaction-machinery.js +7 -33
  181. package/dist/core/runner/run-harness-handlers.js +4 -2
  182. package/dist/core/runner/run-identity-wiring.d.ts +3 -1
  183. package/dist/core/runner/run-identity-wiring.js +3 -2
  184. package/dist/core/runner/run-leg.js +62 -84
  185. package/dist/core/runner/run-notification-lane.js +1 -0
  186. package/dist/core/runner/run-recovery-lanes.d.ts +3 -0
  187. package/dist/core/runner/run-recovery-lanes.js +11 -10
  188. package/dist/core/runner/run-settle-and-teardown.js +9 -28
  189. package/dist/core/runner/run-stop-and-final-verify.js +18 -25
  190. package/dist/core/runner/run-terminal-adoption.d.ts +3 -0
  191. package/dist/core/runner/run-terminal-adoption.js +33 -22
  192. package/dist/core/runner/run-tool-mount-facts.js +5 -3
  193. package/dist/core/runner/run-turn-boundary.js +23 -34
  194. package/dist/core/runner/runtask.d.ts +6 -7
  195. package/dist/core/runner/runtask.js +14 -72
  196. package/dist/core/runner/session-rule-policy.d.ts +5 -5
  197. package/dist/core/runner/session-rule-policy.js +13 -8
  198. package/dist/core/runner/side-call-account.d.ts +68 -0
  199. package/dist/core/runner/side-call-account.js +61 -0
  200. package/dist/core/runner/stream-halt-verbs.js +12 -17
  201. package/dist/core/runner/stream-lifecycle-verbs.js +8 -5
  202. package/dist/core/runner/stream-steer-verb.d.ts +1 -1
  203. package/dist/core/runner/stream-steer-verb.js +20 -38
  204. package/dist/core/runner/sub-agent-deny-lists.d.ts +121 -22
  205. package/dist/core/runner/sub-agent-deny-lists.js +228 -71
  206. package/dist/core/runner/tool-end-body.d.ts +5 -6
  207. package/dist/core/runner/tool-end-body.js +6 -4
  208. package/dist/core/runner/tool-not-executed.d.ts +15 -0
  209. package/dist/core/runner/tool-not-executed.js +30 -0
  210. package/dist/core/runner/tool-occurrence.d.ts +8 -7
  211. package/dist/core/runner/tool-occurrence.js +5 -5
  212. package/dist/core/runner/tool-result-media-seat.d.ts +1 -1
  213. package/dist/core/runner-deps.d.ts +20 -28
  214. package/dist/core/safety-merge-corpus.js +18 -2
  215. package/dist/core/secret-env.d.ts +88 -20
  216. package/dist/core/secret-env.js +192 -38
  217. package/dist/core/session-policy-store.d.ts +52 -16
  218. package/dist/core/session-policy-store.js +118 -28
  219. package/dist/core/session-reconcile.d.ts +4 -0
  220. package/dist/core/session-reconcile.js +2 -1
  221. package/dist/core/shell-read-silence.js +3 -32
  222. package/dist/core/side-query.d.ts +5 -3
  223. package/dist/core/skill-grant.d.ts +3 -2
  224. package/dist/core/skill-grant.js +17 -9
  225. package/dist/core/skills-directory.d.ts +31 -11
  226. package/dist/core/skills-directory.js +655 -104
  227. package/dist/core/task-event.d.ts +13 -3
  228. package/dist/core/task-result.d.ts +8 -0
  229. package/dist/core/task-spec.d.ts +20 -19
  230. package/dist/core/task-stream.d.ts +14 -4
  231. package/dist/core/tighten-task-spec.d.ts +4 -3
  232. package/dist/core/tighten-task-spec.js +2 -4
  233. package/dist/core/tool-check-reading.d.ts +74 -0
  234. package/dist/core/tool-check-reading.js +80 -0
  235. package/dist/core/tool-policy.d.ts +59 -18
  236. package/dist/core/tool-policy.js +77 -12
  237. package/dist/core/tool-registry.d.ts +20 -0
  238. package/dist/core/tool-registry.js +4 -0
  239. package/dist/core/tool-spec.d.ts +10 -6
  240. package/dist/core/tools.js +2 -0
  241. package/dist/core/trace.d.ts +51 -32
  242. package/dist/core/unc-spelling.d.ts +10 -0
  243. package/dist/core/unc-spelling.js +3 -0
  244. package/dist/core/untrusted-egress.d.ts +8 -0
  245. package/dist/core/untrusted-egress.js +4 -1
  246. package/dist/core/user-attachment.d.ts +12 -2
  247. package/dist/core/user-attachment.js +17 -2
  248. package/dist/core/wiring-manifest.d.ts +14 -13
  249. package/dist/core/wiring-manifest.js +2 -2
  250. package/dist/engine/compaction/utils.js +1 -2
  251. package/dist/engine/execution-env/node-execution-env.d.ts +4 -3
  252. package/dist/engine/execution-env/symlink-chain.js +1 -1
  253. package/dist/engine/harness/agent-harness.d.ts +1 -1
  254. package/dist/engine/harness/agent-harness.js +3 -3
  255. package/dist/engine/harness/types.d.ts +17 -16
  256. package/dist/engine/harness/types.js +7 -1
  257. package/dist/engine/llm/types.d.ts +12 -7
  258. package/dist/engine/loop/agent-loop.js +1 -1
  259. package/dist/engine/loop/types.d.ts +1 -1
  260. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  261. package/dist/engine/session/import-validate.js +3 -10
  262. package/dist/engine/session/session.d.ts +4 -4
  263. package/dist/engine/session/session.js +4 -4
  264. package/dist/index.d.ts +20 -16
  265. package/dist/index.js +13 -11
  266. package/dist/internal/harness.d.ts +1 -1
  267. package/dist/internal/harness.js +1 -1
  268. package/dist/orchestration/run-spec.d.ts +4 -6
  269. package/dist/orchestration/run-spec.js +39 -63
  270. package/dist/orchestration/run-workflow-tool.js +1 -2
  271. package/dist/orchestration/workflow.d.ts +11 -3
  272. package/dist/orchestration/workflow.js +11 -2
  273. package/dist/prompt-assembly/artifact-store.d.ts +37 -56
  274. package/dist/prompt-assembly/artifact-store.js +31 -49
  275. package/dist/prompt-assembly/artifact.d.ts +89 -76
  276. package/dist/prompt-assembly/artifact.js +167 -146
  277. package/dist/prompt-assembly/assemble.d.ts +34 -29
  278. package/dist/prompt-assembly/assemble.js +33 -220
  279. package/dist/prompt-assembly/bands.d.ts +20 -0
  280. package/dist/prompt-assembly/bands.js +18 -0
  281. package/dist/prompt-assembly/catalog/constitution.d.ts +23 -0
  282. package/dist/prompt-assembly/catalog/constitution.js +69 -0
  283. package/dist/prompt-assembly/catalog/core-behavior.d.ts +9 -0
  284. package/dist/prompt-assembly/catalog/core-behavior.js +85 -0
  285. package/dist/prompt-assembly/catalog/index.d.ts +11 -0
  286. package/dist/prompt-assembly/catalog/index.js +59 -0
  287. package/dist/prompt-assembly/catalog/modes.d.ts +15 -0
  288. package/dist/prompt-assembly/catalog/modes.js +137 -0
  289. package/dist/prompt-assembly/catalog/role.d.ts +10 -0
  290. package/dist/prompt-assembly/catalog/role.js +157 -0
  291. package/dist/prompt-assembly/catalog/schema.d.ts +124 -0
  292. package/dist/prompt-assembly/catalog/schema.js +25 -0
  293. package/dist/prompt-assembly/catalog/sections.d.ts +9 -0
  294. package/dist/prompt-assembly/catalog/sections.js +98 -0
  295. package/dist/prompt-assembly/catalog/team.d.ts +4 -0
  296. package/dist/prompt-assembly/catalog/team.js +258 -0
  297. package/dist/prompt-assembly/composer.d.ts +24 -28
  298. package/dist/prompt-assembly/composer.js +124 -46
  299. package/dist/prompt-assembly/epoch.d.ts +89 -79
  300. package/dist/prompt-assembly/epoch.js +115 -142
  301. package/dist/prompt-assembly/explain.d.ts +58 -34
  302. package/dist/prompt-assembly/explain.js +21 -24
  303. package/dist/prompt-assembly/overlay.d.ts +127 -0
  304. package/dist/prompt-assembly/overlay.js +301 -0
  305. package/dist/prompt-assembly/renderers.d.ts +21 -0
  306. package/dist/prompt-assembly/renderers.js +39 -0
  307. package/dist/prompt-assembly/section-usage.d.ts +3 -3
  308. package/dist/prompt-assembly/section-usage.js +1 -1
  309. package/dist/prompt-assembly/select.d.ts +56 -0
  310. package/dist/prompt-assembly/select.js +69 -0
  311. package/dist/prompt-assembly/sugar.d.ts +31 -0
  312. package/dist/prompt-assembly/sugar.js +20 -0
  313. package/dist/prompt-assembly/turn-snapshot.d.ts +3 -2
  314. package/dist/prompt-assembly/types.d.ts +45 -148
  315. package/dist/prompts/coordinator.d.ts +2 -21
  316. package/dist/prompts/coordinator.js +3 -255
  317. package/dist/prompts/cowork.d.ts +27 -16
  318. package/dist/prompts/cowork.js +2 -23
  319. package/dist/prompts/default.d.ts +38 -500
  320. package/dist/prompts/default.js +20 -285
  321. package/dist/prompts/supervisor.d.ts +6 -71
  322. package/dist/prompts/supervisor.js +6 -117
  323. package/dist/tools/fs/bash-readonly-classifier.d.ts +6 -5
  324. package/dist/tools/fs/dir-entries.d.ts +4 -2
  325. package/dist/tools/fs/dir-entries.js +16 -4
  326. package/dist/tools/fs/fs-bash.d.ts +1 -1
  327. package/dist/tools/fs/fs-bash.js +22 -11
  328. package/dist/tools/fs/fs-pdf.js +17 -13
  329. package/dist/tools/fs/fs-read.js +4 -3
  330. package/dist/tools/fs/fs-shared.d.ts +1 -10
  331. package/dist/tools/fs/fs-shared.js +3 -4
  332. package/dist/tools/fs/fs-write.js +2 -1
  333. package/dist/tools/fs/notebook.js +1 -1
  334. package/dist/tools/fs/pdf.d.ts +20 -10
  335. package/dist/tools/fs/pdf.js +19 -10
  336. package/dist/tools/fs/program-read-model.d.ts +68 -8
  337. package/dist/tools/fs/program-read-model.js +112 -33
  338. package/dist/tools/fs/program-read-model.rows.js +30 -10
  339. package/dist/tools/fs/read-deny-home.d.ts +25 -9
  340. package/dist/tools/fs/read-deny-home.js +28 -27
  341. package/dist/tools/fs/read-deny.d.ts +41 -11
  342. package/dist/tools/fs/read-deny.js +51 -5
  343. package/dist/tools/fs/safety.d.ts +4 -26
  344. package/dist/tools/fs/safety.js +10 -32
  345. package/dist/tools/fs/search.js +15 -10
  346. package/dist/tools/fs/shell-read-argv.d.ts +3 -2
  347. package/dist/tools/fs/shell-read-argv.js +118 -38
  348. package/dist/tools/fs/shell-read-establish.d.ts +5 -5
  349. package/dist/tools/fs/shell-read-establish.js +11 -61
  350. package/dist/tools/fs/shell-read-identity.js +6 -3
  351. package/dist/tools/fs/shell-read-judge.d.ts +13 -15
  352. package/dist/tools/fs/shell-read-judge.js +18 -4
  353. package/dist/tools/fs/shell-read-plan.d.ts +2 -2
  354. package/dist/tools/web.js +1 -1
  355. package/package.json +13 -1
  356. package/test/export-surface.snapshot.json +242 -99
  357. package/wire-changes/core@7.52.0.json +5859 -0
  358. package/dist/core/hook-seats.d.ts +0 -66
  359. package/dist/core/hook-seats.js +0 -37
  360. package/dist/prompt-assembly/packs/sema-default.d.ts +0 -2
  361. package/dist/prompt-assembly/packs/sema-default.js +0 -147
  362. package/dist/prompts/simple-sections.d.ts +0 -58
  363. package/dist/prompts/simple-sections.js +0 -43
@@ -1,6 +1,6 @@
1
1
  import { withArgsReading } from "./effective-path-target.js";
2
- import { attest, attestationOf, decisionText, refuseOutOfContractDecision } from "./tool-policy.js";
3
- import { arbitrateByMode, classifyAsk, fileCommandOptionsSentence, persistedRuleMandateOf, ruleClearanceOf, safetyAxisOf, stampAskOrigin } from "./ask-origin.js";
2
+ import { attest, attestationOf, decisionText, foldHookAsk, ownArgs, refusalOf, refuseOutOfContractDecision } from "./tool-policy.js";
3
+ import { arbitrateByMode, classifyAsk, decisionAskClassesOf, fileCommandOptionsSentence, persistedRuleMandateOf, ruleClearanceOf, safetyAxisOf, stampAskOrigin } from "./ask-origin.js";
4
4
  import { classifierParseFailureDenyMessage, denialLimitFallbackMessage, rungDidNotRule, unarmedWindow } from "./auto-mode.js";
5
5
  import { classifierNoRulingArm, settleNoRulingAsk } from "./classifier-unavailable-arm.js";
6
6
  import { SETTLEMENT_NOBODY_JUDGED } from "./gate-outcome.js";
@@ -17,11 +17,13 @@ import { callFaceSeat } from "./tool-roster.js";
17
17
  import { heldBy, wireOf } from "./tool-name-readings.js";
18
18
  import { asksUnstated, modeAcceptsFileCommand, permissionSeatAt, unstatedAskMessage } from "./mode-policy.js";
19
19
  import { ORG_RULE_DECISION_REASON, ORG_UNAVAILABLE_DECISION_REASON } from "./permission-rule-org.js";
20
- import { exitGate, passAskFace } from "./runner/gate-exit.js";
20
+ import { exitGate, passAskFace, unownedArgsMessage } from "./runner/gate-exit.js";
21
21
  import { readOrgRuleLane, readPersistedRuleLane } from "./rule-lane-reads.js";
22
22
  import { traceHookCrash } from "./gate-crash-trace.js";
23
23
  import { createGateDeadline, awaitWriteProtectionJudgment, withGateTimeout } from "./gate-bounded-await.js";
24
24
  import { readStationAnswer } from "./shell-read-silence.js";
25
+ import { agentIdOf, judgedInputOf, raiseToolCheck } from "./mods/stations.js";
26
+ import { readToolChecks } from "./tool-check-reading.js";
25
27
  import { policyThrowLine, reportPolicyThrow } from "./runner/policy-throw.js";
26
28
  const QUESTION_TOOL_NAMES = new Set([ASK_USER_QUESTION_TOOL_NAME]);
27
29
  function parkWith(suspendAsk, parkArgs, carry) {
@@ -34,6 +36,38 @@ export async function runGateLanes(pass) {
34
36
  const boundedAwaitDeadlineMs = createGateDeadline(input, notifier);
35
37
  let orgRealApprovalRequired = false;
36
38
  let markedThisRound;
39
+ let approvedWithArgs = false;
40
+ let carriedOwnAsk;
41
+ const takeApprovedEdit = (read) => {
42
+ carriedOwnAsk = read.outstanding ?? (pass.decision.action === "ask" ? pass.decision : undefined);
43
+ pass.decision = read.allow;
44
+ approvedWithArgs = true;
45
+ };
46
+ const safetyOf = (d) => safetyAxisOf({ egress: input.egress, shellGated: input.shellGated, irreversibility: input.irreversibility, probeMandated: d.action === "ask" && d.probeMandated === true, probeUnanswered: pass.probeUnanswered === true, tightened: pass.tightenedBy });
47
+ const realApprovalOf = (d, org) => {
48
+ if (d.action !== "ask" || d.requiresRealApproval !== true)
49
+ return undefined;
50
+ if (d.origin === undefined)
51
+ throw new Error(`a real-approval ask for "${toolName}" reached a park site with no origin word — the origin stamp precedes every park`);
52
+ return { origin: d.origin, ...(org !== undefined ? { org } : {}) };
53
+ };
54
+ const carryOf = (d) => ({
55
+ ...(callSignal !== undefined ? { signal: callSignal } : {}),
56
+ ...(d.action === "ask" && d.denialLimitFallback !== undefined ? { denialLimitFallback: unarmedWindow(d.denialLimitFallback) } : {}),
57
+ ...(d.action === "ask" && d.classifierNoRuling !== undefined ? { classifierNoRuling: d.classifierNoRuling } : {}),
58
+ ...(d.action === "ask" && d.origin !== undefined ? { origin: d.origin } : {}),
59
+ ...(d.action === "ask" && d.askClass !== undefined && d.classes !== undefined ? { askClass: d.askClass, classes: d.classes } : {}),
60
+ ...(d.action === "ask" && d.mandated === true ? { mandated: true, ...(d.mandate !== undefined ? { mandate: d.mandate } : {}) } : {}),
61
+ ...(d.action === "ask" && d.authoredBy === "deployment" ? { authoredBy: "deployment" } : {}),
62
+ });
63
+ const parkAsk = async (d, req, args, safety, liveFaceUnavailable, org) => {
64
+ if (suspendAsk === undefined || d.action !== "ask")
65
+ return undefined;
66
+ const suspended = await parkWith(suspendAsk, [req, args, safety, liveFaceUnavailable, realApprovalOf(d, org), d.allowRuleShadowed, d.decisionReason, d.probeReason, d.probeCause, d.segmentCoverage, d.matchedAskRule, d.probeMandated], carryOf(d));
67
+ if (suspended && "parkFailed" in suspended)
68
+ pass.parkFailed = suspended.parkFailed;
69
+ return suspended && !("parkFailed" in suspended) ? { suspend: suspended, preToolContext: pass.preToolContext } : undefined;
70
+ };
37
71
  const markedUnresolvable = () => (markedThisRound ??= input.isMarkedUnresolvable?.(input.event.toolCallId) === true);
38
72
  const mandateMarksNow = () => ({
39
73
  egress: input.egress,
@@ -75,7 +109,7 @@ export async function runGateLanes(pass) {
75
109
  if (wireOf("lanes.orgContentAskExemption", pass.req) === ASK_USER_QUESTION_TOOL_NAME && input.orgRules.contentAskToolMounted === true)
76
110
  return { decision: current, org: undefined };
77
111
  let decided = current;
78
- const answer = await readOrgRuleLane(input.orgRules, { toolName, args, toolCallId, ...callFaceSeat(pass.req.face) }, input.abortSignal);
112
+ const answer = await readOrgRuleLane(input.orgRules, Object.freeze({ toolName, args, toolCallId, ...callFaceSeat(pass.req.face) }), input.abortSignal);
79
113
  if (answer.status === "unavailable") {
80
114
  orgEvidence = { revisionAbsent: "unavailable", ruleAbsent: "unavailable" };
81
115
  orgRealApprovalRequired = true;
@@ -103,7 +137,7 @@ export async function runGateLanes(pass) {
103
137
  orgTightenCount += 1;
104
138
  pass.deniedBy = "org";
105
139
  pass.denyCause = undefined;
106
- return { decision: { action: "deny", message: `an organization policy rule (${rule}) denies this call`, decisionReason: ORG_RULE_DECISION_REASON }, org: undefined };
140
+ return { decision: refusalOf({ action: "deny", message: `an organization policy rule (${rule}) denies this call`, decisionReason: ORG_RULE_DECISION_REASON }, args), org: undefined };
107
141
  }
108
142
  if (decided.action === "deny")
109
143
  return { decision: decided, org: undefined };
@@ -120,33 +154,75 @@ export async function runGateLanes(pass) {
120
154
  org: "rule",
121
155
  };
122
156
  };
123
- const orgAnswer = await applyOrgLayer(pass.decision, pass.policyRewrite !== undefined ? pass.policyRewrite : pass.currentInput);
157
+ const finalArgs = pass.policyRewrite !== undefined ? pass.policyRewrite : pass.currentInput;
158
+ if (pass.decision.action === "deny")
159
+ pass.decision = refusalOf(pass.decision, finalArgs);
160
+ const orgAnswer = await applyOrgLayer(pass.decision, finalArgs);
124
161
  pass.decision = orgAnswer.decision;
125
162
  const readPersistedRules = (req) => readPersistedRuleLane(input.persistedRules, req, input.abortSignal);
126
163
  const reread = pass.policyRewrite !== undefined ? withArgsReading(pass.req, pass.policyRewrite, pass.callSignal ?? input.abortSignal) : undefined;
127
- const laneReq = reread !== undefined ? await reread : { ...pass.req, ...(pass.policyRewrite !== undefined ? { args: pass.policyRewrite } : {}) };
164
+ const laneReq = Object.freeze(reread !== undefined ? await reread : { ...pass.req, ...(pass.policyRewrite !== undefined ? { args: pass.policyRewrite } : {}) });
128
165
  const laneAnswer = input.persistedRules !== undefined && wireOf("lanes.persistedLaneSkip", pass.req) !== ASK_USER_QUESTION_TOOL_NAME ? await readPersistedRules(laneReq) : undefined;
129
166
  {
130
167
  const tightened = applyPersistedTightening(pass.decision, laneAnswer, laneReq);
131
- pass.decision = tightened.decision;
168
+ pass.decision = tightened.tightened === "deny" ? refusalOf(tightened.decision, laneReq.args) : tightened.decision;
132
169
  if (tightened.tightened === "deny")
133
170
  pass.deniedBy = "persisted_rule";
134
171
  if (tightened.tightened === "deny")
135
172
  pass.denyCause = undefined;
136
173
  const skillRefusal = pass.decision.action === "deny" ? undefined : skillRowRefusal(input.skillGrants, laneReq);
137
174
  if (skillRefusal !== undefined) {
138
- pass.decision = skillRefusal;
175
+ pass.decision = refusalOf(skillRefusal, laneReq.args);
139
176
  pass.deniedBy = "policy";
140
177
  pass.denyCause = undefined;
141
178
  }
142
179
  }
180
+ let settledRefusal;
181
+ const checkTool = async (standing, args, org, rewrite, mayClear) => {
182
+ const agentId = agentIdOf(input.identity);
183
+ const ceiling = org !== undefined ? { ceiling: "ask" } : {};
184
+ const e = { tool: toolName, input: judgedInputOf(args), tool_use_id: toolCallId, ...(agentId !== undefined ? { agentId } : {}), ...ceiling };
185
+ const signal = callSignal ?? input.abortSignal;
186
+ const own = input.modBus;
187
+ settledRefusal = undefined;
188
+ const settleThroughLedger = (settle) => async (ask, call, sig) => {
189
+ const read = ledger.fromDecision(await settle(ask, call, sig));
190
+ if (read.decision.action === "deny")
191
+ settledRefusal = { deniedBy: read.deniedBy ?? "policy", cause: ledger.causeOf(read.decision) };
192
+ return read.decision;
193
+ };
194
+ const chains = [
195
+ ...(own !== undefined ? [{ raise: (p) => raiseToolCheck(own, { ...e }, p, signal), ...(mayClear !== undefined ? { mayClear } : {}) }] : []),
196
+ ...(input.inheritedToolChecks ?? []).map((c) => ({ raise: (p) => raiseToolCheck(c.bus, { ...e }, p, signal, c.judges), settle: settleThroughLedger(c.settle) })),
197
+ ];
198
+ const project = (current, clears) => {
199
+ const reason = decisionText(current);
200
+ const said = reason !== undefined ? { reason } : {};
201
+ return current.action === "ask" ? { decision: "ask", ...said, classes: [...(current.classes ?? [])], mandated: clears?.() !== true, ...ceiling } : { decision: "allow", ...said, ...ceiling };
202
+ };
203
+ return await readToolChecks(chains, standing, { toolName, judged: args, rewrite, request: Object.freeze({ ...pass.req, args }), signal }, project);
204
+ };
205
+ const refuseByExtension = (deny) => {
206
+ pass.decision = deny;
207
+ pass.deniedBy = settledRefusal?.deniedBy ?? "hook";
208
+ pass.denyCause = settledRefusal?.cause;
209
+ };
210
+ if (pass.decision.action === "allow") {
211
+ const read = await checkTool(pass.decision, finalArgs, orgAnswer.org, pass.policyRewrite);
212
+ if (read !== undefined)
213
+ pass.toolCheckRaised = true;
214
+ if (read?.kind === "denied")
215
+ refuseByExtension(read.deny);
216
+ else if (read?.kind === "asked")
217
+ pass.decision = read.ask;
218
+ else if (read?.kind === "approved")
219
+ takeApprovedEdit(read);
220
+ }
143
221
  if (pass.decision.action === "ask") {
144
222
  pass.decision = { ...pass.decision };
145
223
  if (pass.policyRewrite !== undefined) {
146
224
  pass.currentInput = pass.policyRewrite;
147
- pass.req.args = pass.policyRewrite;
148
- if (laneReq.targetReading !== undefined)
149
- pass.req.targetReading = laneReq.targetReading;
225
+ pass.req = Object.freeze({ ...pass.req, args: pass.policyRewrite, ...(laneReq.targetReading !== undefined ? { targetReading: laneReq.targetReading } : {}) });
150
226
  }
151
227
  const ruleMayClear = () => ruleClearanceOf(pass.decision.action === "ask" ? pass.decision : undefined, mandateMarksNow()).ruleMayClear;
152
228
  const classMayClear = () => pass.decision.action === "ask" && classifyAsk(pass.decision, askOriginFacts(orgAnswer.org, laneAnswer)).row.ruleMayClear;
@@ -194,7 +270,7 @@ export async function runGateLanes(pass) {
194
270
  });
195
271
  const storedAllows = laneAnswer?.hit?.behavior === "allow" ? laneAnswer.hit.rules : undefined;
196
272
  const members = [
197
- ["hook", () => (pass.hookAllowed === true && pass.policyRewrite === undefined ? { entries: [], clear: () => ({ action: "allow", message: "a PreToolUse hook allowed this call", decisionReason: "hook" }), afterClear: async () => undefined } : undefined)],
273
+ ["hook", () => (pass.hookAllowedBy !== undefined && pass.policyRewrite === undefined ? { entries: pass.hookAllowedBy, clear: () => ({ action: "allow", message: "a PreToolUse hook allowed this call", decisionReason: "hook" }), afterClear: async () => undefined } : undefined)],
198
274
  ["deployment", () => {
199
275
  const hit = input.deploymentAllows?.allowing(pass.req, mode);
200
276
  return hit && { entries: hit.entries, clear: () => listAllow("deployment_rule", "the deployment's", hit.entries), afterClear: () => notifier.notifyAsync(() => input.deploymentAllows?.onAllowed?.({ toolName: pass.req.toolName, toolCallId, entries: hit.entries }), "toolGate.allowedToolsResolved") };
@@ -268,6 +344,24 @@ export async function runGateLanes(pass) {
268
344
  pass.decision = { ...pass.decision, message: CD_GIT_COMPOUND_SENTENCE };
269
345
  }
270
346
  }
347
+ if (pass.toolCheckRaised !== true && pass.decision.action !== "deny") {
348
+ const read = await checkTool(pass.decision, pass.currentInput, orgAnswer.org, pass.policyRewrite, () => allowLayerMayClear() && ruleMayClear() && classMayClear());
349
+ if (read?.kind === "denied")
350
+ refuseByExtension(read.deny);
351
+ else if (read?.kind === "cleared")
352
+ pass.decision = read.allow;
353
+ else if (read?.kind === "asked") {
354
+ const asked = read.minted ? { ...read.ask, ruleEvidence: mintRuleEvidence(personalEvidence) } : read.ask;
355
+ if (read.marked === true)
356
+ markedThisRound = undefined;
357
+ const facts = read.marked === true ? askOriginFacts(orgAnswer.org, laneAnswer) : originFacts;
358
+ pass.decision = stampAskOrigin(asked, facts, classifyStanding(asked, facts));
359
+ }
360
+ else if (read?.kind === "shadowed" && pass.decision.action === "ask")
361
+ pass.decision = { ...pass.decision, allowRuleShadowed: [...(pass.decision.allowRuleShadowed ?? []), ...read.shadows] };
362
+ else if (read?.kind === "approved")
363
+ takeApprovedEdit(read);
364
+ }
271
365
  if (pass.decision.action === "ask")
272
366
  ledger.supersede();
273
367
  if (input.autoMode && pass.decision.action === "ask" && pass.decision.origin !== undefined && pass.askClassification?.row.classifierEligible === true && (input.permissionMode === undefined || input.permissionMode() === "auto")) {
@@ -296,7 +390,7 @@ export async function runGateLanes(pass) {
296
390
  pass.classifierRound = undefined;
297
391
  }
298
392
  else if (arm?.kind === "denied")
299
- pass.decision = arm.deny;
393
+ pass.decision = refusalOf(arm.deny, finalArgs);
300
394
  else {
301
395
  const reason = verdict.kind === "block" ? (verdict.reason ? inlineUntrusted(verdict.reason) : "") : classifierParseFailureDenyMessage(verdict.classifier);
302
396
  const category = verdict.kind === "block" && verdict.category ? inlineUntrusted(verdict.category) : "";
@@ -310,7 +404,7 @@ export async function runGateLanes(pass) {
310
404
  message: verdict.kind === "block" ? `auto-mode classifier blocked this call${reason ? `: ${reason}` : category ? `: [${category}]` : ""}` : reason,
311
405
  decisionReason: "classifier",
312
406
  };
313
- pass.decision = verdict.kind === "parse_error" ? attest(denied, pass.req, { classifierCause: "parse_error" }) : denied;
407
+ pass.decision = refusalOf(verdict.kind === "parse_error" ? attest(denied, pass.req, { classifierCause: "parse_error" }) : denied, finalArgs);
314
408
  }
315
409
  }
316
410
  }
@@ -373,86 +467,46 @@ export async function runGateLanes(pass) {
373
467
  pass.arbitration = verdict;
374
468
  pass.deniedBy = "mode";
375
469
  pass.denyCause = undefined;
376
- pass.decision = {
470
+ pass.decision = refusalOf({
377
471
  action: "deny",
378
472
  message: verdict.mode === "dontAsk"
379
473
  ? `refused by the dontAsk permission mode: this call needed approval (${verdict.askClass}) and the mode answers no ask; run under a mode with an approver, or change the call`
380
474
  : `refused by the bypassPermissions permission mode: the write-protection judge could not resolve this write's target, and with nobody to ask the mode refuses rather than releases it`,
381
475
  decisionReason: "mode",
382
- };
476
+ }, finalArgs);
383
477
  }
384
478
  }
385
- const safety = safetyAxisOf({
386
- egress: input.egress,
387
- shellGated: input.shellGated,
388
- irreversibility: input.irreversibility,
389
- probeMandated: pass.decision.action === "ask" && pass.decision.probeMandated === true,
390
- probeUnanswered: pass.probeUnanswered === true,
391
- tightened: pass.tightenedBy,
392
- });
393
- const realApprovalOf = (d) => {
394
- if (d.action !== "ask" || d.requiresRealApproval !== true)
395
- return undefined;
396
- if (d.origin === undefined)
397
- throw new Error(`a real-approval ask for "${toolName}" reached a park site with no origin word — the origin stamp precedes every park`);
398
- return { origin: d.origin, ...(originFacts.org !== undefined ? { org: originFacts.org } : {}) };
399
- };
400
- const carryOf = (d) => ({
401
- ...(callSignal !== undefined ? { signal: callSignal } : {}),
402
- ...(d.action === "ask" && d.denialLimitFallback !== undefined ? { denialLimitFallback: unarmedWindow(d.denialLimitFallback) } : {}),
403
- ...(d.action === "ask" && d.classifierNoRuling !== undefined ? { classifierNoRuling: d.classifierNoRuling } : {}),
404
- ...(d.action === "ask" && d.origin !== undefined ? { origin: d.origin } : {}),
405
- ...(d.action === "ask" && d.askClass !== undefined && d.classes !== undefined ? { askClass: d.askClass, classes: d.classes } : {}),
406
- ...(d.action === "ask" && d.mandated === true ? { mandated: true, ...(d.mandate !== undefined ? { mandate: d.mandate } : {}) } : {}),
407
- ...(d.action === "ask" && d.authoredBy === "deployment" ? { authoredBy: "deployment" } : {}),
408
- });
479
+ const safety = safetyOf(pass.decision);
409
480
  if (suspendAsk && pass.decision.action === "ask") {
410
- const parkArgs = [pass.req, pass.currentInput, safety, undefined, realApprovalOf(pass.decision), pass.decision.action === "ask" ? pass.decision.allowRuleShadowed : undefined, pass.decision.action === "ask" ? pass.decision.decisionReason : undefined, pass.decision.action === "ask" ? pass.decision.probeReason : undefined, pass.decision.action === "ask" ? pass.decision.probeCause : undefined, pass.decision.action === "ask" ? pass.decision.segmentCoverage : undefined, pass.decision.action === "ask" ? pass.decision.matchedAskRule : undefined, pass.decision.action === "ask" ? pass.decision.probeMandated : undefined];
411
- const suspended = await parkWith(suspendAsk, parkArgs, carryOf(pass.decision));
412
- if (suspended) {
413
- if ("parkFailed" in suspended)
414
- pass.parkFailed = suspended.parkFailed;
415
- else
416
- return { suspend: suspended, preToolContext: pass.preToolContext };
417
- }
481
+ const parked = await parkAsk(pass.decision, pass.req, pass.currentInput, safety, undefined, originFacts.org);
482
+ if (parked)
483
+ return parked;
418
484
  }
419
485
  if (pass.decision.action === "ask" && wireOf("lanes.contentAskRoute", pass.req) === ASK_USER_QUESTION_TOOL_NAME) {
420
486
  const outcome = input.resolveContentAsk !== undefined ? await (callSignal !== undefined ? input.resolveContentAsk(pass.req, callSignal) : input.resolveContentAsk(pass.req)) : { kind: "unavailable", parkDeclined: false };
421
487
  if (outcome.kind === "answered") {
422
- pass.decision = { action: "allow", updatedInput: outcome.presentedInput };
488
+ pass.decision = { action: "allow" };
423
489
  }
424
490
  else if (outcome.kind === "unavailable") {
425
- if (outcome.presentedInput !== undefined) {
426
- pass.currentInput = outcome.presentedInput;
427
- pass.req.args = outcome.presentedInput;
428
- }
429
491
  if (suspendAsk && outcome.parkDeclined && pass.parkFailed === undefined) {
430
- const parkArgs = [pass.req, pass.currentInput, safety, true, realApprovalOf(pass.decision), pass.decision.action === "ask" ? pass.decision.allowRuleShadowed : undefined, pass.decision.action === "ask" ? pass.decision.decisionReason : undefined, pass.decision.action === "ask" ? pass.decision.probeReason : undefined, pass.decision.action === "ask" ? pass.decision.probeCause : undefined, pass.decision.action === "ask" ? pass.decision.segmentCoverage : undefined, pass.decision.action === "ask" ? pass.decision.matchedAskRule : undefined, pass.decision.action === "ask" ? pass.decision.probeMandated : undefined];
431
- const suspended = await parkWith(suspendAsk, parkArgs, carryOf(pass.decision));
432
- if (suspended) {
433
- if ("parkFailed" in suspended)
434
- pass.parkFailed = suspended.parkFailed;
435
- else
436
- return { suspend: suspended, preToolContext: pass.preToolContext };
437
- }
492
+ const parked = await parkAsk(pass.decision, pass.req, pass.currentInput, safety, true, originFacts.org);
493
+ if (parked)
494
+ return parked;
438
495
  }
439
496
  if (pass.decision.origin === undefined)
440
497
  throw new Error(`the content ask for "${toolName}" reached its refusal without an origin word`);
441
498
  ledger.set({ settlement: { kind: input.resolveContentAsk !== undefined ? "approver_unavailable" : "no_approver", who: { party: "none" }, when: Date.now() }, origin: pass.decision.origin });
442
499
  pass.deniedBy = "ask_resolution";
443
- pass.decision = {
500
+ pass.decision = refusalOf({
444
501
  action: "deny",
445
502
  message: "AskUserQuestion could not be parked for a durable human answer on this path (no checkpoint " +
446
503
  "facility, or the suspend failed) and a synchronous permission approver cannot carry an answer — " +
447
504
  "the question was NOT shown to anyone. Proceed with your best judgment and state the assumption " +
448
505
  "you made.",
449
- };
506
+ }, finalArgs);
450
507
  }
451
508
  else {
452
- if (outcome.presentedInput !== undefined)
453
- pass.decision = { action: "allow", updatedInput: outcome.presentedInput };
454
- else
455
- pass.decision = { action: "allow" };
509
+ pass.decision = { action: "allow" };
456
510
  }
457
511
  }
458
512
  if (pass.decision.action === "ask") {
@@ -467,16 +521,11 @@ export async function runGateLanes(pass) {
467
521
  resolved = ledger.fromResolved(resolved, askBeforeResolve, pass.req);
468
522
  if (resolved.action === "deny")
469
523
  pass.deniedBy = "ask_resolution";
470
- pass.decision = resolved;
524
+ pass.decision = resolved.action === "deny" ? refusalOf(resolved, finalArgs) : resolved;
471
525
  if (resolved.action === "deny" && resolved.approverUnavailable === true && suspendAsk && pass.parkFailed === undefined) {
472
- const parkArgs = [pass.req, pass.currentInput, safety, true, realApprovalOf(askBeforeResolve), askBeforeResolve.action === "ask" ? askBeforeResolve.allowRuleShadowed : undefined, askBeforeResolve.action === "ask" ? askBeforeResolve.decisionReason : undefined, askBeforeResolve.action === "ask" ? askBeforeResolve.probeReason : undefined, askBeforeResolve.action === "ask" ? askBeforeResolve.probeCause : undefined, askBeforeResolve.action === "ask" ? askBeforeResolve.segmentCoverage : undefined, askBeforeResolve.action === "ask" ? askBeforeResolve.matchedAskRule : undefined, askBeforeResolve.action === "ask" ? askBeforeResolve.probeMandated : undefined];
473
- const suspended = await parkWith(suspendAsk, parkArgs, carryOf(askBeforeResolve));
474
- if (suspended) {
475
- if ("parkFailed" in suspended)
476
- pass.parkFailed = suspended.parkFailed;
477
- else
478
- return { suspend: suspended, preToolContext: pass.preToolContext };
479
- }
526
+ const parked = await parkAsk(askBeforeResolve, pass.req, pass.currentInput, safety, true, originFacts.org);
527
+ if (parked)
528
+ return parked;
480
529
  }
481
530
  if (askBeforeResolve.action === "ask" && askBeforeResolve.denialLimitFallback !== undefined) {
482
531
  if (pass.decision.action === "allow") {
@@ -493,211 +542,248 @@ export async function runGateLanes(pass) {
493
542
  }
494
543
  }
495
544
  }
496
- if (pass.decision.action === "allow" && pass.decision.updatedInput !== undefined) {
497
- let editArgs = pass.decision.updatedInput;
498
- let editDenied;
499
- let editRewrittenSinceHuman = false;
500
- for (let round = 0;; round++) {
501
- if (round >= 3) {
502
- editDenied = {
503
- action: "deny",
504
- message: `the approval-edit chain for "${toolName}" exceeded the re-approval cap — denied fail-closed; re-submit the edited action directly`,
505
- };
506
- pass.deniedBy = "policy";
507
- break;
508
- }
509
- if (screening !== undefined) {
510
- let hr;
511
- let hrUnanswered;
512
- try {
513
- const seat = await screening.screen(editArgs);
514
- if (seat.expired)
515
- hrUnanswered = seat.cause;
516
- else
517
- hr = screening.screened(seat.value);
518
- }
519
- catch (err) {
520
- traceHookCrash(input, err, notifier);
521
- editDenied = { action: "deny", message: screening.crashReason(`the approved edit for "${toolName}"`, err) };
522
- pass.deniedBy = "hook";
523
- break;
524
- }
525
- if (hrUnanswered !== undefined) {
526
- editDenied = { action: "deny", message: await screening.unansweredReason(`the approved edit for "${toolName}"`, hrUnanswered) };
527
- pass.deniedBy = "hook";
528
- break;
529
- }
530
- if (hr) {
531
- if (hr.additionalContext)
532
- pass.preToolContext.push(hr.additionalContext);
533
- if (hr.action === "deny") {
534
- editDenied = { action: "deny", message: decisionText(hr) ?? `the approved edit for "${toolName}" was blocked by a PreToolUse hook` };
535
- pass.deniedBy = "hook";
536
- break;
537
- }
538
- if (hr.action === "ask") {
539
- editDenied = {
540
- action: "deny",
541
- message: `the approved edit for "${toolName}" raises a new PreToolUse approval requirement the original approval does not cover — denied fail-closed; re-submit the edited action directly`,
542
- };
543
- pass.deniedBy = "hook";
544
- break;
545
- }
546
- if (hr.updatedInput !== undefined) {
547
- editArgs = hr.updatedInput;
548
- editRewrittenSinceHuman = true;
549
- }
550
- }
551
- }
552
- let recheck = { action: "allow" };
553
- if (adjudicate) {
554
- try {
555
- const editReq = { toolName, args: editArgs, toolCallId, ...(pass.req.face !== undefined ? { face: pass.req.face } : {}) };
556
- recheck = refuseOutOfContractDecision(await (callSignal !== undefined ? adjudicate(editReq, callSignal) : adjudicate(editReq)));
557
- }
558
- catch (err) {
559
- reportPolicyThrow((e) => traceHookCrash(input, e, notifier), "the tool policy's re-check of the approved edit", { toolName, toolCallId }, err, callSignal ?? input.abortSignal);
560
- recheck = {
561
- action: "deny",
562
- message: `policy re-check of the approved edit for "${toolName}" errored: ${policyThrowLine(err)}`,
563
- };
564
- }
565
- }
566
- {
567
- const attributed = ledger.classifierRoundOf(recheck);
568
- if (attributed !== undefined)
569
- pass.classifierRound = attributed;
570
- const read = ledger.fromDecision(recheck);
571
- recheck = read.decision;
572
- if (recheck.action === "deny" && read.deniedBy !== undefined) {
573
- editDenied = recheck;
574
- pass.deniedBy = read.deniedBy;
575
- pass.denyCause = ledger.causeOf(recheck);
576
- break;
577
- }
578
- }
579
- if (recheck.updatedInput !== undefined) {
580
- editArgs = recheck.updatedInput;
581
- editRewrittenSinceHuman = true;
582
- }
583
- const editOrg = await applyOrgLayer(recheck, editArgs);
584
- recheck = editOrg.decision;
585
- if (recheck.action === "deny") {
586
- editDenied = recheck;
587
- break;
588
- }
589
- let editLane;
590
- const editReread = withArgsReading(pass.req, editArgs, callSignal ?? input.abortSignal);
591
- const editLaneReq = editReread !== undefined ? await editReread : { toolName, args: editArgs, toolCallId, ...(pass.req.face !== undefined ? { face: pass.req.face } : {}) };
592
- if (input.persistedRules !== undefined && wireOf("lanes.persistedEditSkip", pass.req) !== ASK_USER_QUESTION_TOOL_NAME) {
593
- editLane = await readPersistedRules(editLaneReq);
594
- const editTightened = applyPersistedTightening(recheck, editLane, editLaneReq);
595
- recheck = editTightened.decision;
596
- if (editTightened.tightened === "deny")
597
- pass.deniedBy = "persisted_rule";
598
- if (recheck.action === "deny") {
599
- editDenied = recheck;
600
- break;
601
- }
602
- }
603
- const editSkillRefusal = skillRowRefusal(input.skillGrants, editLaneReq);
604
- if (editSkillRefusal !== undefined) {
605
- editDenied = editSkillRefusal;
606
- pass.deniedBy = "policy";
545
+ approvedWithArgs = pass.decision.action === "allow" && pass.decision.updatedInput !== undefined;
546
+ }
547
+ }
548
+ if (approvedWithArgs && pass.decision.action === "allow" && pass.decision.updatedInput !== undefined) {
549
+ let editArgs = pass.decision.updatedInput;
550
+ let editDenied;
551
+ let editRewrittenSinceHuman = false;
552
+ let unanswered;
553
+ const refusedAtResolution = (d) => { editDenied = d; pass.deniedBy = "ask_resolution"; };
554
+ for (let round = 0;; round++) {
555
+ const taken = ownArgs(editArgs);
556
+ if (!taken.ok) {
557
+ editDenied = { action: "deny", message: unownedArgsMessage(`the approved edit for "${toolName}"`, taken.reason) };
558
+ pass.deniedBy = "policy";
559
+ break;
560
+ }
561
+ editArgs = taken.value;
562
+ if (round >= 3) {
563
+ editDenied = {
564
+ action: "deny",
565
+ message: `the approval-edit chain for "${toolName}" exceeded the re-approval cap — denied fail-closed; re-submit the edited action directly`,
566
+ };
567
+ pass.deniedBy = "policy";
568
+ break;
569
+ }
570
+ let editHookAsk;
571
+ if (screening !== undefined) {
572
+ const screened = await screening.screen(editArgs, `the approved edit for "${toolName}"`);
573
+ if (screened.kind === "refused") {
574
+ editDenied = { action: "deny", message: screened.reason };
575
+ pass.deniedBy = "hook";
576
+ break;
577
+ }
578
+ const hr = screened.answer;
579
+ if (hr) {
580
+ if (hr.additionalContext)
581
+ pass.preToolContext.push(hr.additionalContext);
582
+ if (hr.action === "deny") {
583
+ editDenied = { action: "deny", message: decisionText(hr) ?? `the approved edit for "${toolName}" was blocked by a PreToolUse hook` };
584
+ pass.deniedBy = "hook";
607
585
  break;
608
586
  }
609
- if (recheck.action === "allow") {
610
- if (recheck.updatedInput !== undefined) {
611
- editArgs = recheck.updatedInput;
612
- editRewrittenSinceHuman = true;
613
- }
614
- if (!editRewrittenSinceHuman || !asksUnstated(recheck, permissionSeatAt(input, editArgs)?.seat, input.permissionMode?.()))
615
- break;
616
- recheck = { action: "ask", message: permissionSeatAt(input, editArgs)?.question ?? unstatedAskMessage(toolName) };
617
- pass.tightenedBy = "unstated";
587
+ if (hr.action === "ask") {
588
+ const { updatedInput: _adopted, ...ask } = hr;
589
+ editHookAsk = ask;
618
590
  }
619
- if (recheck.updatedInput !== undefined) {
620
- editArgs = recheck.updatedInput;
591
+ if (hr.updatedInput !== undefined) {
592
+ editArgs = hr.updatedInput;
621
593
  editRewrittenSinceHuman = true;
622
594
  }
623
- const editAskSnapshot = { ...recheck, ruleEvidence: mintRuleEvidence({ dotsAbsent: "not_adjudicated" }) };
595
+ }
596
+ }
597
+ let recheck = { action: "allow" };
598
+ if (adjudicate) {
599
+ try {
600
+ const editReq = Object.freeze({ toolName, args: editArgs, toolCallId, ...(pass.req.face !== undefined ? { face: pass.req.face } : {}) });
601
+ recheck = refuseOutOfContractDecision(await (callSignal !== undefined ? adjudicate(editReq, callSignal) : adjudicate(editReq)));
602
+ }
603
+ catch (err) {
604
+ reportPolicyThrow((e) => traceHookCrash(input, e, notifier), "the tool policy's re-check of the approved edit", { toolName, toolCallId }, err, callSignal ?? input.abortSignal);
605
+ recheck = {
606
+ action: "deny",
607
+ message: `policy re-check of the approved edit for "${toolName}" errored: ${policyThrowLine(err)}`,
608
+ };
609
+ }
610
+ }
611
+ {
612
+ const attributed = ledger.classifierRoundOf(recheck);
613
+ if (attributed !== undefined)
614
+ pass.classifierRound = attributed;
615
+ const read = ledger.fromDecision(recheck);
616
+ recheck = read.decision;
617
+ if (recheck.action === "deny" && read.deniedBy !== undefined) {
618
+ editDenied = recheck;
619
+ pass.deniedBy = read.deniedBy;
620
+ pass.denyCause = ledger.causeOf(recheck);
621
+ break;
622
+ }
623
+ }
624
+ if (recheck.updatedInput !== undefined) {
625
+ editArgs = recheck.updatedInput;
626
+ editRewrittenSinceHuman = true;
627
+ }
628
+ const editOrg = await applyOrgLayer(recheck, editArgs);
629
+ recheck = editOrg.decision;
630
+ if (recheck.action === "deny") {
631
+ editDenied = recheck;
632
+ break;
633
+ }
634
+ let editLane;
635
+ const editReread = withArgsReading(pass.req, editArgs, callSignal ?? input.abortSignal);
636
+ const editLaneReq = Object.freeze(editReread !== undefined ? await editReread : { toolName, args: editArgs, toolCallId, ...(pass.req.face !== undefined ? { face: pass.req.face } : {}) });
637
+ if (input.persistedRules !== undefined && wireOf("lanes.persistedEditSkip", pass.req) !== ASK_USER_QUESTION_TOOL_NAME) {
638
+ editLane = await readPersistedRules(editLaneReq);
639
+ const editTightened = applyPersistedTightening(recheck, editLane, editLaneReq);
640
+ recheck = editTightened.decision;
641
+ if (editTightened.tightened === "deny")
642
+ pass.deniedBy = "persisted_rule";
643
+ if (recheck.action === "deny") {
644
+ editDenied = recheck;
645
+ break;
646
+ }
647
+ }
648
+ const editSkillRefusal = skillRowRefusal(input.skillGrants, editLaneReq);
649
+ if (editSkillRefusal !== undefined) {
650
+ editDenied = editSkillRefusal;
651
+ pass.deniedBy = "policy";
652
+ break;
653
+ }
654
+ if (recheck.action === "allow") {
655
+ if (recheck.updatedInput !== undefined) {
656
+ editArgs = recheck.updatedInput;
657
+ editRewrittenSinceHuman = true;
658
+ }
659
+ if (editRewrittenSinceHuman && asksUnstated(recheck, permissionSeatAt(input, editArgs)?.seat, input.permissionMode?.())) {
660
+ recheck = { action: "ask", message: permissionSeatAt(input, editArgs)?.question ?? unstatedAskMessage(toolName) };
661
+ pass.tightenedBy = "unstated";
662
+ }
663
+ }
664
+ if (recheck.updatedInput !== undefined) {
665
+ editArgs = recheck.updatedInput;
666
+ editRewrittenSinceHuman = true;
667
+ }
668
+ let editFacts;
669
+ const stampEditAsk = (ask) => {
670
+ const editAskSnapshot = { ...ask, ruleEvidence: mintRuleEvidence({ dotsAbsent: "not_adjudicated" }) };
671
+ if (editFacts === undefined) {
624
672
  markedThisRound = undefined;
625
- const editFacts = askOriginFacts(editOrg.org, editLane);
626
- const editAskDecision = stampAskOrigin(editAskSnapshot, editFacts, classifyStanding(editAskSnapshot, editFacts));
627
- if (input.permissionMode !== undefined && pass.askClassification !== undefined) {
628
- const editVerdict = arbitrateByMode(input.permissionMode(), pass.askClassification, { ...(editAskDecision.origin !== undefined ? { origin: editAskDecision.origin } : {}), ...(editAskDecision.mandate !== undefined ? { mandate: editAskDecision.mandate } : {}) });
629
- if (editVerdict.kind === "released") {
630
- ledger.supersede();
631
- pass.arbitration = editVerdict;
632
- await notifier.notifyAsync(() => input.onModeReleased?.({ toolName, toolCallId, release: { mode: editVerdict.mode, askClass: editVerdict.askClass, classes: editVerdict.classes, ...(editVerdict.origin !== undefined ? { origin: editVerdict.origin } : {}), ...(editVerdict.mandate !== undefined ? { mandate: editVerdict.mandate } : {}), ...(editVerdict.reason !== undefined ? { reason: editVerdict.reason } : {}) }, ...(pass.shellReadUnestablished === true ? { readUnestablished: true } : {}) }), "toolGate.onModeReleased");
633
- break;
634
- }
635
- if (editVerdict.kind === "denied_by_mode") {
636
- ledger.supersede();
637
- pass.arbitration = editVerdict;
638
- editDenied = { action: "deny", message: `the approved edit for "${toolName}" raised a new approval requirement that the ${editVerdict.mode} permission mode refuses`, decisionReason: "mode" };
639
- pass.deniedBy = "mode";
640
- break;
641
- }
642
- }
643
- const editAskReq = { toolName, args: editArgs, toolCallId, ...(pass.req.face !== undefined ? { face: pass.req.face } : {}) };
644
- const rr = ledger.fromResolved(await (callSignal !== undefined ? resolveAsk(editAskDecision, editAskReq, callSignal) : resolveAsk(editAskDecision, editAskReq)), editAskDecision, editAskReq);
645
- if (rr.action !== "allow") {
646
- editDenied = rr;
647
- pass.deniedBy = "ask_resolution";
648
- break;
649
- }
650
- if (rr.updatedInput === undefined) {
651
- if (rr.presentedInput !== undefined)
652
- editArgs = rr.presentedInput;
653
- editRewrittenSinceHuman = false;
654
- break;
655
- }
656
- editArgs = rr.updatedInput;
657
- editRewrittenSinceHuman = false;
673
+ editFacts = askOriginFacts(editOrg.org, editLane);
658
674
  }
659
- if (editDenied === undefined && editRewrittenSinceHuman && input.writeProtectionCheck !== undefined) {
660
- const check = input.writeProtectionCheck;
661
- const verdict = await awaitWriteProtectionJudgment((deadline) => check(toolName, editArgs, pass.req.face, input.trackedCwd?.(), deadline), boundedAwaitDeadlineMs, callSignal ?? input.abortSignal);
662
- if (verdict !== undefined && verdict.kind !== "clear") {
663
- editDenied = {
664
- action: "deny",
665
- message: verdict.kind === "hit"
666
- ? `the approved edit for "${toolName}" was rewritten by the restriction chain onto a write-protected path (table entry "${verdict.hit.name}") that no approval covers — denied fail-closed; re-submit the edited action directly`
667
- : `the approved edit for "${toolName}" was rewritten by the restriction chain onto a target whose destination could not be determined (target_unresolved: ${verdict.cause}) — denied fail-closed; re-submit the edited action directly`,
668
- };
669
- pass.deniedBy = "write_protection";
670
- }
675
+ return stampAskOrigin(editAskSnapshot, editFacts, classifyStanding(editAskSnapshot, editFacts));
676
+ };
677
+ if (editHookAsk !== undefined)
678
+ recheck = foldHookAsk(recheck, editHookAsk);
679
+ let editDecision = recheck.action === "ask" ? stampEditAsk(recheck) : recheck;
680
+ if (carriedOwnAsk !== undefined) {
681
+ const { updatedInput: _theOriginalBytes, ...carried } = carriedOwnAsk;
682
+ const rra = carried.requiresRealApproval === true ? { requiresRealApproval: true } : {};
683
+ editDecision = stampEditAsk(editDecision.action === "ask" ? { ...editDecision, foldedAskClasses: [...(editDecision.foldedAskClasses ?? []), ...decisionAskClassesOf(carried), ...(carried.classes ?? [])], ...rra } : carried);
684
+ carriedOwnAsk = undefined;
685
+ }
686
+ const editRead = await checkTool(editDecision, editArgs, editOrg.org, undefined);
687
+ if (editRead?.kind === "denied") {
688
+ refuseByExtension(editRead.deny);
689
+ editDenied = editRead.deny;
690
+ break;
691
+ }
692
+ if (editRead?.kind === "approved") {
693
+ carriedOwnAsk = editRead.outstanding ?? (editDecision.action === "ask" ? editDecision : undefined);
694
+ editArgs = editRead.allow.updatedInput;
695
+ editRewrittenSinceHuman = false;
696
+ continue;
697
+ }
698
+ if (editRead?.kind === "asked" && editRead.marked === true)
699
+ editFacts = undefined;
700
+ if (editRead?.kind === "asked")
701
+ editDecision = stampEditAsk(editRead.ask);
702
+ else if (editRead?.kind === "shadowed" && editDecision.action === "ask")
703
+ editDecision = { ...editDecision, allowRuleShadowed: [...(editDecision.allowRuleShadowed ?? []), ...editRead.shadows] };
704
+ if (editDecision.action !== "ask")
705
+ break;
706
+ const editAskDecision = editDecision;
707
+ if (input.permissionMode !== undefined && pass.askClassification !== undefined) {
708
+ const editVerdict = arbitrateByMode(input.permissionMode(), pass.askClassification, { ...(editAskDecision.origin !== undefined ? { origin: editAskDecision.origin } : {}), ...(editAskDecision.mandate !== undefined ? { mandate: editAskDecision.mandate } : {}) });
709
+ if (editVerdict.kind === "released") {
710
+ ledger.supersede();
711
+ pass.arbitration = editVerdict;
712
+ await notifier.notifyAsync(() => input.onModeReleased?.({ toolName, toolCallId, release: { mode: editVerdict.mode, askClass: editVerdict.askClass, classes: editVerdict.classes, ...(editVerdict.origin !== undefined ? { origin: editVerdict.origin } : {}), ...(editVerdict.mandate !== undefined ? { mandate: editVerdict.mandate } : {}), ...(editVerdict.reason !== undefined ? { reason: editVerdict.reason } : {}) }, ...(pass.shellReadUnestablished === true ? { readUnestablished: true } : {}) }), "toolGate.onModeReleased");
713
+ break;
671
714
  }
672
- if (editDenied === undefined && input.shellReadCheck !== undefined) {
673
- const station = input.shellReadCheck;
674
- const judged = station.judge(pass.req, editArgs, input.trackedCwd?.(), callSignal ?? input.abortSignal, { seat: "rejudge", toolCallId });
675
- if (judged !== null) {
676
- let verdict;
677
- try {
678
- verdict = await withGateTimeout(judged, boundedAwaitDeadlineMs(), callSignal ?? input.abortSignal, "shellReadStation");
679
- }
680
- catch {
681
- verdict = station.unanswered(pass.req, "the read station could not answer");
682
- }
683
- const reading = readStationAnswer(verdict, { toolName, toolCallId, report: (e) => traceHookCrash(input, e, notifier) });
684
- if (reading.kind !== "vouch") {
685
- editDenied = {
686
- action: "deny",
687
- message: reading.verdict.sentence ?? `the approved edit for "${toolName}" reads where the read boundary does not vouch — denied fail-closed; re-submit the command as a fresh call and answer its card`,
688
- };
689
- pass.deniedBy = "read_boundary";
690
- if (reading.verdict.details !== undefined)
691
- pass.denyDetails = reading.verdict.details;
692
- }
693
- }
715
+ if (editVerdict.kind === "denied_by_mode") {
716
+ ledger.supersede();
717
+ pass.arbitration = editVerdict;
718
+ editDenied = { action: "deny", message: `the approved edit for "${toolName}" raised a new approval requirement that the ${editVerdict.mode} permission mode refuses`, decisionReason: "mode" };
719
+ pass.deniedBy = "mode";
720
+ break;
694
721
  }
695
- pass.decision = editDenied ?? { ...pass.decision, updatedInput: editArgs };
696
722
  }
697
- else if (pass.decision.action === "allow" && pass.decision.updatedInput === undefined && resolved.presentedInput !== undefined) {
698
- pass.decision = { ...pass.decision, updatedInput: resolved.presentedInput };
723
+ const editAskReq = Object.freeze({ toolName, args: editArgs, toolCallId, ...(pass.req.face !== undefined ? { face: pass.req.face } : {}) });
724
+ if (suspendAsk !== undefined && markedUnresolvable()) {
725
+ unanswered = { ask: editAskDecision, req: editAskReq, org: editOrg.org };
726
+ break;
727
+ }
728
+ const rr = ledger.fromResolved(await (callSignal !== undefined ? resolveAsk(editAskDecision, editAskReq, callSignal) : resolveAsk(editAskDecision, editAskReq)), editAskDecision, editAskReq);
729
+ if (rr.action !== "allow") {
730
+ refusedAtResolution(rr);
731
+ if (rr.approverUnavailable === true)
732
+ unanswered = { ask: editAskDecision, req: editAskReq, org: editOrg.org, deny: rr };
733
+ break;
699
734
  }
735
+ if (rr.updatedInput === undefined) {
736
+ editRewrittenSinceHuman = false;
737
+ break;
738
+ }
739
+ editArgs = rr.updatedInput;
740
+ editRewrittenSinceHuman = false;
741
+ }
742
+ const rejudged = () => editDenied === undefined || editDenied === unanswered?.deny;
743
+ if (rejudged() && editRewrittenSinceHuman && input.writeProtectionCheck !== undefined) {
744
+ const check = input.writeProtectionCheck;
745
+ const verdict = await awaitWriteProtectionJudgment((deadline) => check(toolName, editArgs, pass.req.face, input.trackedCwd?.(), deadline), boundedAwaitDeadlineMs, callSignal ?? input.abortSignal);
746
+ if (verdict !== undefined && verdict.kind !== "clear") {
747
+ editDenied = {
748
+ action: "deny",
749
+ message: verdict.kind === "hit"
750
+ ? `the approved edit for "${toolName}" was rewritten by the restriction chain onto a write-protected path (table entry "${verdict.hit.name}") that no approval covers — denied fail-closed; re-submit the edited action directly`
751
+ : `the approved edit for "${toolName}" was rewritten by the restriction chain onto a target whose destination could not be determined (target_unresolved: ${verdict.cause}) — denied fail-closed; re-submit the edited action directly`,
752
+ };
753
+ pass.deniedBy = "write_protection";
754
+ }
755
+ }
756
+ if (rejudged() && input.shellReadCheck !== undefined) {
757
+ const station = input.shellReadCheck;
758
+ const judged = station.judge(pass.req, editArgs, input.trackedCwd?.(), callSignal ?? input.abortSignal, { seat: "rejudge", toolCallId });
759
+ if (judged !== null) {
760
+ let verdict;
761
+ try {
762
+ verdict = await withGateTimeout(judged, boundedAwaitDeadlineMs(), callSignal ?? input.abortSignal, "shellReadStation");
763
+ }
764
+ catch {
765
+ verdict = station.unanswered(pass.req, "the read station could not answer");
766
+ }
767
+ const reading = readStationAnswer(verdict, { toolName, toolCallId, report: (e) => traceHookCrash(input, e, notifier) });
768
+ if (reading.kind !== "vouch") {
769
+ editDenied = {
770
+ action: "deny",
771
+ message: reading.verdict.sentence ?? `the approved edit for "${toolName}" reads where the read boundary does not vouch — denied fail-closed; re-submit the command as a fresh call and answer its card`,
772
+ };
773
+ pass.deniedBy = "read_boundary";
774
+ if (reading.verdict.details !== undefined)
775
+ pass.denyDetails = reading.verdict.details;
776
+ }
777
+ }
778
+ }
779
+ if (unanswered !== undefined && editDenied === unanswered.deny && pass.parkFailed === undefined) {
780
+ const parked = await parkAsk(unanswered.ask, unanswered.req, editArgs, safetyOf(unanswered.ask), unanswered.deny !== undefined || undefined, unanswered.org);
781
+ if (parked)
782
+ return parked;
700
783
  }
784
+ if (unanswered !== undefined && unanswered.deny === undefined && editDenied === undefined)
785
+ refusedAtResolution(ledger.fromResolved(await (callSignal !== undefined ? resolveAsk(unanswered.ask, unanswered.req, callSignal) : resolveAsk(unanswered.ask, unanswered.req)), unanswered.ask, unanswered.req));
786
+ pass.decision = editDenied !== undefined ? refusalOf(editDenied, editArgs) : { ...pass.decision, updatedInput: editArgs };
701
787
  }
702
788
  return await exitGate(pass);
703
789
  }