approval-md 0.0.1 → 0.2.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 (722) hide show
  1. package/LICENSE +176 -0
  2. package/NOTICE +5 -0
  3. package/README.md +940 -4
  4. package/SPEC.md +476 -34
  5. package/cli.js +29 -3
  6. package/dist/src/adapters/agentmail.d.ts +426 -0
  7. package/dist/src/adapters/agentmail.js +1200 -0
  8. package/dist/src/adapters/agentmail.js.map +1 -0
  9. package/dist/src/adapters/conformance.d.ts +149 -0
  10. package/dist/src/adapters/conformance.js +461 -0
  11. package/dist/src/adapters/conformance.js.map +1 -0
  12. package/dist/src/adapters/contract.d.ts +628 -0
  13. package/dist/src/adapters/contract.js +1035 -0
  14. package/dist/src/adapters/contract.js.map +1 -0
  15. package/dist/src/adapters/email.d.ts +324 -0
  16. package/dist/src/adapters/email.js +749 -0
  17. package/dist/src/adapters/email.js.map +1 -0
  18. package/dist/src/adapters/env-passphrase.d.ts +93 -0
  19. package/dist/src/adapters/env-passphrase.js +132 -0
  20. package/dist/src/adapters/env-passphrase.js.map +1 -0
  21. package/dist/src/adapters/public.d.ts +11 -0
  22. package/dist/src/adapters/public.js +11 -0
  23. package/dist/src/adapters/public.js.map +1 -0
  24. package/dist/src/adapters/registry.d.ts +59 -0
  25. package/dist/src/adapters/registry.js +77 -0
  26. package/dist/src/adapters/registry.js.map +1 -0
  27. package/dist/src/adapters/smtp.d.ts +213 -0
  28. package/dist/src/adapters/smtp.js +499 -0
  29. package/dist/src/adapters/smtp.js.map +1 -0
  30. package/dist/src/adapters/vault-provider.d.ts +114 -0
  31. package/dist/src/adapters/vault-provider.js +161 -0
  32. package/dist/src/adapters/vault-provider.js.map +1 -0
  33. package/dist/src/adapters/zzz.d.ts +66 -0
  34. package/dist/src/adapters/zzz.js +299 -0
  35. package/dist/src/adapters/zzz.js.map +1 -0
  36. package/dist/src/channels/batch.d.ts +109 -0
  37. package/dist/src/channels/batch.js +121 -0
  38. package/dist/src/channels/batch.js.map +1 -0
  39. package/dist/src/channels/cli.d.ts +193 -0
  40. package/dist/src/channels/cli.js +468 -0
  41. package/dist/src/channels/cli.js.map +1 -0
  42. package/dist/src/channels/conformance.d.ts +92 -0
  43. package/dist/src/channels/conformance.js +445 -0
  44. package/dist/src/channels/conformance.js.map +1 -0
  45. package/dist/src/channels/contract.d.ts +623 -0
  46. package/dist/src/channels/contract.js +494 -0
  47. package/dist/src/channels/contract.js.map +1 -0
  48. package/dist/src/channels/payload-view.d.ts +35 -0
  49. package/dist/src/channels/payload-view.js +43 -0
  50. package/dist/src/channels/payload-view.js.map +1 -0
  51. package/dist/src/channels/render-queue.d.ts +149 -0
  52. package/dist/src/channels/render-queue.js +564 -0
  53. package/dist/src/channels/render-queue.js.map +1 -0
  54. package/dist/src/channels/tagging.d.ts +196 -0
  55. package/dist/src/channels/tagging.js +723 -0
  56. package/dist/src/channels/tagging.js.map +1 -0
  57. package/dist/src/channels/telegram.d.ts +1832 -0
  58. package/dist/src/channels/telegram.js +3190 -0
  59. package/dist/src/channels/telegram.js.map +1 -0
  60. package/dist/src/channels/web.d.ts +341 -0
  61. package/dist/src/channels/web.js +903 -0
  62. package/dist/src/channels/web.js.map +1 -0
  63. package/dist/src/cli/adapter.d.ts +90 -0
  64. package/dist/src/cli/adapter.js +288 -0
  65. package/dist/src/cli/adapter.js.map +1 -0
  66. package/dist/src/cli/amend.d.ts +59 -0
  67. package/dist/src/cli/amend.js +2171 -0
  68. package/dist/src/cli/amend.js.map +1 -0
  69. package/dist/src/cli/args.d.ts +43 -0
  70. package/dist/src/cli/args.js +86 -0
  71. package/dist/src/cli/args.js.map +1 -0
  72. package/dist/src/cli/attest.d.ts +41 -0
  73. package/dist/src/cli/attest.js +307 -0
  74. package/dist/src/cli/attest.js.map +1 -0
  75. package/dist/src/cli/audit-card.d.ts +62 -0
  76. package/dist/src/cli/audit-card.js +201 -0
  77. package/dist/src/cli/audit-card.js.map +1 -0
  78. package/dist/src/cli/audit.d.ts +59 -0
  79. package/dist/src/cli/audit.js +460 -0
  80. package/dist/src/cli/audit.js.map +1 -0
  81. package/dist/src/cli/channel-telegram.d.ts +806 -0
  82. package/dist/src/cli/channel-telegram.js +2063 -0
  83. package/dist/src/cli/channel-telegram.js.map +1 -0
  84. package/dist/src/cli/channel-web.d.ts +131 -0
  85. package/dist/src/cli/channel-web.js +357 -0
  86. package/dist/src/cli/channel-web.js.map +1 -0
  87. package/dist/src/cli/channel.d.ts +71 -0
  88. package/dist/src/cli/channel.js +438 -0
  89. package/dist/src/cli/channel.js.map +1 -0
  90. package/dist/src/cli/checkpoint-tap.d.ts +169 -0
  91. package/dist/src/cli/checkpoint-tap.js +238 -0
  92. package/dist/src/cli/checkpoint-tap.js.map +1 -0
  93. package/dist/src/cli/codex.d.ts +2 -0
  94. package/dist/src/cli/codex.js +172 -0
  95. package/dist/src/cli/codex.js.map +1 -0
  96. package/dist/src/cli/coverage.d.ts +61 -0
  97. package/dist/src/cli/coverage.js +343 -0
  98. package/dist/src/cli/coverage.js.map +1 -0
  99. package/dist/src/cli/daemon.d.ts +120 -0
  100. package/dist/src/cli/daemon.js +631 -0
  101. package/dist/src/cli/daemon.js.map +1 -0
  102. package/dist/src/cli/doctor.d.ts +129 -0
  103. package/dist/src/cli/doctor.js +2762 -0
  104. package/dist/src/cli/doctor.js.map +1 -0
  105. package/dist/src/cli/env.d.ts +65 -0
  106. package/dist/src/cli/env.js +302 -0
  107. package/dist/src/cli/env.js.map +1 -0
  108. package/dist/src/cli/execute.d.ts +202 -0
  109. package/dist/src/cli/execute.js +1682 -0
  110. package/dist/src/cli/execute.js.map +1 -0
  111. package/dist/src/cli/exit-codes.d.ts +73 -0
  112. package/dist/src/cli/exit-codes.js +82 -0
  113. package/dist/src/cli/exit-codes.js.map +1 -0
  114. package/dist/src/cli/feedback.d.ts +60 -0
  115. package/dist/src/cli/feedback.js +205 -0
  116. package/dist/src/cli/feedback.js.map +1 -0
  117. package/dist/src/cli/gate-window.d.ts +40 -0
  118. package/dist/src/cli/gate-window.js +294 -0
  119. package/dist/src/cli/gate-window.js.map +1 -0
  120. package/dist/src/cli/gate.d.ts +68 -0
  121. package/dist/src/cli/gate.js +557 -0
  122. package/dist/src/cli/gate.js.map +1 -0
  123. package/dist/src/cli/git-scope.d.ts +190 -0
  124. package/dist/src/cli/git-scope.js +295 -0
  125. package/dist/src/cli/git-scope.js.map +1 -0
  126. package/dist/src/cli/gloss-attach.d.ts +85 -0
  127. package/dist/src/cli/gloss-attach.js +107 -0
  128. package/dist/src/cli/gloss-attach.js.map +1 -0
  129. package/dist/src/cli/gloss-codex-child.d.ts +9 -0
  130. package/dist/src/cli/gloss-codex-child.js +149 -0
  131. package/dist/src/cli/gloss-codex-child.js.map +1 -0
  132. package/dist/src/cli/gloss-codex.d.ts +24 -0
  133. package/dist/src/cli/gloss-codex.js +255 -0
  134. package/dist/src/cli/gloss-codex.js.map +1 -0
  135. package/dist/src/cli/gloss-options.d.ts +42 -0
  136. package/dist/src/cli/gloss-options.js +79 -0
  137. package/dist/src/cli/gloss-options.js.map +1 -0
  138. package/dist/src/cli/gloss.d.ts +265 -0
  139. package/dist/src/cli/gloss.js +362 -0
  140. package/dist/src/cli/gloss.js.map +1 -0
  141. package/dist/src/cli/help.d.ts +103 -0
  142. package/dist/src/cli/help.js +2339 -0
  143. package/dist/src/cli/help.js.map +1 -0
  144. package/dist/src/cli/hook-codex.d.ts +78 -0
  145. package/dist/src/cli/hook-codex.js +167 -0
  146. package/dist/src/cli/hook-codex.js.map +1 -0
  147. package/dist/src/cli/hook.d.ts +331 -0
  148. package/dist/src/cli/hook.js +2849 -0
  149. package/dist/src/cli/hook.js.map +1 -0
  150. package/dist/src/cli/import.d.ts +35 -0
  151. package/dist/src/cli/import.js +175 -0
  152. package/dist/src/cli/import.js.map +1 -0
  153. package/dist/src/cli/init.d.ts +84 -0
  154. package/dist/src/cli/init.js +336 -0
  155. package/dist/src/cli/init.js.map +1 -0
  156. package/dist/src/cli/instructions.d.ts +23 -0
  157. package/dist/src/cli/instructions.js +262 -0
  158. package/dist/src/cli/instructions.js.map +1 -0
  159. package/dist/src/cli/journal.d.ts +41 -0
  160. package/dist/src/cli/journal.js +238 -0
  161. package/dist/src/cli/journal.js.map +1 -0
  162. package/dist/src/cli/log-advance.d.ts +287 -0
  163. package/dist/src/cli/log-advance.js +840 -0
  164. package/dist/src/cli/log-advance.js.map +1 -0
  165. package/dist/src/cli/log-anchor.d.ts +176 -0
  166. package/dist/src/cli/log-anchor.js +387 -0
  167. package/dist/src/cli/log-anchor.js.map +1 -0
  168. package/dist/src/cli/log-checkpoint.d.ts +22 -0
  169. package/dist/src/cli/log-checkpoint.js +128 -0
  170. package/dist/src/cli/log-checkpoint.js.map +1 -0
  171. package/dist/src/cli/log-sync.d.ts +243 -0
  172. package/dist/src/cli/log-sync.js +849 -0
  173. package/dist/src/cli/log-sync.js.map +1 -0
  174. package/dist/src/cli/log-verbs.d.ts +16 -0
  175. package/dist/src/cli/log-verbs.js +360 -0
  176. package/dist/src/cli/log-verbs.js.map +1 -0
  177. package/dist/src/cli/long-help.d.ts +70 -0
  178. package/dist/src/cli/long-help.js +148 -0
  179. package/dist/src/cli/long-help.js.map +1 -0
  180. package/dist/src/cli/main.d.ts +77 -0
  181. package/dist/src/cli/main.js +1206 -0
  182. package/dist/src/cli/main.js.map +1 -0
  183. package/dist/src/cli/mcp.d.ts +52 -0
  184. package/dist/src/cli/mcp.js +306 -0
  185. package/dist/src/cli/mcp.js.map +1 -0
  186. package/dist/src/cli/paths.d.ts +56 -0
  187. package/dist/src/cli/paths.js +79 -0
  188. package/dist/src/cli/paths.js.map +1 -0
  189. package/dist/src/cli/payload.d.ts +58 -0
  190. package/dist/src/cli/payload.js +253 -0
  191. package/dist/src/cli/payload.js.map +1 -0
  192. package/dist/src/cli/policy.d.ts +43 -0
  193. package/dist/src/cli/policy.js +229 -0
  194. package/dist/src/cli/policy.js.map +1 -0
  195. package/dist/src/cli/preflight.d.ts +363 -0
  196. package/dist/src/cli/preflight.js +1175 -0
  197. package/dist/src/cli/preflight.js.map +1 -0
  198. package/dist/src/cli/progress.d.ts +78 -0
  199. package/dist/src/cli/progress.js +112 -0
  200. package/dist/src/cli/progress.js.map +1 -0
  201. package/dist/src/cli/prompt.d.ts +209 -0
  202. package/dist/src/cli/prompt.js +312 -0
  203. package/dist/src/cli/prompt.js.map +1 -0
  204. package/dist/src/cli/quickstart.d.ts +46 -0
  205. package/dist/src/cli/quickstart.js +297 -0
  206. package/dist/src/cli/quickstart.js.map +1 -0
  207. package/dist/src/cli/records.d.ts +34 -0
  208. package/dist/src/cli/records.js +66 -0
  209. package/dist/src/cli/records.js.map +1 -0
  210. package/dist/src/cli/render.d.ts +22 -0
  211. package/dist/src/cli/render.js +132 -0
  212. package/dist/src/cli/render.js.map +1 -0
  213. package/dist/src/cli/sandbox.d.ts +51 -0
  214. package/dist/src/cli/sandbox.js +150 -0
  215. package/dist/src/cli/sandbox.js.map +1 -0
  216. package/dist/src/cli/scaffold.d.ts +79 -0
  217. package/dist/src/cli/scaffold.js +137 -0
  218. package/dist/src/cli/scaffold.js.map +1 -0
  219. package/dist/src/cli/setup-adapter.d.ts +137 -0
  220. package/dist/src/cli/setup-adapter.js +509 -0
  221. package/dist/src/cli/setup-adapter.js.map +1 -0
  222. package/dist/src/cli/setup-channel.d.ts +117 -0
  223. package/dist/src/cli/setup-channel.js +635 -0
  224. package/dist/src/cli/setup-channel.js.map +1 -0
  225. package/dist/src/cli/setup-checkpoint.d.ts +57 -0
  226. package/dist/src/cli/setup-checkpoint.js +196 -0
  227. package/dist/src/cli/setup-checkpoint.js.map +1 -0
  228. package/dist/src/cli/setup-common.d.ts +275 -0
  229. package/dist/src/cli/setup-common.js +376 -0
  230. package/dist/src/cli/setup-common.js.map +1 -0
  231. package/dist/src/cli/setup-flow.d.ts +287 -0
  232. package/dist/src/cli/setup-flow.js +476 -0
  233. package/dist/src/cli/setup-flow.js.map +1 -0
  234. package/dist/src/cli/setup-service.d.ts +96 -0
  235. package/dist/src/cli/setup-service.js +308 -0
  236. package/dist/src/cli/setup-service.js.map +1 -0
  237. package/dist/src/cli/setup.d.ts +202 -0
  238. package/dist/src/cli/setup.js +473 -0
  239. package/dist/src/cli/setup.js.map +1 -0
  240. package/dist/src/cli/style.d.ts +320 -0
  241. package/dist/src/cli/style.js +469 -0
  242. package/dist/src/cli/style.js.map +1 -0
  243. package/dist/src/cli/token.d.ts +39 -0
  244. package/dist/src/cli/token.js +274 -0
  245. package/dist/src/cli/token.js.map +1 -0
  246. package/dist/src/cli/up.d.ts +155 -0
  247. package/dist/src/cli/up.js +849 -0
  248. package/dist/src/cli/up.js.map +1 -0
  249. package/dist/src/cli/usage.d.ts +37 -0
  250. package/dist/src/cli/usage.js +91 -0
  251. package/dist/src/cli/usage.js.map +1 -0
  252. package/dist/src/cli/values.d.ts +40 -0
  253. package/dist/src/cli/values.js +189 -0
  254. package/dist/src/cli/values.js.map +1 -0
  255. package/dist/src/cli/vault.d.ts +59 -0
  256. package/dist/src/cli/vault.js +362 -0
  257. package/dist/src/cli/vault.js.map +1 -0
  258. package/dist/src/cli/verb-registry.d.ts +76 -0
  259. package/dist/src/cli/verb-registry.js +2341 -0
  260. package/dist/src/cli/verb-registry.js.map +1 -0
  261. package/dist/src/cli/wordmark.d.ts +31 -0
  262. package/dist/src/cli/wordmark.js +52 -0
  263. package/dist/src/cli/wordmark.js.map +1 -0
  264. package/dist/src/codex/doctor.d.ts +13 -0
  265. package/dist/src/codex/doctor.js +41 -0
  266. package/dist/src/codex/doctor.js.map +1 -0
  267. package/dist/src/codex/manifest.d.ts +49 -0
  268. package/dist/src/codex/manifest.js +103 -0
  269. package/dist/src/codex/manifest.js.map +1 -0
  270. package/dist/src/codex/templates.d.ts +41 -0
  271. package/dist/src/codex/templates.js +319 -0
  272. package/dist/src/codex/templates.js.map +1 -0
  273. package/dist/src/codex/trust.d.ts +19 -0
  274. package/dist/src/codex/trust.js +183 -0
  275. package/dist/src/codex/trust.js.map +1 -0
  276. package/dist/src/codex/workspace-plan.d.ts +131 -0
  277. package/dist/src/codex/workspace-plan.js +561 -0
  278. package/dist/src/codex/workspace-plan.js.map +1 -0
  279. package/dist/src/core/actor.d.ts +2 -0
  280. package/dist/src/core/actor.js +5 -0
  281. package/dist/src/core/actor.js.map +1 -0
  282. package/dist/src/core/advance-cycle.d.ts +170 -0
  283. package/dist/src/core/advance-cycle.js +200 -0
  284. package/dist/src/core/advance-cycle.js.map +1 -0
  285. package/dist/src/core/agents-md.d.ts +276 -0
  286. package/dist/src/core/agents-md.js +747 -0
  287. package/dist/src/core/agents-md.js.map +1 -0
  288. package/dist/src/core/apply-patch.d.ts +49 -0
  289. package/dist/src/core/apply-patch.js +266 -0
  290. package/dist/src/core/apply-patch.js.map +1 -0
  291. package/dist/src/core/attest.d.ts +420 -0
  292. package/dist/src/core/attest.js +589 -0
  293. package/dist/src/core/attest.js.map +1 -0
  294. package/dist/src/core/audit.d.ts +492 -0
  295. package/dist/src/core/audit.js +882 -0
  296. package/dist/src/core/audit.js.map +1 -0
  297. package/dist/src/core/budgets.d.ts +238 -0
  298. package/dist/src/core/budgets.js +449 -0
  299. package/dist/src/core/budgets.js.map +1 -0
  300. package/dist/src/core/checkpoint.d.ts +500 -0
  301. package/dist/src/core/checkpoint.js +738 -0
  302. package/dist/src/core/checkpoint.js.map +1 -0
  303. package/dist/src/core/child-env.d.ts +88 -0
  304. package/dist/src/core/child-env.js +86 -0
  305. package/dist/src/core/child-env.js.map +1 -0
  306. package/dist/src/core/clock.d.ts +52 -0
  307. package/dist/src/core/clock.js +43 -0
  308. package/dist/src/core/clock.js.map +1 -0
  309. package/dist/src/core/command-class.d.ts +543 -0
  310. package/dist/src/core/command-class.js +2356 -0
  311. package/dist/src/core/command-class.js.map +1 -0
  312. package/dist/src/core/coverage-sources/adapter.d.ts +40 -0
  313. package/dist/src/core/coverage-sources/adapter.js +71 -0
  314. package/dist/src/core/coverage-sources/adapter.js.map +1 -0
  315. package/dist/src/core/coverage-sources/gh.d.ts +48 -0
  316. package/dist/src/core/coverage-sources/gh.js +136 -0
  317. package/dist/src/core/coverage-sources/gh.js.map +1 -0
  318. package/dist/src/core/coverage-sources/git.d.ts +101 -0
  319. package/dist/src/core/coverage-sources/git.js +269 -0
  320. package/dist/src/core/coverage-sources/git.js.map +1 -0
  321. package/dist/src/core/coverage.d.ts +217 -0
  322. package/dist/src/core/coverage.js +337 -0
  323. package/dist/src/core/coverage.js.map +1 -0
  324. package/dist/src/core/credential-spec.d.ts +72 -0
  325. package/dist/src/core/credential-spec.js +23 -0
  326. package/dist/src/core/credential-spec.js.map +1 -0
  327. package/dist/src/core/dark-session.d.ts +331 -0
  328. package/dist/src/core/dark-session.js +714 -0
  329. package/dist/src/core/dark-session.js.map +1 -0
  330. package/dist/src/core/decision-refusal.d.ts +185 -0
  331. package/dist/src/core/decision-refusal.js +265 -0
  332. package/dist/src/core/decision-refusal.js.map +1 -0
  333. package/dist/src/core/env-file.d.ts +450 -0
  334. package/dist/src/core/env-file.js +837 -0
  335. package/dist/src/core/env-file.js.map +1 -0
  336. package/dist/src/core/execute.d.ts +858 -0
  337. package/dist/src/core/execute.js +1271 -0
  338. package/dist/src/core/execute.js.map +1 -0
  339. package/dist/src/core/frontmatter.d.ts +78 -0
  340. package/dist/src/core/frontmatter.js +100 -0
  341. package/dist/src/core/frontmatter.js.map +1 -0
  342. package/dist/src/core/gate-window.d.ts +312 -0
  343. package/dist/src/core/gate-window.js +506 -0
  344. package/dist/src/core/gate-window.js.map +1 -0
  345. package/dist/src/core/gate.d.ts +1364 -0
  346. package/dist/src/core/gate.js +3002 -0
  347. package/dist/src/core/gate.js.map +1 -0
  348. package/dist/src/core/git-run.d.ts +73 -0
  349. package/dist/src/core/git-run.js +93 -0
  350. package/dist/src/core/git-run.js.map +1 -0
  351. package/dist/src/core/harness-version.d.ts +157 -0
  352. package/dist/src/core/harness-version.js +211 -0
  353. package/dist/src/core/harness-version.js.map +1 -0
  354. package/dist/src/core/harness-wait.d.ts +55 -0
  355. package/dist/src/core/harness-wait.js +58 -0
  356. package/dist/src/core/harness-wait.js.map +1 -0
  357. package/dist/src/core/head-retry.d.ts +107 -0
  358. package/dist/src/core/head-retry.js +121 -0
  359. package/dist/src/core/head-retry.js.map +1 -0
  360. package/dist/src/core/instance.d.ts +253 -0
  361. package/dist/src/core/instance.js +319 -0
  362. package/dist/src/core/instance.js.map +1 -0
  363. package/dist/src/core/intake-limits.d.ts +247 -0
  364. package/dist/src/core/intake-limits.js +350 -0
  365. package/dist/src/core/intake-limits.js.map +1 -0
  366. package/dist/src/core/jcs.d.ts +52 -0
  367. package/dist/src/core/jcs.js +132 -0
  368. package/dist/src/core/jcs.js.map +1 -0
  369. package/dist/src/core/journal.d.ts +144 -0
  370. package/dist/src/core/journal.js +200 -0
  371. package/dist/src/core/journal.js.map +1 -0
  372. package/dist/src/core/live-draw.d.ts +436 -0
  373. package/dist/src/core/live-draw.js +703 -0
  374. package/dist/src/core/live-draw.js.map +1 -0
  375. package/dist/src/core/log-reconcile.d.ts +89 -0
  376. package/dist/src/core/log-reconcile.js +136 -0
  377. package/dist/src/core/log-reconcile.js.map +1 -0
  378. package/dist/src/core/log-subscribe.d.ts +36 -0
  379. package/dist/src/core/log-subscribe.js +162 -0
  380. package/dist/src/core/log-subscribe.js.map +1 -0
  381. package/dist/src/core/log.d.ts +278 -0
  382. package/dist/src/core/log.js +546 -0
  383. package/dist/src/core/log.js.map +1 -0
  384. package/dist/src/core/loop.d.ts +274 -0
  385. package/dist/src/core/loop.js +487 -0
  386. package/dist/src/core/loop.js.map +1 -0
  387. package/dist/src/core/md-fence.d.ts +41 -0
  388. package/dist/src/core/md-fence.js +74 -0
  389. package/dist/src/core/md-fence.js.map +1 -0
  390. package/dist/src/core/money.d.ts +147 -0
  391. package/dist/src/core/money.js +195 -0
  392. package/dist/src/core/money.js.map +1 -0
  393. package/dist/src/core/payload-census.d.ts +74 -0
  394. package/dist/src/core/payload-census.js +146 -0
  395. package/dist/src/core/payload-census.js.map +1 -0
  396. package/dist/src/core/payload-store.d.ts +175 -0
  397. package/dist/src/core/payload-store.js +340 -0
  398. package/dist/src/core/payload-store.js.map +1 -0
  399. package/dist/src/core/payload.d.ts +71 -0
  400. package/dist/src/core/payload.js +80 -0
  401. package/dist/src/core/payload.js.map +1 -0
  402. package/dist/src/core/policy-diff.d.ts +292 -0
  403. package/dist/src/core/policy-diff.js +588 -0
  404. package/dist/src/core/policy-diff.js.map +1 -0
  405. package/dist/src/core/policy-expectations.d.ts +199 -0
  406. package/dist/src/core/policy-expectations.js +394 -0
  407. package/dist/src/core/policy-expectations.js.map +1 -0
  408. package/dist/src/core/policy-explain.d.ts +150 -0
  409. package/dist/src/core/policy-explain.js +258 -0
  410. package/dist/src/core/policy-explain.js.map +1 -0
  411. package/dist/src/core/policy-load.d.ts +527 -0
  412. package/dist/src/core/policy-load.js +536 -0
  413. package/dist/src/core/policy-load.js.map +1 -0
  414. package/dist/src/core/policy-match.d.ts +281 -0
  415. package/dist/src/core/policy-match.js +478 -0
  416. package/dist/src/core/policy-match.js.map +1 -0
  417. package/dist/src/core/policy-proposal.d.ts +265 -0
  418. package/dist/src/core/policy-proposal.js +458 -0
  419. package/dist/src/core/policy-proposal.js.map +1 -0
  420. package/dist/src/core/prompt-layout.d.ts +221 -0
  421. package/dist/src/core/prompt-layout.js +422 -0
  422. package/dist/src/core/prompt-layout.js.map +1 -0
  423. package/dist/src/core/protected-path-guard.d.ts +453 -0
  424. package/dist/src/core/protected-path-guard.js +1566 -0
  425. package/dist/src/core/protected-path-guard.js.map +1 -0
  426. package/dist/src/core/registration.d.ts +25 -0
  427. package/dist/src/core/registration.js +39 -0
  428. package/dist/src/core/registration.js.map +1 -0
  429. package/dist/src/core/reindex.d.ts +99 -0
  430. package/dist/src/core/reindex.js +336 -0
  431. package/dist/src/core/reindex.js.map +1 -0
  432. package/dist/src/core/sampler.d.ts +313 -0
  433. package/dist/src/core/sampler.js +388 -0
  434. package/dist/src/core/sampler.js.map +1 -0
  435. package/dist/src/core/sandbox.d.ts +290 -0
  436. package/dist/src/core/sandbox.js +424 -0
  437. package/dist/src/core/sandbox.js.map +1 -0
  438. package/dist/src/core/seal.d.ts +165 -0
  439. package/dist/src/core/seal.js +290 -0
  440. package/dist/src/core/seal.js.map +1 -0
  441. package/dist/src/core/state.d.ts +505 -0
  442. package/dist/src/core/state.js +1009 -0
  443. package/dist/src/core/state.js.map +1 -0
  444. package/dist/src/core/task-file.d.ts +185 -0
  445. package/dist/src/core/task-file.js +464 -0
  446. package/dist/src/core/task-file.js.map +1 -0
  447. package/dist/src/core/telegram-config.d.ts +93 -0
  448. package/dist/src/core/telegram-config.js +114 -0
  449. package/dist/src/core/telegram-config.js.map +1 -0
  450. package/dist/src/core/token.d.ts +409 -0
  451. package/dist/src/core/token.js +561 -0
  452. package/dist/src/core/token.js.map +1 -0
  453. package/dist/src/core/validate.d.ts +138 -0
  454. package/dist/src/core/validate.js +0 -0
  455. package/dist/src/core/validate.js.map +1 -0
  456. package/dist/src/core/values.d.ts +137 -0
  457. package/dist/src/core/values.js +153 -0
  458. package/dist/src/core/values.js.map +1 -0
  459. package/dist/src/core/vault.d.ts +291 -0
  460. package/dist/src/core/vault.js +612 -0
  461. package/dist/src/core/vault.js.map +1 -0
  462. package/dist/src/core/verified-snapshot.d.ts +204 -0
  463. package/dist/src/core/verified-snapshot.js +506 -0
  464. package/dist/src/core/verified-snapshot.js.map +1 -0
  465. package/dist/src/core/verify.d.ts +336 -0
  466. package/dist/src/core/verify.js +549 -0
  467. package/dist/src/core/verify.js.map +1 -0
  468. package/dist/src/core/version.d.ts +8 -0
  469. package/dist/src/core/version.js +9 -0
  470. package/dist/src/core/version.js.map +1 -0
  471. package/dist/src/core/wysiwys.d.ts +370 -0
  472. package/dist/src/core/wysiwys.js +728 -0
  473. package/dist/src/core/wysiwys.js.map +1 -0
  474. package/dist/src/daemon/advance-child.d.ts +39 -0
  475. package/dist/src/daemon/advance-child.js +78 -0
  476. package/dist/src/daemon/advance-child.js.map +1 -0
  477. package/dist/src/daemon/advance.d.ts +466 -0
  478. package/dist/src/daemon/advance.js +849 -0
  479. package/dist/src/daemon/advance.js.map +1 -0
  480. package/dist/src/daemon/audit.d.ts +87 -0
  481. package/dist/src/daemon/audit.js +90 -0
  482. package/dist/src/daemon/audit.js.map +1 -0
  483. package/dist/src/daemon/daemon.d.ts +1180 -0
  484. package/dist/src/daemon/daemon.js +1988 -0
  485. package/dist/src/daemon/daemon.js.map +1 -0
  486. package/dist/src/daemon/dark-session.d.ts +64 -0
  487. package/dist/src/daemon/dark-session.js +119 -0
  488. package/dist/src/daemon/dark-session.js.map +1 -0
  489. package/dist/src/daemon/draw-child.d.ts +36 -0
  490. package/dist/src/daemon/draw-child.js +132 -0
  491. package/dist/src/daemon/draw-child.js.map +1 -0
  492. package/dist/src/daemon/draw.d.ts +154 -0
  493. package/dist/src/daemon/draw.js +458 -0
  494. package/dist/src/daemon/draw.js.map +1 -0
  495. package/dist/src/daemon/git-evidence.d.ts +173 -0
  496. package/dist/src/daemon/git-evidence.js +345 -0
  497. package/dist/src/daemon/git-evidence.js.map +1 -0
  498. package/dist/src/daemon/projection.d.ts +180 -0
  499. package/dist/src/daemon/projection.js +233 -0
  500. package/dist/src/daemon/projection.js.map +1 -0
  501. package/dist/src/daemon/prune.d.ts +207 -0
  502. package/dist/src/daemon/prune.js +376 -0
  503. package/dist/src/daemon/prune.js.map +1 -0
  504. package/dist/src/mcp/http.d.ts +113 -0
  505. package/dist/src/mcp/http.js +343 -0
  506. package/dist/src/mcp/http.js.map +1 -0
  507. package/dist/src/mcp/server.d.ts +265 -0
  508. package/dist/src/mcp/server.js +602 -0
  509. package/dist/src/mcp/server.js.map +1 -0
  510. package/docs/adapter-api.md +106 -0
  511. package/docs/cli-reference.md +5716 -0
  512. package/docs/codex-enforced-session.md +30 -0
  513. package/package.json +53 -4
  514. package/schema/.gitkeep +0 -0
  515. package/schema/LICENSE +117 -0
  516. package/schema/codex-instance.schema.json +82 -0
  517. package/schema/envelope.schema.json +137 -0
  518. package/schema/event.schema.json +1811 -0
  519. package/schema/fixtures/codex-instance/invalid/unpinned-codex-version.json +40 -0
  520. package/schema/fixtures/codex-instance/valid/canonical.json +40 -0
  521. package/schema/fixtures/envelope/invalid/action-missing-idempotency-key.json +15 -0
  522. package/schema/fixtures/envelope/invalid/action-unknown-class-format.json +14 -0
  523. package/schema/fixtures/envelope/invalid/confidence-out-of-range.json +11 -0
  524. package/schema/fixtures/envelope/invalid/est-cost-bare-number.json +14 -0
  525. package/schema/fixtures/envelope/invalid/est-cost-noncanonical-string.json +14 -0
  526. package/schema/fixtures/envelope/invalid/malformed-assignee.json +10 -0
  527. package/schema/fixtures/envelope/invalid/malformed-created-by.json +7 -0
  528. package/schema/fixtures/envelope/invalid/malformed-max-latency.json +11 -0
  529. package/schema/fixtures/envelope/invalid/malformed-payload-hash.json +14 -0
  530. package/schema/fixtures/envelope/invalid/max-cost-bare-number.json +11 -0
  531. package/schema/fixtures/envelope/invalid/missing-origin.json +3 -0
  532. package/schema/fixtures/envelope/invalid/negative-est-cost.json +14 -0
  533. package/schema/fixtures/envelope/invalid/unknown-state.json +7 -0
  534. package/schema/fixtures/envelope/invalid/unknown-top-level-field.json +8 -0
  535. package/schema/fixtures/envelope/valid/action-payload-hash.json +17 -0
  536. package/schema/fixtures/envelope/valid/actions-without-budget.json +18 -0
  537. package/schema/fixtures/envelope/valid/canonical.json +25 -0
  538. package/schema/fixtures/envelope/valid/minimal.json +7 -0
  539. package/schema/fixtures/envelope/valid/multi-action-executed.json +30 -0
  540. package/schema/fixtures/envelope/valid/record-write-stage.json +22 -0
  541. package/schema/fixtures/event/invalid/approval-granted-agent-actor.json +15 -0
  542. package/schema/fixtures/event/invalid/approval-granted-empty-batch-delivery-id.json +17 -0
  543. package/schema/fixtures/event/invalid/approval-granted-fifth-reaction.json +16 -0
  544. package/schema/fixtures/event/invalid/approval-granted-missing-actor.json +14 -0
  545. package/schema/fixtures/event/invalid/approval-requested-missing-action-key.json +14 -0
  546. package/schema/fixtures/event/invalid/approval-withdrawn-agent-policy-drift.json +15 -0
  547. package/schema/fixtures/event/invalid/approval-withdrawn-missing-reason.json +15 -0
  548. package/schema/fixtures/event/invalid/approval-withdrawn-system-actor.json +15 -0
  549. package/schema/fixtures/event/invalid/audit-decision-refused-human-actor.json +17 -0
  550. package/schema/fixtures/event/invalid/audit-decision-refused-missing-code.json +16 -0
  551. package/schema/fixtures/event/invalid/audit-reviewed-agent-actor.json +15 -0
  552. package/schema/fixtures/event/invalid/audit-reviewed-loved-no-note.json +16 -0
  553. package/schema/fixtures/event/invalid/audit-reviewed-system-actor.json +15 -0
  554. package/schema/fixtures/event/invalid/bad-actor-prefix.json +15 -0
  555. package/schema/fixtures/event/invalid/est-cost-bare-number.json +17 -0
  556. package/schema/fixtures/event/invalid/execution-completed-fabricated-exit-code.json +16 -0
  557. package/schema/fixtures/event/invalid/execution-completed-provider-ref-empty-id.json +18 -0
  558. package/schema/fixtures/event/invalid/execution-completed-provider-ref-extra-field.json +19 -0
  559. package/schema/fixtures/event/invalid/execution-completed-provider-ref-id-not-string.json +18 -0
  560. package/schema/fixtures/event/invalid/execution-completed-provider-ref-missing-adapter.json +17 -0
  561. package/schema/fixtures/event/invalid/execution-failed-open-reported-by.json +16 -0
  562. package/schema/fixtures/event/invalid/execution-indeterminate-open-reason.json +14 -0
  563. package/schema/fixtures/event/invalid/execution-reconciled-agent-actor.json +17 -0
  564. package/schema/fixtures/event/invalid/execution-started-negative-env-stripped.json +16 -0
  565. package/schema/fixtures/event/invalid/gate-bypassed-missing-opened-seq.json +15 -0
  566. package/schema/fixtures/event/invalid/gate-closed-non-integer-opened-seq.json +13 -0
  567. package/schema/fixtures/event/invalid/gate-opened-agent-actor.json +16 -0
  568. package/schema/fixtures/event/invalid/gate-organ-attested-absolute-path.json +14 -0
  569. package/schema/fixtures/event/invalid/gate-organ-attested-agent-actor.json +14 -0
  570. package/schema/fixtures/event/invalid/gate-organ-attested-missing-organ-path.json +13 -0
  571. package/schema/fixtures/event/invalid/harness-unknown-kind.json +18 -0
  572. package/schema/fixtures/event/invalid/harness-version-multiline.json +16 -0
  573. package/schema/fixtures/event/invalid/log-checkpoint-agent-actor.json +17 -0
  574. package/schema/fixtures/event/invalid/log-checkpoint-missing-signature.json +16 -0
  575. package/schema/fixtures/event/invalid/log-checkpoint-short-signed-hash.json +17 -0
  576. package/schema/fixtures/event/invalid/log-checkpoint-unknown-signature-alg.json +17 -0
  577. package/schema/fixtures/event/invalid/malformed-ts.json +15 -0
  578. package/schema/fixtures/event/invalid/missing-alg.json +14 -0
  579. package/schema/fixtures/event/invalid/missing-hash.json +14 -0
  580. package/schema/fixtures/event/invalid/non-integer-seq.json +15 -0
  581. package/schema/fixtures/event/invalid/payload-pruned-human-actor.json +14 -0
  582. package/schema/fixtures/event/invalid/payload-pruned-missing-hash.json +14 -0
  583. package/schema/fixtures/event/invalid/policy-declined-agent-actor.json +15 -0
  584. package/schema/fixtures/event/invalid/policy-proposed-missing-diff.json +19 -0
  585. package/schema/fixtures/event/invalid/policy-proposed-system-actor.json +26 -0
  586. package/schema/fixtures/event/invalid/short-hash.json +15 -0
  587. package/schema/fixtures/event/invalid/unknown-alg.json +15 -0
  588. package/schema/fixtures/event/invalid/unknown-event-type.json +15 -0
  589. package/schema/fixtures/event/invalid/unknown-top-level-field.json +16 -0
  590. package/schema/fixtures/event/valid/approval-expired.json +15 -0
  591. package/schema/fixtures/event/valid/approval-granted-batch.json +19 -0
  592. package/schema/fixtures/event/valid/approval-granted-reaction.json +16 -0
  593. package/schema/fixtures/event/valid/approval-granted.json +15 -0
  594. package/schema/fixtures/event/valid/approval-rejected.json +15 -0
  595. package/schema/fixtures/event/valid/approval-requested.json +19 -0
  596. package/schema/fixtures/event/valid/approval-revoked.json +15 -0
  597. package/schema/fixtures/event/valid/approval-withdrawn-policy-drift.json +17 -0
  598. package/schema/fixtures/event/valid/approval-withdrawn.json +16 -0
  599. package/schema/fixtures/event/valid/audit-decision-refused.json +20 -0
  600. package/schema/fixtures/event/valid/audit-reviewed-reaction.json +17 -0
  601. package/schema/fixtures/event/valid/audit-reviewed.json +15 -0
  602. package/schema/fixtures/event/valid/audit-sampled.json +14 -0
  603. package/schema/fixtures/event/valid/budget-exceeded.json +21 -0
  604. package/schema/fixtures/event/valid/envelope-drift.json +16 -0
  605. package/schema/fixtures/event/valid/execution-completed-harness-report.json +16 -0
  606. package/schema/fixtures/event/valid/execution-completed-provider-ref.json +18 -0
  607. package/schema/fixtures/event/valid/execution-completed.json +15 -0
  608. package/schema/fixtures/event/valid/execution-failed-harness-report.json +16 -0
  609. package/schema/fixtures/event/valid/execution-failed.json +15 -0
  610. package/schema/fixtures/event/valid/execution-indeterminate.json +15 -0
  611. package/schema/fixtures/event/valid/execution-reconciled.json +17 -0
  612. package/schema/fixtures/event/valid/execution-started-env-stripped.json +17 -0
  613. package/schema/fixtures/event/valid/execution-started.json +14 -0
  614. package/schema/fixtures/event/valid/gate-bypassed-harness-version.json +18 -0
  615. package/schema/fixtures/event/valid/gate-bypassed.json +19 -0
  616. package/schema/fixtures/event/valid/gate-closed.json +14 -0
  617. package/schema/fixtures/event/valid/gate-opened.json +16 -0
  618. package/schema/fixtures/event/valid/gate-organ-attested.json +14 -0
  619. package/schema/fixtures/event/valid/genesis-null-prev.json +14 -0
  620. package/schema/fixtures/event/valid/log-checkpoint.json +17 -0
  621. package/schema/fixtures/event/valid/payload-pruned-orphan.json +13 -0
  622. package/schema/fixtures/event/valid/payload-pruned.json +17 -0
  623. package/schema/fixtures/event/valid/policy-declined.json +16 -0
  624. package/schema/fixtures/event/valid/policy-proposed.json +35 -0
  625. package/schema/fixtures/event/valid/policy-updated.json +14 -0
  626. package/schema/fixtures/event/valid/reconciliation-required.json +18 -0
  627. package/schema/fixtures/event/valid/reconciliation-satisfied.json +17 -0
  628. package/schema/fixtures/event/valid/route-accepted.json +15 -0
  629. package/schema/fixtures/event/valid/route-proposed.json +16 -0
  630. package/schema/fixtures/event/valid/spec-example.json +15 -0
  631. package/schema/fixtures/event/valid/task-registered-harness-version.json +23 -0
  632. package/schema/fixtures/event/valid/task-registered.json +14 -0
  633. package/schema/fixtures/hash/known-answer-pre-121.json +74 -0
  634. package/schema/fixtures/hash/known-answer.json +74 -0
  635. package/schema/fixtures/policy/invalid/bad-approval-ttl.json +7 -0
  636. package/schema/fixtures/policy/invalid/bad-web-port.json +4 -0
  637. package/schema/fixtures/policy/invalid/checkpoint-key-not-base64.json +6 -0
  638. package/schema/fixtures/policy/invalid/class-rule-missing-autonomy.json +9 -0
  639. package/schema/fixtures/policy/invalid/empty-class-key.json +6 -0
  640. package/schema/fixtures/policy/invalid/live-rate-on-human-only.json +7 -0
  641. package/schema/fixtures/policy/invalid/malformed-class-key.json +6 -0
  642. package/schema/fixtures/policy/invalid/missing-version.json +8 -0
  643. package/schema/fixtures/policy/invalid/negative-limit.json +9 -0
  644. package/schema/fixtures/policy/invalid/non-numeric-limit.json +9 -0
  645. package/schema/fixtures/policy/invalid/non-positive-max-pending.json +9 -0
  646. package/schema/fixtures/policy/invalid/on-expiry-grant.json +8 -0
  647. package/schema/fixtures/policy/invalid/payload-retention-bare-number.json +4 -0
  648. package/schema/fixtures/policy/invalid/payload-retention-compound.json +4 -0
  649. package/schema/fixtures/policy/invalid/payload-retention-fractional.json +4 -0
  650. package/schema/fixtures/policy/invalid/payload-retention-zero.json +4 -0
  651. package/schema/fixtures/policy/invalid/protected-paths-escape.json +4 -0
  652. package/schema/fixtures/policy/invalid/protected-paths-glob.json +4 -0
  653. package/schema/fixtures/policy/invalid/retro-rate-on-human-only.json +7 -0
  654. package/schema/fixtures/policy/invalid/retro-rate-on-manual.json +7 -0
  655. package/schema/fixtures/policy/invalid/retro-rate-zero.json +7 -0
  656. package/schema/fixtures/policy/invalid/sample-rate-too-high.json +5 -0
  657. package/schema/fixtures/policy/invalid/sampling-secret-env-empty.json +7 -0
  658. package/schema/fixtures/policy/invalid/sampling-secret-env-not-string.json +6 -0
  659. package/schema/fixtures/policy/invalid/skew-tolerance-compound.json +6 -0
  660. package/schema/fixtures/policy/invalid/unknown-autonomy.json +7 -0
  661. package/schema/fixtures/policy/invalid/unknown-class-rule-key.json +6 -0
  662. package/schema/fixtures/policy/invalid/unknown-top-level-key.json +7 -0
  663. package/schema/fixtures/policy/invalid/vault-passphrase-env-empty.json +6 -0
  664. package/schema/fixtures/policy/invalid/vault-passphrase-literal.json +6 -0
  665. package/schema/fixtures/policy/invalid/version-not-string.json +4 -0
  666. package/schema/fixtures/policy/valid/canonical.json +47 -0
  667. package/schema/fixtures/policy/valid/checkpoint-keys.json +18 -0
  668. package/schema/fixtures/policy/valid/class-approvers-limits.json +25 -0
  669. package/schema/fixtures/policy/valid/class-retro-rate.json +17 -0
  670. package/schema/fixtures/policy/valid/global-budgets.json +19 -0
  671. package/schema/fixtures/policy/valid/human-only.json +9 -0
  672. package/schema/fixtures/policy/valid/minimal.json +6 -0
  673. package/schema/fixtures/policy/valid/protected-paths.json +10 -0
  674. package/schema/fixtures/policy/valid/record-namespace.json +13 -0
  675. package/schema/fixtures/policy/valid/request-volume-limits.json +26 -0
  676. package/schema/fixtures/policy/valid/retention-and-sampling-secret.json +16 -0
  677. package/schema/fixtures/policy/valid/skew-tolerance.json +15 -0
  678. package/schema/fixtures/policy/valid/vault-passphrase-env.json +14 -0
  679. package/schema/fixtures/policy/valid/wildcards.json +15 -0
  680. package/schema/fixtures/policy-md/invalid/alias-bomb.md +15 -0
  681. package/schema/fixtures/policy-md/invalid/no-fence.md +7 -0
  682. package/schema/fixtures/policy-md/invalid/protected-route-not-a-subclass.md +16 -0
  683. package/schema/fixtures/policy-md/invalid/schema-invalid-autonomy.md +16 -0
  684. package/schema/fixtures/policy-md/invalid/schema-invalid-read-proof.md +17 -0
  685. package/schema/fixtures/policy-md/invalid/two-fences.md +19 -0
  686. package/schema/fixtures/policy-md/invalid/unclosed-fence.md +11 -0
  687. package/schema/fixtures/policy-md/invalid/wrong-info-string.md +11 -0
  688. package/schema/fixtures/policy-md/invalid/yaml-syntax-error.md +13 -0
  689. package/schema/fixtures/policy-md/precedence/both/APPROVAL.md +7 -0
  690. package/schema/fixtures/policy-md/precedence/both/APPROVALS.md +7 -0
  691. package/schema/fixtures/policy-md/precedence/fallback-only/APPROVALS.md +7 -0
  692. package/schema/fixtures/policy-md/valid/canonical.md +50 -0
  693. package/schema/fixtures/policy-md/valid/daemon-read-proof.md +18 -0
  694. package/schema/fixtures/policy-md/valid/minimal.md +3 -0
  695. package/schema/fixtures/policy-md/valid/prose-lookalikes.md +54 -0
  696. package/schema/fixtures/policy-md/valid/routed-protected-paths.md +49 -0
  697. package/schema/fixtures/policy-md/valid/with-values.md +79 -0
  698. package/schema/fixtures/sample-record/invalid/bad-date-time.json +4 -0
  699. package/schema/fixtures/sample-record/invalid/missing-required-field.json +3 -0
  700. package/schema/fixtures/sample-record/invalid/unknown-top-level-field.json +5 -0
  701. package/schema/fixtures/sample-record/invalid/wrong-type.json +4 -0
  702. package/schema/fixtures/sample-record/valid/minimal.json +4 -0
  703. package/schema/fixtures/sample-record/valid/with-note.json +5 -0
  704. package/schema/fixtures/values/invalid/class-shaped.json +9 -0
  705. package/schema/fixtures/values/invalid/duplicate-entry.json +4 -0
  706. package/schema/fixtures/values/invalid/non-string-item.json +4 -0
  707. package/schema/fixtures/values/invalid/over-cap.json +26 -0
  708. package/schema/fixtures/values/invalid/unknown-key.json +5 -0
  709. package/schema/fixtures/values/invalid/version-string.json +1 -0
  710. package/schema/fixtures/values/valid/empty-lists.json +7 -0
  711. package/schema/fixtures/values/valid/full.json +20 -0
  712. package/schema/fixtures/values/valid/minimal.json +1 -0
  713. package/schema/fixtures/values-md/invalid/schema-invalid.md +62 -0
  714. package/schema/fixtures/values-md/invalid/two-blocks.md +69 -0
  715. package/schema/fixtures/values-md/invalid/unterminated.md +61 -0
  716. package/schema/fixtures/values-md/invalid/yaml-error.md +63 -0
  717. package/schema/fixtures/values-md/valid/absent.md +50 -0
  718. package/schema/fixtures/values-md/valid/with-values.md +79 -0
  719. package/schema/policy.schema.json +501 -0
  720. package/schema/sample-record.schema.json +26 -0
  721. package/schema/values.schema.json +55 -0
  722. package/templates/codex/README.md +9 -0
