approval-md 0.0.1 → 0.1.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 (522) hide show
  1. package/LICENSE +176 -0
  2. package/NOTICE +5 -0
  3. package/README.md +909 -4
  4. package/SPEC.md +445 -32
  5. package/cli.js +29 -3
  6. package/dist/src/adapters/agentmail.js +1200 -0
  7. package/dist/src/adapters/agentmail.js.map +1 -0
  8. package/dist/src/adapters/conformance.js +461 -0
  9. package/dist/src/adapters/conformance.js.map +1 -0
  10. package/dist/src/adapters/contract.js +941 -0
  11. package/dist/src/adapters/contract.js.map +1 -0
  12. package/dist/src/adapters/email.js +749 -0
  13. package/dist/src/adapters/email.js.map +1 -0
  14. package/dist/src/adapters/env-passphrase.js +132 -0
  15. package/dist/src/adapters/env-passphrase.js.map +1 -0
  16. package/dist/src/adapters/registry.js +76 -0
  17. package/dist/src/adapters/registry.js.map +1 -0
  18. package/dist/src/adapters/smtp.js +499 -0
  19. package/dist/src/adapters/smtp.js.map +1 -0
  20. package/dist/src/adapters/vault-provider.js +161 -0
  21. package/dist/src/adapters/vault-provider.js.map +1 -0
  22. package/dist/src/channels/batch.js +121 -0
  23. package/dist/src/channels/batch.js.map +1 -0
  24. package/dist/src/channels/cli.js +468 -0
  25. package/dist/src/channels/cli.js.map +1 -0
  26. package/dist/src/channels/conformance.js +445 -0
  27. package/dist/src/channels/conformance.js.map +1 -0
  28. package/dist/src/channels/contract.js +494 -0
  29. package/dist/src/channels/contract.js.map +1 -0
  30. package/dist/src/channels/payload-view.js +43 -0
  31. package/dist/src/channels/payload-view.js.map +1 -0
  32. package/dist/src/channels/render-queue.js +564 -0
  33. package/dist/src/channels/render-queue.js.map +1 -0
  34. package/dist/src/channels/tagging.js +723 -0
  35. package/dist/src/channels/tagging.js.map +1 -0
  36. package/dist/src/channels/telegram.js +3190 -0
  37. package/dist/src/channels/telegram.js.map +1 -0
  38. package/dist/src/channels/web.js +903 -0
  39. package/dist/src/channels/web.js.map +1 -0
  40. package/dist/src/cli/adapter.js +278 -0
  41. package/dist/src/cli/adapter.js.map +1 -0
  42. package/dist/src/cli/amend.js +2171 -0
  43. package/dist/src/cli/amend.js.map +1 -0
  44. package/dist/src/cli/args.js +86 -0
  45. package/dist/src/cli/args.js.map +1 -0
  46. package/dist/src/cli/attest.js +307 -0
  47. package/dist/src/cli/attest.js.map +1 -0
  48. package/dist/src/cli/audit-card.js +201 -0
  49. package/dist/src/cli/audit-card.js.map +1 -0
  50. package/dist/src/cli/audit.js +460 -0
  51. package/dist/src/cli/audit.js.map +1 -0
  52. package/dist/src/cli/channel-telegram.js +2063 -0
  53. package/dist/src/cli/channel-telegram.js.map +1 -0
  54. package/dist/src/cli/channel-web.js +357 -0
  55. package/dist/src/cli/channel-web.js.map +1 -0
  56. package/dist/src/cli/channel.js +438 -0
  57. package/dist/src/cli/channel.js.map +1 -0
  58. package/dist/src/cli/checkpoint-tap.js +238 -0
  59. package/dist/src/cli/checkpoint-tap.js.map +1 -0
  60. package/dist/src/cli/coverage.js +343 -0
  61. package/dist/src/cli/coverage.js.map +1 -0
  62. package/dist/src/cli/daemon.js +631 -0
  63. package/dist/src/cli/daemon.js.map +1 -0
  64. package/dist/src/cli/doctor.js +2648 -0
  65. package/dist/src/cli/doctor.js.map +1 -0
  66. package/dist/src/cli/env.js +302 -0
  67. package/dist/src/cli/env.js.map +1 -0
  68. package/dist/src/cli/execute.js +1682 -0
  69. package/dist/src/cli/execute.js.map +1 -0
  70. package/dist/src/cli/exit-codes.js +82 -0
  71. package/dist/src/cli/exit-codes.js.map +1 -0
  72. package/dist/src/cli/feedback.js +205 -0
  73. package/dist/src/cli/feedback.js.map +1 -0
  74. package/dist/src/cli/gate-window.js +294 -0
  75. package/dist/src/cli/gate-window.js.map +1 -0
  76. package/dist/src/cli/gate.js +557 -0
  77. package/dist/src/cli/gate.js.map +1 -0
  78. package/dist/src/cli/git-scope.js +295 -0
  79. package/dist/src/cli/git-scope.js.map +1 -0
  80. package/dist/src/cli/gloss-attach.js +107 -0
  81. package/dist/src/cli/gloss-attach.js.map +1 -0
  82. package/dist/src/cli/gloss-codex-child.js +149 -0
  83. package/dist/src/cli/gloss-codex-child.js.map +1 -0
  84. package/dist/src/cli/gloss-codex.js +255 -0
  85. package/dist/src/cli/gloss-codex.js.map +1 -0
  86. package/dist/src/cli/gloss-options.js +79 -0
  87. package/dist/src/cli/gloss-options.js.map +1 -0
  88. package/dist/src/cli/gloss.js +362 -0
  89. package/dist/src/cli/gloss.js.map +1 -0
  90. package/dist/src/cli/help.js +2217 -0
  91. package/dist/src/cli/help.js.map +1 -0
  92. package/dist/src/cli/hook.js +2743 -0
  93. package/dist/src/cli/hook.js.map +1 -0
  94. package/dist/src/cli/import.js +175 -0
  95. package/dist/src/cli/import.js.map +1 -0
  96. package/dist/src/cli/init.js +336 -0
  97. package/dist/src/cli/init.js.map +1 -0
  98. package/dist/src/cli/instructions.js +262 -0
  99. package/dist/src/cli/instructions.js.map +1 -0
  100. package/dist/src/cli/journal.js +238 -0
  101. package/dist/src/cli/journal.js.map +1 -0
  102. package/dist/src/cli/log-advance.js +749 -0
  103. package/dist/src/cli/log-advance.js.map +1 -0
  104. package/dist/src/cli/log-anchor.js +387 -0
  105. package/dist/src/cli/log-anchor.js.map +1 -0
  106. package/dist/src/cli/log-checkpoint.js +128 -0
  107. package/dist/src/cli/log-checkpoint.js.map +1 -0
  108. package/dist/src/cli/log-sync.js +849 -0
  109. package/dist/src/cli/log-sync.js.map +1 -0
  110. package/dist/src/cli/log-verbs.js +354 -0
  111. package/dist/src/cli/log-verbs.js.map +1 -0
  112. package/dist/src/cli/long-help.js +148 -0
  113. package/dist/src/cli/long-help.js.map +1 -0
  114. package/dist/src/cli/main.js +1056 -0
  115. package/dist/src/cli/main.js.map +1 -0
  116. package/dist/src/cli/mcp.js +306 -0
  117. package/dist/src/cli/mcp.js.map +1 -0
  118. package/dist/src/cli/paths.js +79 -0
  119. package/dist/src/cli/paths.js.map +1 -0
  120. package/dist/src/cli/payload.js +253 -0
  121. package/dist/src/cli/payload.js.map +1 -0
  122. package/dist/src/cli/policy.js +229 -0
  123. package/dist/src/cli/policy.js.map +1 -0
  124. package/dist/src/cli/preflight.js +888 -0
  125. package/dist/src/cli/preflight.js.map +1 -0
  126. package/dist/src/cli/progress.js +112 -0
  127. package/dist/src/cli/progress.js.map +1 -0
  128. package/dist/src/cli/prompt.js +312 -0
  129. package/dist/src/cli/prompt.js.map +1 -0
  130. package/dist/src/cli/records.js +66 -0
  131. package/dist/src/cli/records.js.map +1 -0
  132. package/dist/src/cli/render.js +132 -0
  133. package/dist/src/cli/render.js.map +1 -0
  134. package/dist/src/cli/sandbox.js +150 -0
  135. package/dist/src/cli/sandbox.js.map +1 -0
  136. package/dist/src/cli/scaffold.js +137 -0
  137. package/dist/src/cli/scaffold.js.map +1 -0
  138. package/dist/src/cli/setup-adapter.js +475 -0
  139. package/dist/src/cli/setup-adapter.js.map +1 -0
  140. package/dist/src/cli/setup-channel.js +635 -0
  141. package/dist/src/cli/setup-channel.js.map +1 -0
  142. package/dist/src/cli/setup-checkpoint.js +196 -0
  143. package/dist/src/cli/setup-checkpoint.js.map +1 -0
  144. package/dist/src/cli/setup-common.js +376 -0
  145. package/dist/src/cli/setup-common.js.map +1 -0
  146. package/dist/src/cli/setup-flow.js +476 -0
  147. package/dist/src/cli/setup-flow.js.map +1 -0
  148. package/dist/src/cli/setup-service.js +308 -0
  149. package/dist/src/cli/setup-service.js.map +1 -0
  150. package/dist/src/cli/setup.js +473 -0
  151. package/dist/src/cli/setup.js.map +1 -0
  152. package/dist/src/cli/style.js +469 -0
  153. package/dist/src/cli/style.js.map +1 -0
  154. package/dist/src/cli/token.js +274 -0
  155. package/dist/src/cli/token.js.map +1 -0
  156. package/dist/src/cli/up.js +847 -0
  157. package/dist/src/cli/up.js.map +1 -0
  158. package/dist/src/cli/usage.js +91 -0
  159. package/dist/src/cli/usage.js.map +1 -0
  160. package/dist/src/cli/values.js +189 -0
  161. package/dist/src/cli/values.js.map +1 -0
  162. package/dist/src/cli/vault.js +362 -0
  163. package/dist/src/cli/vault.js.map +1 -0
  164. package/dist/src/cli/verb-registry.js +2173 -0
  165. package/dist/src/cli/verb-registry.js.map +1 -0
  166. package/dist/src/cli/wordmark.js +52 -0
  167. package/dist/src/cli/wordmark.js.map +1 -0
  168. package/dist/src/core/advance-cycle.js +200 -0
  169. package/dist/src/core/advance-cycle.js.map +1 -0
  170. package/dist/src/core/agents-md.js +747 -0
  171. package/dist/src/core/agents-md.js.map +1 -0
  172. package/dist/src/core/attest.js +577 -0
  173. package/dist/src/core/attest.js.map +1 -0
  174. package/dist/src/core/audit.js +882 -0
  175. package/dist/src/core/audit.js.map +1 -0
  176. package/dist/src/core/budgets.js +449 -0
  177. package/dist/src/core/budgets.js.map +1 -0
  178. package/dist/src/core/checkpoint.js +738 -0
  179. package/dist/src/core/checkpoint.js.map +1 -0
  180. package/dist/src/core/child-env.js +86 -0
  181. package/dist/src/core/child-env.js.map +1 -0
  182. package/dist/src/core/clock.js +43 -0
  183. package/dist/src/core/clock.js.map +1 -0
  184. package/dist/src/core/command-class.js +2321 -0
  185. package/dist/src/core/command-class.js.map +1 -0
  186. package/dist/src/core/coverage-sources/adapter.js +71 -0
  187. package/dist/src/core/coverage-sources/adapter.js.map +1 -0
  188. package/dist/src/core/coverage-sources/gh.js +136 -0
  189. package/dist/src/core/coverage-sources/gh.js.map +1 -0
  190. package/dist/src/core/coverage-sources/git.js +269 -0
  191. package/dist/src/core/coverage-sources/git.js.map +1 -0
  192. package/dist/src/core/coverage.js +337 -0
  193. package/dist/src/core/coverage.js.map +1 -0
  194. package/dist/src/core/credential-spec.js +23 -0
  195. package/dist/src/core/credential-spec.js.map +1 -0
  196. package/dist/src/core/dark-session.js +714 -0
  197. package/dist/src/core/dark-session.js.map +1 -0
  198. package/dist/src/core/decision-refusal.js +265 -0
  199. package/dist/src/core/decision-refusal.js.map +1 -0
  200. package/dist/src/core/env-file.js +837 -0
  201. package/dist/src/core/env-file.js.map +1 -0
  202. package/dist/src/core/execute.js +1233 -0
  203. package/dist/src/core/execute.js.map +1 -0
  204. package/dist/src/core/frontmatter.js +100 -0
  205. package/dist/src/core/frontmatter.js.map +1 -0
  206. package/dist/src/core/gate-window.js +506 -0
  207. package/dist/src/core/gate-window.js.map +1 -0
  208. package/dist/src/core/gate.js +2947 -0
  209. package/dist/src/core/gate.js.map +1 -0
  210. package/dist/src/core/git-run.js +93 -0
  211. package/dist/src/core/git-run.js.map +1 -0
  212. package/dist/src/core/harness-version.js +210 -0
  213. package/dist/src/core/harness-version.js.map +1 -0
  214. package/dist/src/core/harness-wait.js +58 -0
  215. package/dist/src/core/harness-wait.js.map +1 -0
  216. package/dist/src/core/head-retry.js +121 -0
  217. package/dist/src/core/head-retry.js.map +1 -0
  218. package/dist/src/core/instance.js +319 -0
  219. package/dist/src/core/instance.js.map +1 -0
  220. package/dist/src/core/intake-limits.js +350 -0
  221. package/dist/src/core/intake-limits.js.map +1 -0
  222. package/dist/src/core/jcs.js +132 -0
  223. package/dist/src/core/jcs.js.map +1 -0
  224. package/dist/src/core/journal.js +200 -0
  225. package/dist/src/core/journal.js.map +1 -0
  226. package/dist/src/core/live-draw.js +703 -0
  227. package/dist/src/core/live-draw.js.map +1 -0
  228. package/dist/src/core/log-reconcile.js +136 -0
  229. package/dist/src/core/log-reconcile.js.map +1 -0
  230. package/dist/src/core/log.js +546 -0
  231. package/dist/src/core/log.js.map +1 -0
  232. package/dist/src/core/loop.js +476 -0
  233. package/dist/src/core/loop.js.map +1 -0
  234. package/dist/src/core/md-fence.js +74 -0
  235. package/dist/src/core/md-fence.js.map +1 -0
  236. package/dist/src/core/money.js +195 -0
  237. package/dist/src/core/money.js.map +1 -0
  238. package/dist/src/core/payload-census.js +146 -0
  239. package/dist/src/core/payload-census.js.map +1 -0
  240. package/dist/src/core/payload-store.js +340 -0
  241. package/dist/src/core/payload-store.js.map +1 -0
  242. package/dist/src/core/payload.js +80 -0
  243. package/dist/src/core/payload.js.map +1 -0
  244. package/dist/src/core/policy-diff.js +565 -0
  245. package/dist/src/core/policy-diff.js.map +1 -0
  246. package/dist/src/core/policy-expectations.js +394 -0
  247. package/dist/src/core/policy-expectations.js.map +1 -0
  248. package/dist/src/core/policy-explain.js +230 -0
  249. package/dist/src/core/policy-explain.js.map +1 -0
  250. package/dist/src/core/policy-load.js +524 -0
  251. package/dist/src/core/policy-load.js.map +1 -0
  252. package/dist/src/core/policy-match.js +467 -0
  253. package/dist/src/core/policy-match.js.map +1 -0
  254. package/dist/src/core/policy-proposal.js +458 -0
  255. package/dist/src/core/policy-proposal.js.map +1 -0
  256. package/dist/src/core/prompt-layout.js +422 -0
  257. package/dist/src/core/prompt-layout.js.map +1 -0
  258. package/dist/src/core/protected-path-guard.js +1087 -0
  259. package/dist/src/core/protected-path-guard.js.map +1 -0
  260. package/dist/src/core/registration.js +39 -0
  261. package/dist/src/core/registration.js.map +1 -0
  262. package/dist/src/core/reindex.js +336 -0
  263. package/dist/src/core/reindex.js.map +1 -0
  264. package/dist/src/core/sampler.js +388 -0
  265. package/dist/src/core/sampler.js.map +1 -0
  266. package/dist/src/core/sandbox.js +424 -0
  267. package/dist/src/core/sandbox.js.map +1 -0
  268. package/dist/src/core/seal.js +290 -0
  269. package/dist/src/core/seal.js.map +1 -0
  270. package/dist/src/core/state.js +1009 -0
  271. package/dist/src/core/state.js.map +1 -0
  272. package/dist/src/core/task-file.js +464 -0
  273. package/dist/src/core/task-file.js.map +1 -0
  274. package/dist/src/core/telegram-config.js +114 -0
  275. package/dist/src/core/telegram-config.js.map +1 -0
  276. package/dist/src/core/token.js +578 -0
  277. package/dist/src/core/token.js.map +1 -0
  278. package/dist/src/core/validate.js +0 -0
  279. package/dist/src/core/validate.js.map +1 -0
  280. package/dist/src/core/values.js +153 -0
  281. package/dist/src/core/values.js.map +1 -0
  282. package/dist/src/core/vault.js +612 -0
  283. package/dist/src/core/vault.js.map +1 -0
  284. package/dist/src/core/verified-snapshot.js +506 -0
  285. package/dist/src/core/verified-snapshot.js.map +1 -0
  286. package/dist/src/core/verify.js +549 -0
  287. package/dist/src/core/verify.js.map +1 -0
  288. package/dist/src/core/version.js +9 -0
  289. package/dist/src/core/version.js.map +1 -0
  290. package/dist/src/core/wysiwys.js +728 -0
  291. package/dist/src/core/wysiwys.js.map +1 -0
  292. package/dist/src/daemon/advance-child.js +78 -0
  293. package/dist/src/daemon/advance-child.js.map +1 -0
  294. package/dist/src/daemon/advance.js +849 -0
  295. package/dist/src/daemon/advance.js.map +1 -0
  296. package/dist/src/daemon/audit.js +90 -0
  297. package/dist/src/daemon/audit.js.map +1 -0
  298. package/dist/src/daemon/daemon.js +1988 -0
  299. package/dist/src/daemon/daemon.js.map +1 -0
  300. package/dist/src/daemon/dark-session.js +119 -0
  301. package/dist/src/daemon/dark-session.js.map +1 -0
  302. package/dist/src/daemon/draw-child.js +132 -0
  303. package/dist/src/daemon/draw-child.js.map +1 -0
  304. package/dist/src/daemon/draw.js +458 -0
  305. package/dist/src/daemon/draw.js.map +1 -0
  306. package/dist/src/daemon/git-evidence.js +345 -0
  307. package/dist/src/daemon/git-evidence.js.map +1 -0
  308. package/dist/src/daemon/projection.js +233 -0
  309. package/dist/src/daemon/projection.js.map +1 -0
  310. package/dist/src/daemon/prune.js +376 -0
  311. package/dist/src/daemon/prune.js.map +1 -0
  312. package/dist/src/mcp/http.js +343 -0
  313. package/dist/src/mcp/http.js.map +1 -0
  314. package/dist/src/mcp/server.js +594 -0
  315. package/dist/src/mcp/server.js.map +1 -0
  316. package/docs/cli-reference.md +5363 -0
  317. package/package.json +43 -4
  318. package/schema/.gitkeep +0 -0
  319. package/schema/LICENSE +117 -0
  320. package/schema/envelope.schema.json +137 -0
  321. package/schema/event.schema.json +1810 -0
  322. package/schema/fixtures/envelope/invalid/action-missing-idempotency-key.json +15 -0
  323. package/schema/fixtures/envelope/invalid/action-unknown-class-format.json +14 -0
  324. package/schema/fixtures/envelope/invalid/confidence-out-of-range.json +11 -0
  325. package/schema/fixtures/envelope/invalid/est-cost-bare-number.json +14 -0
  326. package/schema/fixtures/envelope/invalid/est-cost-noncanonical-string.json +14 -0
  327. package/schema/fixtures/envelope/invalid/malformed-assignee.json +10 -0
  328. package/schema/fixtures/envelope/invalid/malformed-created-by.json +7 -0
  329. package/schema/fixtures/envelope/invalid/malformed-max-latency.json +11 -0
  330. package/schema/fixtures/envelope/invalid/malformed-payload-hash.json +14 -0
  331. package/schema/fixtures/envelope/invalid/max-cost-bare-number.json +11 -0
  332. package/schema/fixtures/envelope/invalid/missing-origin.json +3 -0
  333. package/schema/fixtures/envelope/invalid/negative-est-cost.json +14 -0
  334. package/schema/fixtures/envelope/invalid/unknown-state.json +7 -0
  335. package/schema/fixtures/envelope/invalid/unknown-top-level-field.json +8 -0
  336. package/schema/fixtures/envelope/valid/action-payload-hash.json +17 -0
  337. package/schema/fixtures/envelope/valid/actions-without-budget.json +18 -0
  338. package/schema/fixtures/envelope/valid/canonical.json +25 -0
  339. package/schema/fixtures/envelope/valid/minimal.json +7 -0
  340. package/schema/fixtures/envelope/valid/multi-action-executed.json +30 -0
  341. package/schema/fixtures/envelope/valid/record-write-stage.json +22 -0
  342. package/schema/fixtures/event/invalid/approval-granted-agent-actor.json +15 -0
  343. package/schema/fixtures/event/invalid/approval-granted-empty-batch-delivery-id.json +17 -0
  344. package/schema/fixtures/event/invalid/approval-granted-fifth-reaction.json +16 -0
  345. package/schema/fixtures/event/invalid/approval-granted-missing-actor.json +14 -0
  346. package/schema/fixtures/event/invalid/approval-requested-missing-action-key.json +14 -0
  347. package/schema/fixtures/event/invalid/approval-withdrawn-agent-policy-drift.json +15 -0
  348. package/schema/fixtures/event/invalid/approval-withdrawn-missing-reason.json +15 -0
  349. package/schema/fixtures/event/invalid/approval-withdrawn-system-actor.json +15 -0
  350. package/schema/fixtures/event/invalid/audit-decision-refused-human-actor.json +17 -0
  351. package/schema/fixtures/event/invalid/audit-decision-refused-missing-code.json +16 -0
  352. package/schema/fixtures/event/invalid/audit-reviewed-agent-actor.json +15 -0
  353. package/schema/fixtures/event/invalid/audit-reviewed-loved-no-note.json +16 -0
  354. package/schema/fixtures/event/invalid/audit-reviewed-system-actor.json +15 -0
  355. package/schema/fixtures/event/invalid/bad-actor-prefix.json +15 -0
  356. package/schema/fixtures/event/invalid/est-cost-bare-number.json +17 -0
  357. package/schema/fixtures/event/invalid/execution-completed-fabricated-exit-code.json +16 -0
  358. package/schema/fixtures/event/invalid/execution-completed-provider-ref-empty-id.json +18 -0
  359. package/schema/fixtures/event/invalid/execution-completed-provider-ref-extra-field.json +19 -0
  360. package/schema/fixtures/event/invalid/execution-completed-provider-ref-id-not-string.json +18 -0
  361. package/schema/fixtures/event/invalid/execution-completed-provider-ref-missing-adapter.json +17 -0
  362. package/schema/fixtures/event/invalid/execution-failed-open-reported-by.json +16 -0
  363. package/schema/fixtures/event/invalid/execution-indeterminate-open-reason.json +14 -0
  364. package/schema/fixtures/event/invalid/execution-reconciled-agent-actor.json +17 -0
  365. package/schema/fixtures/event/invalid/execution-started-negative-env-stripped.json +16 -0
  366. package/schema/fixtures/event/invalid/gate-bypassed-missing-opened-seq.json +15 -0
  367. package/schema/fixtures/event/invalid/gate-closed-non-integer-opened-seq.json +13 -0
  368. package/schema/fixtures/event/invalid/gate-opened-agent-actor.json +16 -0
  369. package/schema/fixtures/event/invalid/gate-organ-attested-absolute-path.json +14 -0
  370. package/schema/fixtures/event/invalid/gate-organ-attested-agent-actor.json +14 -0
  371. package/schema/fixtures/event/invalid/gate-organ-attested-missing-organ-path.json +13 -0
  372. package/schema/fixtures/event/invalid/harness-unknown-kind.json +18 -0
  373. package/schema/fixtures/event/invalid/harness-version-multiline.json +16 -0
  374. package/schema/fixtures/event/invalid/log-checkpoint-agent-actor.json +17 -0
  375. package/schema/fixtures/event/invalid/log-checkpoint-missing-signature.json +16 -0
  376. package/schema/fixtures/event/invalid/log-checkpoint-short-signed-hash.json +17 -0
  377. package/schema/fixtures/event/invalid/log-checkpoint-unknown-signature-alg.json +17 -0
  378. package/schema/fixtures/event/invalid/malformed-ts.json +15 -0
  379. package/schema/fixtures/event/invalid/missing-alg.json +14 -0
  380. package/schema/fixtures/event/invalid/missing-hash.json +14 -0
  381. package/schema/fixtures/event/invalid/non-integer-seq.json +15 -0
  382. package/schema/fixtures/event/invalid/payload-pruned-human-actor.json +14 -0
  383. package/schema/fixtures/event/invalid/payload-pruned-missing-hash.json +14 -0
  384. package/schema/fixtures/event/invalid/policy-declined-agent-actor.json +15 -0
  385. package/schema/fixtures/event/invalid/policy-proposed-missing-diff.json +19 -0
  386. package/schema/fixtures/event/invalid/policy-proposed-system-actor.json +26 -0
  387. package/schema/fixtures/event/invalid/short-hash.json +15 -0
  388. package/schema/fixtures/event/invalid/unknown-alg.json +15 -0
  389. package/schema/fixtures/event/invalid/unknown-event-type.json +15 -0
  390. package/schema/fixtures/event/invalid/unknown-top-level-field.json +16 -0
  391. package/schema/fixtures/event/valid/approval-expired.json +15 -0
  392. package/schema/fixtures/event/valid/approval-granted-batch.json +19 -0
  393. package/schema/fixtures/event/valid/approval-granted-reaction.json +16 -0
  394. package/schema/fixtures/event/valid/approval-granted.json +15 -0
  395. package/schema/fixtures/event/valid/approval-rejected.json +15 -0
  396. package/schema/fixtures/event/valid/approval-requested.json +19 -0
  397. package/schema/fixtures/event/valid/approval-revoked.json +15 -0
  398. package/schema/fixtures/event/valid/approval-withdrawn-policy-drift.json +17 -0
  399. package/schema/fixtures/event/valid/approval-withdrawn.json +16 -0
  400. package/schema/fixtures/event/valid/audit-decision-refused.json +20 -0
  401. package/schema/fixtures/event/valid/audit-reviewed-reaction.json +17 -0
  402. package/schema/fixtures/event/valid/audit-reviewed.json +15 -0
  403. package/schema/fixtures/event/valid/audit-sampled.json +14 -0
  404. package/schema/fixtures/event/valid/budget-exceeded.json +21 -0
  405. package/schema/fixtures/event/valid/envelope-drift.json +16 -0
  406. package/schema/fixtures/event/valid/execution-completed-harness-report.json +16 -0
  407. package/schema/fixtures/event/valid/execution-completed-provider-ref.json +18 -0
  408. package/schema/fixtures/event/valid/execution-completed.json +15 -0
  409. package/schema/fixtures/event/valid/execution-failed-harness-report.json +16 -0
  410. package/schema/fixtures/event/valid/execution-failed.json +15 -0
  411. package/schema/fixtures/event/valid/execution-indeterminate.json +15 -0
  412. package/schema/fixtures/event/valid/execution-reconciled.json +17 -0
  413. package/schema/fixtures/event/valid/execution-started-env-stripped.json +17 -0
  414. package/schema/fixtures/event/valid/execution-started.json +14 -0
  415. package/schema/fixtures/event/valid/gate-bypassed-harness-version.json +18 -0
  416. package/schema/fixtures/event/valid/gate-bypassed.json +19 -0
  417. package/schema/fixtures/event/valid/gate-closed.json +14 -0
  418. package/schema/fixtures/event/valid/gate-opened.json +16 -0
  419. package/schema/fixtures/event/valid/gate-organ-attested.json +14 -0
  420. package/schema/fixtures/event/valid/genesis-null-prev.json +14 -0
  421. package/schema/fixtures/event/valid/log-checkpoint.json +17 -0
  422. package/schema/fixtures/event/valid/payload-pruned-orphan.json +13 -0
  423. package/schema/fixtures/event/valid/payload-pruned.json +17 -0
  424. package/schema/fixtures/event/valid/policy-declined.json +16 -0
  425. package/schema/fixtures/event/valid/policy-proposed.json +35 -0
  426. package/schema/fixtures/event/valid/policy-updated.json +14 -0
  427. package/schema/fixtures/event/valid/reconciliation-required.json +18 -0
  428. package/schema/fixtures/event/valid/reconciliation-satisfied.json +17 -0
  429. package/schema/fixtures/event/valid/route-accepted.json +15 -0
  430. package/schema/fixtures/event/valid/route-proposed.json +16 -0
  431. package/schema/fixtures/event/valid/spec-example.json +15 -0
  432. package/schema/fixtures/event/valid/task-registered-harness-version.json +23 -0
  433. package/schema/fixtures/event/valid/task-registered.json +14 -0
  434. package/schema/fixtures/hash/known-answer-pre-121.json +74 -0
  435. package/schema/fixtures/hash/known-answer.json +74 -0
  436. package/schema/fixtures/policy/invalid/bad-approval-ttl.json +7 -0
  437. package/schema/fixtures/policy/invalid/bad-web-port.json +4 -0
  438. package/schema/fixtures/policy/invalid/checkpoint-key-not-base64.json +6 -0
  439. package/schema/fixtures/policy/invalid/class-rule-missing-autonomy.json +9 -0
  440. package/schema/fixtures/policy/invalid/empty-class-key.json +6 -0
  441. package/schema/fixtures/policy/invalid/live-rate-on-human-only.json +7 -0
  442. package/schema/fixtures/policy/invalid/malformed-class-key.json +6 -0
  443. package/schema/fixtures/policy/invalid/missing-version.json +8 -0
  444. package/schema/fixtures/policy/invalid/negative-limit.json +9 -0
  445. package/schema/fixtures/policy/invalid/non-numeric-limit.json +9 -0
  446. package/schema/fixtures/policy/invalid/non-positive-max-pending.json +9 -0
  447. package/schema/fixtures/policy/invalid/on-expiry-grant.json +8 -0
  448. package/schema/fixtures/policy/invalid/payload-retention-bare-number.json +4 -0
  449. package/schema/fixtures/policy/invalid/payload-retention-compound.json +4 -0
  450. package/schema/fixtures/policy/invalid/payload-retention-fractional.json +4 -0
  451. package/schema/fixtures/policy/invalid/payload-retention-zero.json +4 -0
  452. package/schema/fixtures/policy/invalid/protected-paths-escape.json +4 -0
  453. package/schema/fixtures/policy/invalid/protected-paths-glob.json +4 -0
  454. package/schema/fixtures/policy/invalid/retro-rate-on-human-only.json +7 -0
  455. package/schema/fixtures/policy/invalid/retro-rate-on-manual.json +7 -0
  456. package/schema/fixtures/policy/invalid/retro-rate-zero.json +7 -0
  457. package/schema/fixtures/policy/invalid/sample-rate-too-high.json +5 -0
  458. package/schema/fixtures/policy/invalid/sampling-secret-env-empty.json +7 -0
  459. package/schema/fixtures/policy/invalid/sampling-secret-env-not-string.json +6 -0
  460. package/schema/fixtures/policy/invalid/skew-tolerance-compound.json +6 -0
  461. package/schema/fixtures/policy/invalid/unknown-autonomy.json +7 -0
  462. package/schema/fixtures/policy/invalid/unknown-class-rule-key.json +6 -0
  463. package/schema/fixtures/policy/invalid/unknown-top-level-key.json +7 -0
  464. package/schema/fixtures/policy/invalid/vault-passphrase-env-empty.json +6 -0
  465. package/schema/fixtures/policy/invalid/vault-passphrase-literal.json +6 -0
  466. package/schema/fixtures/policy/invalid/version-not-string.json +4 -0
  467. package/schema/fixtures/policy/valid/canonical.json +47 -0
  468. package/schema/fixtures/policy/valid/checkpoint-keys.json +18 -0
  469. package/schema/fixtures/policy/valid/class-approvers-limits.json +25 -0
  470. package/schema/fixtures/policy/valid/class-retro-rate.json +17 -0
  471. package/schema/fixtures/policy/valid/global-budgets.json +19 -0
  472. package/schema/fixtures/policy/valid/human-only.json +9 -0
  473. package/schema/fixtures/policy/valid/minimal.json +6 -0
  474. package/schema/fixtures/policy/valid/protected-paths.json +10 -0
  475. package/schema/fixtures/policy/valid/record-namespace.json +13 -0
  476. package/schema/fixtures/policy/valid/request-volume-limits.json +26 -0
  477. package/schema/fixtures/policy/valid/retention-and-sampling-secret.json +16 -0
  478. package/schema/fixtures/policy/valid/skew-tolerance.json +15 -0
  479. package/schema/fixtures/policy/valid/vault-passphrase-env.json +14 -0
  480. package/schema/fixtures/policy/valid/wildcards.json +15 -0
  481. package/schema/fixtures/policy-md/invalid/alias-bomb.md +15 -0
  482. package/schema/fixtures/policy-md/invalid/no-fence.md +7 -0
  483. package/schema/fixtures/policy-md/invalid/protected-route-not-a-subclass.md +16 -0
  484. package/schema/fixtures/policy-md/invalid/schema-invalid-autonomy.md +16 -0
  485. package/schema/fixtures/policy-md/invalid/schema-invalid-read-proof.md +17 -0
  486. package/schema/fixtures/policy-md/invalid/two-fences.md +19 -0
  487. package/schema/fixtures/policy-md/invalid/unclosed-fence.md +11 -0
  488. package/schema/fixtures/policy-md/invalid/wrong-info-string.md +11 -0
  489. package/schema/fixtures/policy-md/invalid/yaml-syntax-error.md +13 -0
  490. package/schema/fixtures/policy-md/precedence/both/APPROVAL.md +7 -0
  491. package/schema/fixtures/policy-md/precedence/both/APPROVALS.md +7 -0
  492. package/schema/fixtures/policy-md/precedence/fallback-only/APPROVALS.md +7 -0
  493. package/schema/fixtures/policy-md/valid/canonical.md +50 -0
  494. package/schema/fixtures/policy-md/valid/daemon-read-proof.md +18 -0
  495. package/schema/fixtures/policy-md/valid/minimal.md +3 -0
  496. package/schema/fixtures/policy-md/valid/prose-lookalikes.md +54 -0
  497. package/schema/fixtures/policy-md/valid/routed-protected-paths.md +49 -0
  498. package/schema/fixtures/policy-md/valid/with-values.md +79 -0
  499. package/schema/fixtures/sample-record/invalid/bad-date-time.json +4 -0
  500. package/schema/fixtures/sample-record/invalid/missing-required-field.json +3 -0
  501. package/schema/fixtures/sample-record/invalid/unknown-top-level-field.json +5 -0
  502. package/schema/fixtures/sample-record/invalid/wrong-type.json +4 -0
  503. package/schema/fixtures/sample-record/valid/minimal.json +4 -0
  504. package/schema/fixtures/sample-record/valid/with-note.json +5 -0
  505. package/schema/fixtures/values/invalid/class-shaped.json +9 -0
  506. package/schema/fixtures/values/invalid/duplicate-entry.json +4 -0
  507. package/schema/fixtures/values/invalid/non-string-item.json +4 -0
  508. package/schema/fixtures/values/invalid/over-cap.json +26 -0
  509. package/schema/fixtures/values/invalid/unknown-key.json +5 -0
  510. package/schema/fixtures/values/invalid/version-string.json +1 -0
  511. package/schema/fixtures/values/valid/empty-lists.json +7 -0
  512. package/schema/fixtures/values/valid/full.json +20 -0
  513. package/schema/fixtures/values/valid/minimal.json +1 -0
  514. package/schema/fixtures/values-md/invalid/schema-invalid.md +62 -0
  515. package/schema/fixtures/values-md/invalid/two-blocks.md +69 -0
  516. package/schema/fixtures/values-md/invalid/unterminated.md +61 -0
  517. package/schema/fixtures/values-md/invalid/yaml-error.md +63 -0
  518. package/schema/fixtures/values-md/valid/absent.md +50 -0
  519. package/schema/fixtures/values-md/valid/with-values.md +79 -0
  520. package/schema/policy.schema.json +481 -0
  521. package/schema/sample-record.schema.json +26 -0
  522. package/schema/values.schema.json +55 -0