@@ -0,0 +1,840 @@
1
+ /**
2
+ * `approval log advance` (APRV-125) — the commit-and-push half of the log
3
+ * ritual, as a verb.
4
+ *
5
+ * The APRV-92 flow, written down: the log's appends the remote does not have
6
+ * yet are gathered into a commit whose message names the seq range they cover,
7
+ * and pushed to a short-lived records branch that exists for it. Main is
8
+ * protected here, so the commit reaches it through a pull request, and the PR
9
+ * step is `--pr`, which runs the ordinary gated `gh` path. Since APRV-284 that
10
+ * step also ARMS the merge (`gh pr merge <branch> --merge --auto`, off with
11
+ * `--no-auto-merge`): a records pull request carries only evidence paths, so
12
+ * the click it was waiting for was never a review. {@link armAutoMerge} carries
13
+ * the reasoning and the guard that keeps it true.
14
+ *
15
+ * ## The three refusals that are the point
16
+ *
17
+ * **`log-advance-dirty-stage`.** The staged set must be EXACTLY the log, the
18
+ * queue projection, and the payload store — nothing else. The failure this
19
+ * prevents is the one CLAUDE.md's rule is written against: a log commit riding
20
+ * a branch that carries other work. A verb that ran `git add -A` and hoped
21
+ * would be a worse version of the hand-ritual it replaces, so anything else
22
+ * already staged is a refusal and not a thing to unstage. Unstaging someone
23
+ * else's work is not this verb's decision to make.
24
+ *
25
+ * **`log-advance-checkout-required`.** This verb never checks out anything. The
26
+ * checkout is the footgun: a branch switch with an uncommitted working log
27
+ * rewinds `events.jsonl` under whatever holds it open, which is fork 2 of
28
+ * 2026-08-20. It builds the commit with a scratch index and pushes THAT commit
29
+ * to a records branch by refspec, which moves no HEAD and touches no file.
30
+ *
31
+ * ## The base is the remote, not the local branch (APRV-203)
32
+ *
33
+ * The verb used to commit on the branch you were standing on, which made the
34
+ * operator responsible for that branch being current. A checkout whose local
35
+ * `main` was behind origin produced a records commit parented on a stale tip,
36
+ * carrying a tree that silently reverted everything main had merged since. So
37
+ * the verb fetches first and bases its commit on the remote's tip: `git
38
+ * read-tree` fills a scratch index from origin's tree, the log, the queue
39
+ * projection and the payload store are laid over it from the working tree, and
40
+ * `commit-tree` parents the result on origin. HEAD, the operator's index and
41
+ * every file in the working tree are exactly as they were found.
42
+ *
43
+ * **`log-advance-not-primary`.** Same rule as sync's: the committed log has one
44
+ * home, and it is not a worktree.
45
+ *
46
+ * ## One records branch, and one pull request, per day (APRV-204)
47
+ *
48
+ * The daemon advances on a cadence, so an advance is no longer a once-a-day
49
+ * ceremony and the day's records branch usually already exists. When it does,
50
+ * and its log is a prefix of the working log, the commit is parented on THAT
51
+ * branch rather than on the trunk: parenting every advance on the trunk makes
52
+ * the second push of the day a non-fast-forward of a branch a pull request is
53
+ * already open on. `--pr` asks whether an open pull request exists for the head
54
+ * branch before creating one, so a day gets a single pull request that later
55
+ * advances grow.
56
+ *
57
+ * A local branch that is AHEAD of origin with commits this verb did not make is
58
+ * not a refusal: the advance is based on origin either way, and those commits
59
+ * are simply not part of it. What IS refused is a working log that origin's log
60
+ * is not a prefix of, in either direction, because an advance is only ever the
61
+ * records origin does not have yet.
62
+ *
63
+ * ## This verb appends no event
64
+ *
65
+ * For the same reason `log sync` appends none: committing the file the log
66
+ * lives in is housekeeping on the container, not a decision about the world.
67
+ * The commit is already the record of itself, in git, where a reader can see
68
+ * exactly which bytes moved (SPEC §10.1, amended APRV-125).
69
+ */
70
+ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
71
+ import { tmpdir } from "node:os";
72
+ import { join } from "node:path";
73
+ import { isAdvanceBookkeeping } from "../core/advance-cycle.js";
74
+ import { withAppendLock } from "../core/log.js";
75
+ import { verify } from "../core/verify.js";
76
+ import { commitOnBase, currentBranch, failureText, fetchBase, gh, git, outputLines, primaryCheckout, repoPath, showBlob, } from "./git-scope.js";
77
+ import { anchorRevs, defaultRecordsBranch } from "./log-anchor.js";
78
+ import { compareChains } from "../core/log-reconcile.js";
79
+ import { silentProgress } from "./progress.js";
80
+ import { DEFAULT_LOG_PATH } from "./paths.js";
81
+ import { DEFAULT_QUEUE_PATH } from "./render.js";
82
+ /** SPEC §9: the payload store, the third and last path an advance may carry. */
83
+ const DEFAULT_PAYLOADS_DIR = ".approval/payloads";
84
+ /**
85
+ * The only paths an advance may stage, as git spells them.
86
+ *
87
+ * A closed list, checked in both directions: everything staged must be in it,
88
+ * and nothing outside it may be staged. Widening it is a reviewable diff.
89
+ */
90
+ export const ADVANCE_PATHS = [
91
+ DEFAULT_LOG_PATH,
92
+ DEFAULT_QUEUE_PATH,
93
+ DEFAULT_PAYLOADS_DIR,
94
+ ];
95
+ /** Machine-readable refusal codes. Frozen public API, printed in the help. */
96
+ export const LOG_ADVANCE_REFUSAL_CODES = [
97
+ "log-advance-not-primary",
98
+ "log-advance-no-branch",
99
+ "log-advance-dirty-stage",
100
+ "log-advance-checkout-required",
101
+ "log-advance-unverified",
102
+ "log-advance-locked",
103
+ "log-advance-fetch-failed",
104
+ "log-advance-behind-remote",
105
+ "log-advance-remote-diverged",
106
+ "log-advance-git-failed",
107
+ "log-advance-push-rejected",
108
+ "log-advance-pr-failed",
109
+ "log-advance-co-author-invalid",
110
+ ];
111
+ function detail(cause) {
112
+ return cause instanceof Error ? cause.message : String(cause);
113
+ }
114
+ // Re-exported rather than defined here (APRV-219). The anchor check and this
115
+ // verb must name the day's records branch identically, and `cli/log-anchor.ts`
116
+ // is the module that owns which revs a committed copy of the log may live at.
117
+ export { defaultRecordsBranch };
118
+ /**
119
+ * Everything currently staged, as repo-relative paths.
120
+ *
121
+ * `--name-only --cached` is the whole index against HEAD; the `-z` form is used
122
+ * because a path with a space in it is a path, and a split on newlines would
123
+ * quietly mangle it.
124
+ */
125
+ function stagedPaths(root) {
126
+ const result = git(["diff", "--cached", "--name-only", "-z"], root);
127
+ if (!result.ok)
128
+ return { ok: false, message: failureText(result) };
129
+ const paths = result.stdout.split("\0").filter((entry) => entry.length > 0);
130
+ return { ok: true, paths };
131
+ }
132
+ /**
133
+ * Does `commit` already carry `candidate` in its history? (APRV-234)
134
+ *
135
+ * The question the day's records branch has to answer before another commit is
136
+ * stacked on it: a branch that no longer contains the trunk cannot be
137
+ * fast-forwarded into it, and everything built on it inherits that. Answered
138
+ * with `merge-base --is-ancestor`, whose exit status IS the answer; anything
139
+ * that is not a clean "yes" reads as "no", which is the direction that rebuilds
140
+ * rather than the direction that stacks on a base nobody checked.
141
+ */
142
+ function contains(root, commit, candidate) {
143
+ return git(["merge-base", "--is-ancestor", candidate, commit], root).ok;
144
+ }
145
+ /** Is `path` inside one of the three paths an advance is allowed to carry? */
146
+ function isAdvancePath(path) {
147
+ return ADVANCE_PATHS.some((allowed) => path === allowed || path.startsWith(`${allowed}/`));
148
+ }
149
+ /** `approval log advance`, as a function. The CLI wrapper formats its answer. */
150
+ export function logAdvance(options) {
151
+ const coAuthor = validateCoAuthor(options.coAuthor);
152
+ if (!coAuthor.ok) {
153
+ return {
154
+ ok: false,
155
+ code: "log-advance-co-author-invalid",
156
+ message: coAuthor.message,
157
+ };
158
+ }
159
+ const remote = options.remote ?? "origin";
160
+ const dryRun = options.dryRun === true;
161
+ const primary = primaryCheckout(options.cwd);
162
+ if (!primary.ok) {
163
+ return {
164
+ ok: false,
165
+ code: "log-advance-not-primary",
166
+ message: `log advance runs in the PRIMARY checkout only: ${primary.reason}. Log-touching commits are made where the log lives, never from a worktree. Run this in ${primary.primary ?? "the primary checkout"}.`,
167
+ };
168
+ }
169
+ const root = primary.root;
170
+ const logPath = join(root, DEFAULT_LOG_PATH);
171
+ const branch = currentBranch(root);
172
+ if (branch === null) {
173
+ return {
174
+ ok: false,
175
+ code: "log-advance-no-branch",
176
+ message: `HEAD in ${root} is detached, so there is no branch to commit on. This verb never checks anything out; check out the branch the log lives on yourself and run it again.`,
177
+ };
178
+ }
179
+ // The lock covers the READ of the log and nothing after it (APRV-233).
180
+ //
181
+ // It used to wrap this whole function, `git fetch`, `git push` and `gh pr
182
+ // create` included, and on 2026-09-02 that stalled every harness hook on the
183
+ // machine: each one asked for the append lock, waited the full two seconds
184
+ // and refused its command `append-failed`, for as long as each advance's
185
+ // network round-trips took. Nothing in the git half of the verb appends
186
+ // anything, so nothing in it needs the lock. What the lock IS for is the
187
+ // consistency of one read: the chain must verify, the seq range must be
188
+ // measured, and the bytes that get committed must be the bytes that were
189
+ // verified — so the log's exact content is pinned as a git blob HERE, under
190
+ // the lock, and the commit is assembled from that object rather than from a
191
+ // file another writer may have grown in the meantime.
192
+ (options.progress ?? silentProgress).phase("verifying the log chain before anything is committed from it");
193
+ const held = withAppendLock(logPath, () => snapshotUnderLock(root, logPath));
194
+ if (!held.ok) {
195
+ return {
196
+ ok: false,
197
+ code: held.error.code === "lock-timeout" ? "log-advance-locked" : "log-advance-git-failed",
198
+ message: held.error.code === "lock-timeout"
199
+ ? `${held.error.message}. Advance holds the append lock while it READS the chain, so the seq range it names is the range it commits. Wait for the append to finish and run this again.`
200
+ : held.error.message,
201
+ };
202
+ }
203
+ if (!held.value.ok)
204
+ return held.value;
205
+ return advanceOnSnapshot({ root, logPath, branch, remote, dryRun, options }, held.value);
206
+ }
207
+ /**
208
+ * Everything the advance must read from the log, read once and pinned.
209
+ *
210
+ * Short by design: a chain verify, an index read and one `git hash-object`, all
211
+ * local. Every writer on the machine waits on this and on nothing else.
212
+ */
213
+ function snapshotUnderLock(root, logPath) {
214
+ // 1. The chain, verified. A commit of a log that does not verify would be
215
+ // publishing the break.
216
+ const verified = verify(logPath);
217
+ if (verified.status !== "clean") {
218
+ return {
219
+ ok: false,
220
+ code: "log-advance-unverified",
221
+ message: verified.status === "torn-tail"
222
+ ? `${logPath} ends without a newline: the final record is truncated. Nothing is committed from a torn log; run \`approval log verify\`.`
223
+ : `${logPath} does not verify (${verified.reason}): ${verified.message}. Nothing is committed from a log that does not verify.`,
224
+ };
225
+ }
226
+ // 2. The staged set: exactly the three paths, and nothing else.
227
+ const staged = stagedPaths(root);
228
+ if (!staged.ok) {
229
+ return {
230
+ ok: false,
231
+ code: "log-advance-git-failed",
232
+ message: `the index could not be read: ${staged.message}`,
233
+ };
234
+ }
235
+ const offending = staged.paths.filter((path) => !isAdvancePath(path));
236
+ if (offending.length > 0) {
237
+ return {
238
+ ok: false,
239
+ code: "log-advance-dirty-stage",
240
+ offending,
241
+ message: `${String(offending.length)} path(s) are staged that an advance may not carry: ${offending.join(", ")}. An advance commits the log, the queue projection and the payload store, and nothing else — a log commit that rides other work is the thing the one-commit rule exists to forbid. Unstage them yourself (\`git restore --staged <path>\`) and run this again; this verb will not unstage anyone's work for them.`,
242
+ };
243
+ }
244
+ // 3. The bytes, pinned. `hash-object -w` writes the blob into the object
245
+ // store and answers its sha, so the commit built after the lock is
246
+ // released carries exactly what was verified above, however much the file
247
+ // has grown by then.
248
+ const text = textOfWorking(logPath);
249
+ const hashed = git(["hash-object", "-w", "--", repoPath(root, logPath)], root);
250
+ const blob = hashed.stdout.trim();
251
+ if (!hashed.ok || blob.length === 0) {
252
+ return {
253
+ ok: false,
254
+ code: "log-advance-git-failed",
255
+ message: `the working log could not be written to the object store: ${failureText(hashed)}; nothing was committed.`,
256
+ };
257
+ }
258
+ return { ok: true, text, blob, staged: staged.paths };
259
+ }
260
+ function advanceOnSnapshot(ctx, snapshot) {
261
+ const { root, logPath, branch, remote, dryRun, options } = ctx;
262
+ const coAuthor = options.coAuthor ?? null;
263
+ const progress = options.progress ?? silentProgress;
264
+ // 4. The base: the remote's tip, fetched by this verb rather than by the
265
+ // operator (APRV-203). Everything after this is measured against it.
266
+ const baseBranch = options.base ?? branch;
267
+ progress.phase(`fetching ${remote}/${baseBranch}: an advance is based on the remote, not on this checkout`);
268
+ const fetched = fetchBase(root, remote, baseBranch);
269
+ if (!fetched.ok) {
270
+ return {
271
+ ok: false,
272
+ code: "log-advance-fetch-failed",
273
+ message: `${fetched.message}. An advance bases its commit on ${remote}/${baseBranch}, so it cannot proceed without knowing where that is. Nothing was committed. Fix the remote (network, credentials, or a branch named something else — pass \`--base <branch>\`) and run this again.`,
274
+ quote: fetched.quote,
275
+ };
276
+ }
277
+ const baseSha = fetched.sha;
278
+ // 5. What is owed: the seq range between the committed log and the working
279
+ // head. Measured against the SNAPSHOT (APRV-233), which is the same bytes
280
+ // the commit will carry, so the range this names is the range it commits
281
+ // even though the lock is no longer held.
282
+ const workingText = snapshot.text;
283
+ const against = (sha, label) => {
284
+ const blob = showBlob(root, sha, repoPath(root, logPath));
285
+ const compared = compareChains({ label: `the working log ${logPath}`, text: workingText }, {
286
+ label: `the committed log ${label}:${repoPath(root, logPath)}`,
287
+ text: blob === null ? "" : blob.toString("utf8"),
288
+ });
289
+ if (!compared.ok) {
290
+ return { ok: false, code: "log-advance-unverified", message: compared.message };
291
+ }
292
+ if (compared.drift.relation === "diverged") {
293
+ return {
294
+ ok: false,
295
+ code: "log-advance-remote-diverged",
296
+ message: `the working log and ${label}'s log part at seq ${String(compared.drift.firstDivergentSeq)}: two chains, not one. Nothing is advanced over a fork, and nothing was committed. Run \`approval doctor\` for the log-drift report; hash chains do not merge, so which of the two is the log is a human decision.`,
297
+ };
298
+ }
299
+ if (compared.drift.relation === "behind") {
300
+ return {
301
+ ok: false,
302
+ code: "log-advance-behind-remote",
303
+ message: `${label} carries records this working log does not (its head is ${String(compared.drift.committedHead?.seq ?? 0)}, the working head is ${String(compared.drift.workingHead?.seq ?? 0)}). An advance publishes records the remote lacks, so there is nothing here to publish and committing would propose an older chain than the one already on the remote. Run \`approval log sync\` first, then run this again. Nothing was committed.`,
304
+ };
305
+ }
306
+ return { ok: true, drift: compared.drift };
307
+ };
308
+ const trunk = against(baseSha, `${remote}/${baseBranch}`);
309
+ if (!("drift" in trunk))
310
+ return trunk;
311
+ const recordsBranch = options.branch ?? defaultRecordsBranch(options.today ?? new Date().toISOString());
312
+ if (recordsBranch === "main" || recordsBranch === "master") {
313
+ return {
314
+ ok: false,
315
+ code: "log-advance-checkout-required",
316
+ message: `--branch ${recordsBranch} would push the advance straight at the trunk. An advance goes to a records branch and reaches the trunk through a pull request; pick another name.`,
317
+ };
318
+ }
319
+ // 4a. One records branch per day, updated rather than re-created (APRV-204).
320
+ //
321
+ // The day's branch usually already exists: the daemon advances on a cadence
322
+ // and every tick after the first would otherwise build ANOTHER commit on the
323
+ // trunk, which the remote rejects as a non-fast-forward of the branch a pull
324
+ // request is already open on. So when the records branch exists and its log
325
+ // is a prefix of the working log, THAT is the parent: the push fast-forwards
326
+ // and the open pull request grows by one commit.
327
+ //
328
+ // A fetch failure here is read as "no such branch", which is what it is
329
+ // whenever the trunk fetch a moment ago succeeded. The alternative — treating
330
+ // it as a network failure and refusing — would refuse every first advance of
331
+ // every day, since the branch genuinely does not exist yet.
332
+ //
333
+ // 4b. Unless the trunk has moved under the branch (APRV-234).
334
+ //
335
+ // Observed 2026-09-02: a ceremony commit landed on main carrying its own copy
336
+ // of the log, so `records-log-2026-09-02` no longer contained the trunk. The
337
+ // daemon went on stacking advance commits on the branch tip — six of them —
338
+ // each built on a base that was missing main's copy, and the pull request
339
+ // went DIRTY and stayed DIRTY. Nothing the cadence could do would clear it;
340
+ // it took a hand `git merge -X ours origin/main` by a person, which is
341
+ // precisely the tap this feature exists to remove.
342
+ //
343
+ // So: stack only while the branch still contains the base. When it does not,
344
+ // REBUILD — the same commit content, parented on the current trunk instead —
345
+ // and push it over the branch. That is sound here for a reason peculiar to
346
+ // this verb: the only paths it carries are the append-only log, its
347
+ // projection and its content-addressed payloads, and the trunk check above
348
+ // has already refused unless the working log is a SUPERSET of the trunk's
349
+ // (`log-advance-behind-remote` in one direction, `log-advance-remote-diverged`
350
+ // in the other). A rebuilt commit is therefore the trunk's own log plus the
351
+ // tail it lacks, never a revert of anything the trunk merged.
352
+ let parent = { ref: `${remote}/${baseBranch}`, sha: baseSha };
353
+ let drift = trunk.drift;
354
+ let reusedRecordsBranch = false;
355
+ let rebuilt = false;
356
+ let rebuiltOn;
357
+ const existing = fetchBase(root, remote, recordsBranch);
358
+ if (existing.ok) {
359
+ if (contains(root, existing.sha, baseSha)) {
360
+ const onBranch = against(existing.sha, `${remote}/${recordsBranch}`);
361
+ if (!("drift" in onBranch))
362
+ return onBranch;
363
+ parent = { ref: `${remote}/${recordsBranch}`, sha: existing.sha };
364
+ drift = onBranch.drift;
365
+ reusedRecordsBranch = true;
366
+ }
367
+ else {
368
+ // The branch exists and does not contain the trunk. Keep `parent` at the
369
+ // trunk and say so: the range is measured against the trunk's log, which
370
+ // is what `trunk.drift` already holds.
371
+ rebuilt = true;
372
+ rebuiltOn = { ref: `${remote}/${baseBranch}`, sha: baseSha };
373
+ }
374
+ }
375
+ const committedSeq = drift.committedHead?.seq ?? 0;
376
+ // `null` when there is nothing owed. A no-op advance is a SUCCESS, exactly as
377
+ // a no-op `policy amend` is: an operator who runs it on an already-committed
378
+ // log has established what they wanted to establish.
379
+ const range = drift.relation === "ahead"
380
+ ? { from: committedSeq + 1, to: drift.workingHead?.seq ?? committedSeq }
381
+ : null;
382
+ const message = range === null ? "" : messageWithCoAuthor(advanceMessage(range, branch), coAuthor);
383
+ const carried = ADVANCE_PATHS.filter((path) => existsSync(join(root, path)));
384
+ const report = (over) => ({
385
+ root,
386
+ branch,
387
+ recordsBranch,
388
+ remote,
389
+ base: { branch: baseBranch, sha: baseSha },
390
+ parent: { ref: parent.ref, sha: parent.sha },
391
+ reusedRecordsBranch,
392
+ rebuilt,
393
+ ...(rebuiltOn === undefined ? {} : { rebuiltOn }),
394
+ prCreated: false,
395
+ autoMerge: null,
396
+ autoMergeNote: null,
397
+ range,
398
+ committedHead: drift.committedHead,
399
+ workingHead: drift.workingHead,
400
+ staged: carried,
401
+ message,
402
+ commit: null,
403
+ pushed: false,
404
+ prUrl: null,
405
+ dryRun,
406
+ ...over,
407
+ });
408
+ if (range === null || dryRun)
409
+ return { ok: true, report: report({ staged: range === null ? [] : carried }) };
410
+ // 5. Build the commit on the remote's tip, in a scratch index. Exactly those
411
+ // paths, laid over origin's tree; the operator's index is never touched
412
+ // and nothing is checked out.
413
+ progress.phase(`building the records commit on ${parent.ref} ${parent.sha.slice(0, 12)} (nothing is checked out)`);
414
+ const built = commitOnBase(root, {
415
+ base: parent.sha,
416
+ paths: carried,
417
+ message,
418
+ // APRV-233. The log goes in as the blob taken under the append lock, not as
419
+ // whatever the file holds now: the lock was released before the fetch, and
420
+ // a record appended since is a record this commit's message does not claim.
421
+ blobs: carried.includes(DEFAULT_LOG_PATH)
422
+ ? [{ path: repoPath(root, logPath), sha: snapshot.blob }]
423
+ : [],
424
+ });
425
+ if (!built.ok) {
426
+ return {
427
+ ok: false,
428
+ code: "log-advance-git-failed",
429
+ message: `${built.message}; nothing was committed and the checkout is untouched.`,
430
+ quote: built.quote,
431
+ };
432
+ }
433
+ if (built.unchanged) {
434
+ // The chains said records were owed and the trees say otherwise, which
435
+ // means the log file on the remote already carries these bytes under a
436
+ // different commit. Nothing to publish, and an empty commit would say
437
+ // otherwise.
438
+ return { ok: true, report: report({ commit: null, staged: [] }) };
439
+ }
440
+ const commit = built.sha;
441
+ // 6. Anchor the commit before pushing, so a rejected push loses nothing. A
442
+ // ref under `refs/approval/` rather than a branch: it keeps the object
443
+ // reachable without adding a branch nobody asked for, and it moves no HEAD.
444
+ const anchor = `refs/approval/advance/${recordsBranch}`;
445
+ git(["update-ref", anchor, commit], root);
446
+ // 7. Push THAT commit to the records branch, by refspec. A sha on the left
447
+ // moves no local ref and checks nothing out: the operator's branch stays
448
+ // exactly where they left it.
449
+ progress.phase(`pushing ${commit.slice(0, 12)} to ${remote} ${recordsBranch}`);
450
+ // A rebuilt commit does not descend from the branch it replaces, so it needs
451
+ // the `+`. It is not a history rewrite in the sense the rule forbids: the
452
+ // branch is a proposal nobody has merged, every record it carried is in the
453
+ // new commit's log, and the alternative is a pull request that cannot land.
454
+ const refspec = `${rebuilt ? "+" : ""}${commit}:refs/heads/${recordsBranch}`;
455
+ let target = recordsBranch;
456
+ let fallbackFrom = null;
457
+ let pushed = git(["push", remote, refspec], root);
458
+ if (!pushed.ok && rebuilt) {
459
+ // The branch cannot be updated in place: a protected-branch ruleset
460
+ // (GH006), or a pull request the merge queue has already taken. The records
461
+ // still have to reach a branch somebody can merge, so they get a fresh one
462
+ // and the report says which (APRV-234).
463
+ const rejection = failureText(pushed);
464
+ for (let n = 2; n <= 9 && !pushed.ok; n += 1) {
465
+ const alternate = `${recordsBranch}-${String(n)}`;
466
+ const attempt = git(["push", remote, `${commit}:refs/heads/${alternate}`], root);
467
+ if (attempt.ok) {
468
+ pushed = attempt;
469
+ fallbackFrom = recordsBranch;
470
+ target = alternate;
471
+ git(["update-ref", `refs/approval/advance/${alternate}`, commit], root);
472
+ progress.phase(`${recordsBranch} would not take the rebuilt commit (${rejection}); opened ${alternate} instead`);
473
+ }
474
+ }
475
+ }
476
+ if (!pushed.ok) {
477
+ return {
478
+ ok: false,
479
+ code: "log-advance-push-rejected",
480
+ message: `the advance is built on ${parent.ref} as ${commit.slice(0, 12)} and held at ${anchor}, but \`git push ${remote} ${refspec}\` was REJECTED: ${failureText(pushed)}. The commit exists and nothing was lost; push it when the remote will take it (\`git push ${remote} ${refspec}\`). Your checkout is exactly as you left it, on ${branch}.`,
481
+ quote: outputLines(pushed.stderr, pushed.stdout),
482
+ };
483
+ }
484
+ if (options.pr !== true) {
485
+ progress.done();
486
+ return {
487
+ ok: true,
488
+ report: report({ commit, pushed: true, recordsBranch: target, fallbackFrom }),
489
+ };
490
+ }
491
+ progress.phase(`opening or updating the pull request for ${target}`);
492
+ const pr = ghPullRequest(root, target, range, coAuthor);
493
+ if (!pr.ok) {
494
+ progress.done();
495
+ return {
496
+ ok: false,
497
+ code: "log-advance-pr-failed",
498
+ message: `the advance is committed and pushed to ${target}, but \`gh pr ${pr.step}\` failed: ${pr.message}. Open the pull request by hand and merge it with a merge commit.`,
499
+ };
500
+ }
501
+ // APRV-284. The arm, and never a refusal of the verb: the records are
502
+ // committed, pushed and open as a pull request whatever `gh` says next.
503
+ const arm = options.autoMerge === false
504
+ ? { state: "off", note: null }
505
+ : armAutoMerge(root, target, { baseSha, commit });
506
+ if (arm.state === "armed") {
507
+ progress.phase(`auto-merge armed on ${target}`);
508
+ }
509
+ else if (arm.note !== null) {
510
+ progress.phase(`auto-merge was not armed on ${target}: ${arm.note}`);
511
+ }
512
+ progress.done();
513
+ return {
514
+ ok: true,
515
+ report: report({
516
+ commit,
517
+ pushed: true,
518
+ recordsBranch: target,
519
+ fallbackFrom,
520
+ prUrl: pr.url,
521
+ prCreated: pr.created,
522
+ autoMerge: arm.state,
523
+ autoMergeNote: arm.note,
524
+ }),
525
+ };
526
+ }
527
+ /**
528
+ * The chain head of one git rev's copy of the log, or `null`.
529
+ *
530
+ * `null` covers three cases that mean the same thing here: no such rev, no such
531
+ * blob, and a copy that is not this chain (a fork, or a chain somehow ahead of
532
+ * the working log). None is evidence that any working record has been
533
+ * published, and treating any of them as evidence would UNDER-count what is
534
+ * owed, which is the direction that loses records.
535
+ */
536
+ function publishedHeadAt(root, logPath, workingText, rev) {
537
+ const blob = showBlob(root, rev, repoPath(root, logPath));
538
+ if (blob === null)
539
+ return null;
540
+ const compared = compareChains({ label: "the working log", text: workingText }, { label: rev, text: blob.toString("utf8") });
541
+ if (!compared.ok)
542
+ return null;
543
+ if (compared.drift.relation === "diverged" || compared.drift.relation === "behind")
544
+ return null;
545
+ return compared.drift.committedHead?.seq ?? 0;
546
+ }
547
+ /**
548
+ * How much of the working log is already on a records branch or the trunk.
549
+ *
550
+ * Reads git's object store and NEVER the network: this is asked on every daemon
551
+ * tick and by `approval doctor`, and a status question must not depend on a
552
+ * remote being reachable. The revs consulted are the local advance anchors
553
+ * (`refs/approval/advance/*`, which {@link logAdvance} writes before it pushes),
554
+ * the remote-tracking refs for the base branch and the day's records branch, and
555
+ * `HEAD`. The highest head among the copies that are a PREFIX of this chain
556
+ * wins; anything else is ignored, which can only make a caller advance less
557
+ * eagerly.
558
+ *
559
+ * It lives here rather than beside the daemon's cadence because `approval
560
+ * doctor` reports the same number and a CLI module may not import the daemon.
561
+ */
562
+ export function publishedState(root, logPath, records, where, today) {
563
+ const workingSeq = records.length === 0 ? 0 : (records[records.length - 1]?.seq ?? 0);
564
+ let workingText;
565
+ try {
566
+ workingText = readFileSync(logPath, "utf8");
567
+ }
568
+ catch {
569
+ workingText = "";
570
+ }
571
+ const revs = anchorRevs(root, { remote: where.remote, base: where.base, today });
572
+ let publishedSeq = 0;
573
+ let publishedRev = null;
574
+ for (const rev of revs) {
575
+ const head = publishedHeadAt(root, logPath, workingText, rev);
576
+ if (head !== null && head > publishedSeq) {
577
+ publishedSeq = head;
578
+ publishedRev = rev;
579
+ }
580
+ }
581
+ const unpublished = records.filter((record) => record.seq > publishedSeq);
582
+ const substantive = unpublished.filter((record) => !isAdvanceBookkeeping(record));
583
+ return {
584
+ publishedSeq,
585
+ workingSeq,
586
+ pending: unpublished.length,
587
+ substantive: substantive.length,
588
+ substantiveSeq: substantive[substantive.length - 1]?.seq ?? publishedSeq,
589
+ publishedRev,
590
+ revs,
591
+ };
592
+ }
593
+ /** The working log's text, or the empty string when there is no file. */
594
+ function textOfWorking(path) {
595
+ try {
596
+ return readFileSync(path, "utf8");
597
+ }
598
+ catch (cause) {
599
+ if (cause.code === "ENOENT")
600
+ return "";
601
+ throw new Error(`log ${path} could not be read: ${detail(cause)}`);
602
+ }
603
+ }
604
+ /** The canonical commit subject. It names the seq range, so the log is findable. */
605
+ export function advanceMessage(range, branch) {
606
+ const span = range.from === range.to ? `seq ${String(range.from)}` : `seq ${String(range.from)}..${String(range.to)}`;
607
+ return `Log advance: ${span} (${branch})`;
608
+ }
609
+ const CO_AUTHOR_MAX_BYTES = 254;
610
+ const CO_AUTHOR_EMAIL = /^[A-Za-z0-9.!#$%&'*+/=?^_`{|}~-]+@[A-Za-z0-9](?:[A-Za-z0-9.-]*[A-Za-z0-9])?$/u;
611
+ /**
612
+ * Validate a display-only Git trailer identity before any mutating step.
613
+ *
614
+ * The accepted form is deliberately one line and one header value. It is never
615
+ * derived from a log actor and never interpreted as gate or GitHub authority.
616
+ */
617
+ export function validateCoAuthor(input) {
618
+ if (input === undefined)
619
+ return { ok: true, value: null };
620
+ if (input.length === 0 || Buffer.byteLength(input, "utf8") > CO_AUTHOR_MAX_BYTES) {
621
+ return {
622
+ ok: false,
623
+ message: `--co-author expects one Name <email> identity of at most ${String(CO_AUTHOR_MAX_BYTES)} bytes`,
624
+ };
625
+ }
626
+ if (/[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/u.test(input) || input.trim() !== input) {
627
+ return {
628
+ ok: false,
629
+ message: "--co-author must be one line with no control or separator characters or surrounding whitespace",
630
+ };
631
+ }
632
+ const matched = /^([^<>:]+) <([^<>]+)>$/u.exec(input);
633
+ const name = matched?.[1] ?? "";
634
+ const email = matched?.[2] ?? "";
635
+ if (name.length === 0 || name.trim() !== name || !CO_AUTHOR_EMAIL.test(email)) {
636
+ return {
637
+ ok: false,
638
+ message: "--co-author expects exactly Name <email>; it is display credit, not an actor or approval identity",
639
+ };
640
+ }
641
+ return { ok: true, value: input };
642
+ }
643
+ function coAuthorTrailer(coAuthor) {
644
+ return `Co-authored-by: ${coAuthor}`;
645
+ }
646
+ function messageWithCoAuthor(message, coAuthor) {
647
+ return coAuthor === null ? message : `${message}\n\n${coAuthorTrailer(coAuthor)}`;
648
+ }
649
+ function bodyWithCoAuthor(body, coAuthor) {
650
+ const trailer = coAuthorTrailer(coAuthor);
651
+ const normalized = body.replace(/\r\n/gu, "\n").trimEnd();
652
+ if (normalized === trailer || normalized.endsWith(`\n\n${trailer}`))
653
+ return body;
654
+ return `${body}${body.endsWith("\n") ? "\n" : "\n\n"}${trailer}`;
655
+ }
656
+ function ghWithBodyFile(root, args, body) {
657
+ const scratch = mkdtempSync(join(tmpdir(), "approval-pr-body-"));
658
+ const bodyPath = join(scratch, "body.md");
659
+ try {
660
+ writeFileSync(bodyPath, body, { encoding: "utf8", flag: "wx", mode: 0o600 });
661
+ return gh([...args, "--body-file", bodyPath], root);
662
+ }
663
+ finally {
664
+ rmSync(scratch, { recursive: true, force: true });
665
+ }
666
+ }
667
+ /** The first `http…` line of a `gh` run's output, which is how `gh` names a PR. */
668
+ function urlOf(text) {
669
+ return (text
670
+ .split("\n")
671
+ .map((line) => line.trim())
672
+ .filter((line) => line.startsWith("http"))
673
+ .pop() ?? null);
674
+ }
675
+ /**
676
+ * The day's pull request for the records branch: opened once, updated after.
677
+ *
678
+ * ONE PR PER DAY, not one per advance (APRV-204). The daemon advances on a
679
+ * cadence, so `gh pr create` on every run would either fail (a PR for the head
680
+ * branch already exists) or, on a remote that allows it, litter the repository
681
+ * with a pull request per tick. The push has already updated the branch by the
682
+ * time this runs, so an open pull request for that head IS the updated one and
683
+ * this function's whole job is to notice it.
684
+ *
685
+ * `gh pr list` is a read (`read.vcs.remote` in this project's own taxonomy) and
686
+ * asks nothing of the remote's state.
687
+ */
688
+ function ghPullRequest(root, recordsBranch, range, coAuthor) {
689
+ const listed = gh(["pr", "list", "--head", recordsBranch, "--state", "open", "--json", "url,body"], root);
690
+ if (!listed.ok) {
691
+ return { ok: false, step: "list", message: failureText(listed) };
692
+ }
693
+ const open = parsePrList(listed.stdout);
694
+ if (open.length > 0) {
695
+ const current = open[0];
696
+ if (current === undefined)
697
+ throw new Error("unreachable");
698
+ if (coAuthor !== null) {
699
+ if (current.body === null) {
700
+ return {
701
+ ok: false,
702
+ step: "list",
703
+ message: "the open pull request body was unavailable, so its existing text was not replaced",
704
+ };
705
+ }
706
+ const body = bodyWithCoAuthor(current.body, coAuthor);
707
+ if (body !== current.body) {
708
+ const edited = ghWithBodyFile(root, ["pr", "edit", recordsBranch], body);
709
+ if (!edited.ok)
710
+ return { ok: false, step: "edit", message: failureText(edited) };
711
+ }
712
+ }
713
+ return { ok: true, url: current.url, created: false };
714
+ }
715
+ const title = `Log advance: ${range.from === range.to ? `seq ${String(range.from)}` : `seq ${String(range.from)}..${String(range.to)}`}`;
716
+ const body = "This branch carries the append-only log advance, its queue projection, and the payload files the records reference — one commit per advance, and nothing else. " +
717
+ "Merge with a MERGE COMMIT. Nothing else may ride this branch: a log commit alongside other work is what the one-commit rule forbids.";
718
+ const created = coAuthor === null
719
+ ? gh(["pr", "create", "--title", title, "--body", body, "--head", recordsBranch], root)
720
+ : ghWithBodyFile(root, ["pr", "create", "--title", title, "--head", recordsBranch], bodyWithCoAuthor(body, coAuthor));
721
+ if (!created.ok) {
722
+ return { ok: false, step: "create", message: failureText(created) };
723
+ }
724
+ return { ok: true, url: urlOf(created.stdout), created: true };
725
+ }
726
+ /**
727
+ * Arm auto-merge on the day's records pull request (APRV-284).
728
+ *
729
+ * ## Why a records pull request may arm its own merge
730
+ *
731
+ * A records commit carries EXACTLY the log, `QUEUE.md` and
732
+ * `.approval/payloads/` (the `log-advance-dirty-stage` refusal is the other
733
+ * half of that rule), those three are the paths CI's protected-path guard
734
+ * exempts, and there is nothing in them a reviewer reviews: the log is
735
+ * append-only evidence and the queue is a projection of it. So a records pull
736
+ * request is the one shape in this repository that never needs a human to read
737
+ * it, and leaving it at CLEAN until somebody clicks is exactly the failure mode
738
+ * CLAUDE.md's workflow item 7 exists to remove.
739
+ *
740
+ * ## What the arm is, in this project's own taxonomy
741
+ *
742
+ * `gh pr merge <branch> --merge --auto` — the same command with the same class
743
+ * (`vcs.push.main`, `core/command-class.ts`'s `gh-pr-merge` row) a session runs
744
+ * to arm its own pull request. Nothing here mints a class, claims an exemption,
745
+ * or asks a second question: this runs inside whatever authorized the advance,
746
+ * which for the daemon is the `log.advance` grant APRV-204 opened and for a
747
+ * session is the harness hook's answer on the verb.
748
+ *
749
+ * ## The guard, and why the arm is not unconditional
750
+ *
751
+ * The reasoning above holds only while the branch really does carry nothing
752
+ * else. It is a branch on a shared remote, so a commit this verb did not make
753
+ * can be sitting on it, and the advance would fast-forward over that commit and
754
+ * then arm a merge for it. So the arm is preceded by a check of the pushed
755
+ * branch against the base it is measured from, and anything outside
756
+ * {@link ADVANCE_PATHS} WITHHOLDS the arm and names what it saw. Everything
757
+ * ambiguous withholds too: an unreadable diff, a base that could not be
758
+ * resolved. A withheld arm costs a human one click; an unconditional one would
759
+ * land whatever rode the branch.
760
+ *
761
+ * ## An arm `gh` says no to is not a failure
762
+ *
763
+ * Auto-merge disabled on the repository, a merge queue, a pull request already
764
+ * mergeable: `gh` refuses all three, and the advance is committed, pushed and
765
+ * open as a pull request regardless. The refusal is reported and the verb still
766
+ * succeeds — the same rule `cli/amend.ts`'s ceremony arm has followed since
767
+ * APRV-130.
768
+ */
769
+ function armAutoMerge(root, recordsBranch, span) {
770
+ const carried = branchDiffPaths(root, span.baseSha, span.commit);
771
+ if (carried === null) {
772
+ return {
773
+ state: "withheld",
774
+ note: `\`git diff --name-only ${span.baseSha.slice(0, 12)} ${span.commit.slice(0, 12)}\` could not be read, so what ${recordsBranch} carries is unknown`,
775
+ };
776
+ }
777
+ const foreign = carried.filter((path) => !isAdvancePath(path));
778
+ if (foreign.length > 0) {
779
+ return {
780
+ state: "withheld",
781
+ note: `${recordsBranch} carries paths an advance does not: ${foreign.join(", ")}. A records pull request arms its own merge because it carries only evidence; this one does not, so it wants a reviewer`,
782
+ };
783
+ }
784
+ const merged = gh(["pr", "merge", recordsBranch, "--merge", "--auto"], root);
785
+ if (merged.ok)
786
+ return { state: "armed", note: null };
787
+ return {
788
+ state: "refused",
789
+ note: outputLines(merged.stderr, merged.stdout)[0] ?? failureText(merged),
790
+ };
791
+ }
792
+ /**
793
+ * Every path `from..to` touches, or `null` when git would not say.
794
+ *
795
+ * `null` is not "nothing changed": an empty diff is `[]`, and the two must not
796
+ * collapse, because the caller treats the unknown as a reason to withhold and
797
+ * the empty as a branch carrying nothing foreign.
798
+ */
799
+ function branchDiffPaths(root, from, to) {
800
+ if (from.length === 0 || to.length === 0)
801
+ return null;
802
+ const diff = git(["diff", "--name-only", `${from}..${to}`], root);
803
+ if (!diff.ok)
804
+ return null;
805
+ return diff.stdout
806
+ .split("\n")
807
+ .map((line) => line.trim())
808
+ .filter((line) => line.length > 0);
809
+ }
810
+ /**
811
+ * The urls in `gh pr list --json url` output.
812
+ *
813
+ * Unparseable output answers "no open pull request", which is the conservative
814
+ * reading in exactly one direction: the verb then tries to create one, and a
815
+ * `gh pr create` that finds an existing PR fails loudly with the reason. The
816
+ * opposite default would silently skip opening the day's pull request.
817
+ */
818
+ function parsePrList(text) {
819
+ let parsed;
820
+ try {
821
+ parsed = JSON.parse(text.trim().length === 0 ? "[]" : text);
822
+ }
823
+ catch {
824
+ return [];
825
+ }
826
+ if (!Array.isArray(parsed))
827
+ return [];
828
+ const pullRequests = [];
829
+ for (const entry of parsed) {
830
+ if (typeof entry !== "object" || entry === null)
831
+ continue;
832
+ const url = entry["url"];
833
+ const body = entry["body"];
834
+ if (typeof url === "string" && url.length > 0) {
835
+ pullRequests.push({ url, body: typeof body === "string" ? body : null });
836
+ }
837
+ }
838
+ return pullRequests;
839
+ }
840
+ //# sourceMappingURL=log-advance.js.map