@@ -0,0 +1,161 @@
1
+ /**
2
+ * The vault as a {@link CredentialProvider} (SPEC.md §10.4; APRV-68).
3
+ *
4
+ * `adapters/contract.ts` left one seam open and named the task that would fill
5
+ * it: "No vault. {@link CredentialProvider} is the seam a real vault implements
6
+ * (APRV-68)." This module is that implementation, and it is deliberately thin.
7
+ * Everything about *when* a credential may be read belongs to the contract;
8
+ * everything about *how* the bytes are stored belongs to `core/vault.ts`. What
9
+ * is left here is the translation between the two vocabularies.
10
+ *
11
+ * ## The structural rule
12
+ *
13
+ * A provider built here is only ever handed to
14
+ * {@link executeThroughAdapter} through {@link AdapterExecuteOptions.credentials}.
15
+ * The contract wraps it in a window that closes the instant `act` returns, so
16
+ * every read is inside a verified, consumed, single-use token — which is what
17
+ * SPEC.md §10.4 means by "the credentials only answer to tokens". Three things
18
+ * hold that rule up, and none of them is a convention:
19
+ *
20
+ * 1. `core/vault.ts` exports exactly one function that returns a credential
21
+ * value (`getCredential`), and this module is its only caller in the
22
+ * repository. `tests/vault.test.ts` pins both halves.
23
+ * 2. There is no CLI verb that prints a value. `approval vault` can set, list
24
+ * (names), and remove; it cannot show. See `src/cli/vault.ts`.
25
+ * 3. The contract scans everything an adapter returns for the values the
26
+ * provider handed out and redacts them, so a leak by a careless adapter is
27
+ * caught mechanically rather than reviewed for.
28
+ *
29
+ * ## What this defends, and what it does not
30
+ *
31
+ * Exactly what the vault module's own threat model says, restated because a
32
+ * reader arriving from the adapter side deserves it here too. **Defended:**
33
+ * credentials at rest, and casual reads by an agent that can read files in the
34
+ * working tree — the ciphertext hides the names as well as the values.
35
+ * **Not defended (SPEC.md §11, plainly):** a compromised host, and an agent that
36
+ * can read the passphrase environment variable. Such an agent does not need this
37
+ * provider; it can decrypt the file directly. The vault raises the cost of a
38
+ * leak from reading a file to owning the session, and claims nothing beyond
39
+ * that.
40
+ *
41
+ * Total and synchronous, as {@link CredentialProvider} requires: nothing here
42
+ * throws, nothing blocks on a human, and every failure is one of the three
43
+ * {@link CREDENTIAL_REFUSAL_CODES}.
44
+ */
45
+ import { defaultSourceRunner } from "../core/env-file.js";
46
+ import { getCredential, passphraseFrom, vaultPathFor, } from "../core/vault.js";
47
+ import { passphraseUnderGrant } from "./env-passphrase.js";
48
+ /**
49
+ * How a vault refusal is reported to an adapter.
50
+ *
51
+ * The contract's union has three members and they answer three different
52
+ * questions, so the mapping is by *repair* rather than by severity:
53
+ *
54
+ * - **`credential-unavailable`** — nothing is configured yet. No vault, no such
55
+ * name, no passphrase in the environment. The operator has something to do.
56
+ * - **`credential-refused`** — the vault exists and would not open: a wrong
57
+ * passphrase, an altered file, a format this build does not read, an
58
+ * unreadable path. SPEC.md's phrase for this branch is "a locked vault", and
59
+ * it is distinct because the repair is investigation, not configuration.
60
+ * - **`credential-window-closed`** — never produced here. It is the contract's
61
+ * own verdict about *when* the question was asked, and this module has no way
62
+ * to know that.
63
+ */
64
+ function mapRefusal(code) {
65
+ switch (code) {
66
+ case "vault-absent":
67
+ case "passphrase-unset":
68
+ case "credential-absent":
69
+ case "invalid-name":
70
+ return "credential-unavailable";
71
+ case "vault-io":
72
+ case "vault-malformed":
73
+ case "vault-version-unsupported":
74
+ case "vault-unreadable":
75
+ case "empty-value":
76
+ case "vault-write-failed":
77
+ return "credential-refused";
78
+ }
79
+ }
80
+ /**
81
+ * A provider that answers from the encrypted vault.
82
+ *
83
+ * **Lazy, and cached for the life of the provider.** The vault is not opened
84
+ * until an adapter actually asks for something, so an execution that needs no
85
+ * credential pays no scrypt cost and touches no ciphertext. Once opened, the
86
+ * derived value for a name is remembered, because a provider's life *is* one
87
+ * `act` call: the contract closes it when `act` returns, so the cache cannot
88
+ * outlive the token window it was built for, and the alternative — a fresh
89
+ * ~100 ms key derivation per credential — would put a visible tax on an adapter
90
+ * that needs two.
91
+ *
92
+ * The passphrase is read from the environment on every open rather than
93
+ * captured at construction, so a provider built before the operator exported the
94
+ * variable is not permanently poisoned.
95
+ *
96
+ * **The scoped fallback (APRV-168).** When {@link VaultProviderOptions.envFilePath}
97
+ * is supplied AND the contract has told this provider it is inside a token
98
+ * window, a passphrase absent from the environment is resolved from the
99
+ * instance's `.approval/env` instead. That is the one narrowing of
100
+ * `core/env-file.ts`'s "no verb reads this file" rule, and the whole argument
101
+ * for it lives in `adapters/env-passphrase.ts`. The short form: the authority is
102
+ * the token, and a human tapped Approve for exactly this action. The value is
103
+ * used to derive one key and reaches no environment, no argv, no log, and no
104
+ * message; the cache is dropped when the window closes, so a passphrase resolved
105
+ * under one grant opens nothing under the next.
106
+ *
107
+ * Messages name the environment VARIABLE and the credential NAME, and never a
108
+ * value: an adapter's failure message is one of the strings the contract hands
109
+ * back to a caller, and a diagnostic that quoted the secret would defeat the
110
+ * redaction guard by putting the secret in the one place the guard cannot know
111
+ * to look for it.
112
+ */
113
+ export function vaultCredentialProvider(location, options) {
114
+ const vaultPath = "vaultPath" in location ? location.vaultPath : vaultPathFor(location.logPath);
115
+ const { passphraseEnv } = options;
116
+ const cache = new Map();
117
+ // The live grant, set by the contract when the credential window opens and
118
+ // cleared when it closes. Never read except by the fallback below, and the
119
+ // fallback is unreachable while it is null.
120
+ let live = null;
121
+ return {
122
+ grant(grant) {
123
+ live = grant;
124
+ // A cached credential was derived under the previous window's authority.
125
+ // Dropping the cache with the grant means the next window pays for its
126
+ // own passphrase rather than inheriting one.
127
+ if (grant === null)
128
+ cache.clear();
129
+ },
130
+ get(name) {
131
+ const cached = cache.get(name);
132
+ if (cached !== undefined)
133
+ return { ok: true, value: cached };
134
+ const passphrase = passphraseFrom(passphraseEnv, options.env ?? process.env) ??
135
+ // APRV-168. Only inside a window the contract opened against a token a
136
+ // human's grant minted, and only for the one variable the policy names.
137
+ // The value goes straight into the key derivation below: it is not
138
+ // exported, not cached on its own, and it appears in no message on
139
+ // either branch.
140
+ (options.envFilePath === undefined
141
+ ? null
142
+ : passphraseUnderGrant(live, options.envFilePath, passphraseEnv, options.sourceRunner ?? defaultSourceRunner));
143
+ if (passphrase === null) {
144
+ return {
145
+ ok: false,
146
+ code: "credential-unavailable",
147
+ message: `credential ${JSON.stringify(name)} lives in the vault at ${vaultPath}, and the passphrase variable ${passphraseEnv} is unset or empty in this process${options.envFilePath === undefined
148
+ ? ""
149
+ : `, and it did not resolve from ${options.envFilePath} either`}. The policy names the variable and never the value (SPEC.md §5.2, §10.4); export it in the environment that runs the adapter, or give it a line in the environment source map.`,
150
+ };
151
+ }
152
+ const result = getCredential(vaultPath, passphrase, name);
153
+ if (result.ok) {
154
+ cache.set(name, result.value);
155
+ return { ok: true, value: result.value };
156
+ }
157
+ return { ok: false, code: mapRefusal(result.code), message: result.message };
158
+ },
159
+ };
160
+ }
161
+ //# sourceMappingURL=vault-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault-provider.js","sourceRoot":"","sources":["../../../src/adapters/vault-provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Batching: one human gesture over many requests, without losing audit
3
+ * granularity (SPEC.md §10.3, requirement B7).
4
+ *
5
+ * > Channels MAY present multiple pending requests as a batch and collect one
6
+ * > human gesture over the set, and SHOULD for high-volume `record.*` classes.
7
+ * > The log never batches: each granted or rejected request receives its own
8
+ * > `approval.granted` or `approval.rejected` event carrying the batch's channel
9
+ * > delivery id in its payload, so audit granularity survives ergonomic
10
+ * > grouping. A batch MUST NOT mix `manual` classes with differing
11
+ * > payload-display requirements in a way that hides any full payload behind the
12
+ * > fold of another.
13
+ *
14
+ * Two halves, and this module is both: {@link assembleBatch} enforces the
15
+ * forbidden mix *before* anything is delivered, and {@link recordBatchDecisions}
16
+ * records one gate decision per member afterwards.
17
+ *
18
+ * ## The B7 operationalization — FLAGGED FOR HUMAN REVIEW
19
+ *
20
+ * "Hides any full payload behind the fold of another" is a sentence about
21
+ * rendering, and rendering is the one thing the runtime cannot inspect. So B7 is
22
+ * operationalized here as a property of the *batch material* rather than of the
23
+ * pixels:
24
+ *
25
+ * > A batch MUST carry every member's full payload whole. The forbidden mix is
26
+ * > any member whose `fullPayload` is absent or truncated while the batch
27
+ * > contains more than one distinct payload — because with one payload there is
28
+ * > no "another" to hide behind, and with two or more, a member the channel was
29
+ * > not given in full is a member the approver cannot have read.
30
+ *
31
+ * Concretely, {@link assembleBatch} refuses when the batch holds more than one
32
+ * distinct `payload_hash` **and** any member's `fullPayload` is `null` or
33
+ * `truncated`. A single-payload batch (the same bytes requested twice, or one
34
+ * request) is always assemblable, and a multi-payload batch is assemblable
35
+ * exactly when every member arrives whole.
36
+ *
37
+ * What this deliberately does **not** try to be: a judgment about whether a
38
+ * particular channel's layout actually put payload #2 below the fold. That is a
39
+ * per-channel rendering property, and `channels/conformance.ts` checks the
40
+ * observable half of it (every member's full payload text present in the
41
+ * rendering, delineated from the claimed summary). The interpretation to
42
+ * confirm is the reduction of "differing payload-display requirements" to
43
+ * "distinct payload bytes": it is the reading that makes the rule mechanical,
44
+ * and it is stricter than the spec's letter in one direction (two whole payloads
45
+ * are fine only if both are whole) and silent in another (it says nothing about
46
+ * a channel that renders both whole and then collapses one). A human should
47
+ * confirm this is the intended reading before APRV-23/25/26 build against it.
48
+ */
49
+ import { recordChannelDecision, } from "./contract.js";
50
+ export { BATCH_DELIVERY_ID_FIELD, BATCH_DELIVERY_NOTE_PREFIX, batchDeliveryIdOf, batchNote, } from "./contract.js";
51
+ // ---------------------------------------------------------------------------
52
+ // assembleBatch
53
+ // ---------------------------------------------------------------------------
54
+ /** The one way a batch can be refused (SPEC.md §10.3, B7). */
55
+ export const BATCH_REFUSAL_CODE = "batch-forbidden-mix";
56
+ /**
57
+ * Assemble `requests` into a batch, or refuse the forbidden mix.
58
+ *
59
+ * The returned batch carries every member request **whole** — the same
60
+ * {@link ChannelRequest} objects a channel would receive individually, tags and
61
+ * full payloads included. A channel therefore has everything it needs to render
62
+ * each member in full; if it chooses not to, that is a rendering defect the
63
+ * conformance suite catches, not a gap in the material it was handed.
64
+ *
65
+ * `deliveryId` is left unset: it is assigned by the channel at `notify`.
66
+ */
67
+ export function assembleBatch(requests) {
68
+ const hashes = new Set(requests.map((request) => request.payload_hash.value));
69
+ if (hashes.size > 1) {
70
+ const hidden = requests.filter((request) => {
71
+ const rendering = request.fullPayload.value;
72
+ return rendering === null || rendering.truncated;
73
+ });
74
+ if (hidden.length > 0) {
75
+ const keys = hidden.map((request) => request.action_key.value).join(", ");
76
+ return {
77
+ ok: false,
78
+ code: BATCH_REFUSAL_CODE,
79
+ message: `batch refused: it carries ${hashes.size} distinct payloads and ${hidden.length} member(s) whose full payload is absent or truncated (${keys}). SPEC.md §10.3 forbids a batch that hides any full payload behind the fold of another; a member the channel was never given in full is a member the approver cannot have read, so the set is refused before delivery rather than approved in part.`,
80
+ };
81
+ }
82
+ }
83
+ return { ok: true, batch: { requests } };
84
+ }
85
+ /**
86
+ * Record one gate decision per batch member.
87
+ *
88
+ * **Unit decisions mean unit outcomes.** The log never batches (SPEC.md §10.3),
89
+ * so this is a loop over `decide()` and not a transaction: each member is
90
+ * checked and appended on its own, each carries the batch delivery id in its
91
+ * payload as the first-class `batch_delivery_id` field (amended SPEC.md §10.3,
92
+ * APRV-38), and a member that refuses does **not** stop the rest. That is
93
+ * deliberate and it is the only coherent semantics available — an "all or
94
+ * nothing" batch would have to un-append events the log forbids un-appending,
95
+ * and abandoning the remaining members because the third one expired would
96
+ * discard a human's answer to the other four. So: partial success is a real
97
+ * outcome, `ok` is false when any member refused, and `results` says exactly
98
+ * which ones landed. A caller that wants atomicity does not want a batch.
99
+ *
100
+ * Ordering: members are recorded in the order given. Each append passes the
101
+ * gate's compare-and-append precondition against the head *it* read, so a
102
+ * concurrent writer refuses one member with `append-failed`/`head-moved`
103
+ * rather than corrupting the set.
104
+ */
105
+ export function recordBatchDecisions(logPath, decisions, batchDeliveryId, actorOptions, gateOptions = {}) {
106
+ const results = [];
107
+ for (const decision of decisions) {
108
+ const recorded = recordChannelDecision(logPath, { ...decision, batchDeliveryId }, actorOptions, gateOptions);
109
+ results.push({
110
+ action_key: decision.action_key,
111
+ outcome: recorded.outcome,
112
+ ...(recorded.token === undefined ? {} : { token: recorded.token }),
113
+ });
114
+ }
115
+ return {
116
+ ok: results.every((entry) => entry.outcome.ok),
117
+ results,
118
+ batchDeliveryId,
119
+ };
120
+ }
121
+ //# sourceMappingURL=batch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../../src/channels/batch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAGH,OAAO,EACL,qBAAqB,GAOtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,uBAAuB,EACvB,0BAA0B,EAC1B,iBAAiB,EACjB,SAAS,GAEV,MAAM,eAAe,CAAC;AAEvB,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,8DAA8D;AAC9D,MAAM,CAAC,MAAM,kBAAkB,GAAG,qBAAqB,CAAC;AAUxD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAAC,QAA0B;IACtD,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAE9E,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE;YACzC,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC;YAC5C,OAAO,SAAS,KAAK,IAAI,IAAI,SAAS,CAAC,SAAS,CAAC;QACnD,CAAC,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1E,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,IAAI,EAAE,kBAAkB;gBACxB,OAAO,EAAE,6BAA6B,MAAM,CAAC,IAAI,0BAA0B,MAAM,CAAC,MAAM,yDAAyD,IAAI,sPAAsP;aAC5Y,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC;AAC3C,CAAC;AAsBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAe,EACf,SAA4B,EAC5B,eAA2B,EAC3B,YAAiC,EACjC,WAAW,GAAkB,EAAE;IAE/B,MAAM,OAAO,GAAwB,EAAE,CAAC;IACxC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,qBAAqB,CACpC,OAAO,EACP,EAAE,GAAG,QAAQ,EAAE,eAAe,EAAE,EAChC,YAAY,EACZ,WAAW,CACZ,CAAC;QACF,OAAO,CAAC,IAAI,CAAC;YACX,UAAU,EAAE,QAAQ,CAAC,UAAU;YAC/B,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,GAAG,CAAC,QAAQ,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,CAAC;SACnE,CAAC,CAAC;IACL,CAAC;IACD,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9C,OAAO;QACP,eAAe;KAChB,CAAC;AACJ,CAAC"}