approval-md 0.1.0 → 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 (266) hide show
  1. package/README.md +584 -553
  2. package/SPEC.md +42 -13
  3. package/dist/src/adapters/agentmail.d.ts +426 -0
  4. package/dist/src/adapters/agentmail.js +2 -2
  5. package/dist/src/adapters/conformance.d.ts +149 -0
  6. package/dist/src/adapters/contract.d.ts +628 -0
  7. package/dist/src/adapters/contract.js +110 -16
  8. package/dist/src/adapters/contract.js.map +1 -1
  9. package/dist/src/adapters/email.d.ts +324 -0
  10. package/dist/src/adapters/env-passphrase.d.ts +93 -0
  11. package/dist/src/adapters/public.d.ts +11 -0
  12. package/dist/src/adapters/public.js +11 -0
  13. package/dist/src/adapters/public.js.map +1 -0
  14. package/dist/src/adapters/registry.d.ts +59 -0
  15. package/dist/src/adapters/registry.js +2 -1
  16. package/dist/src/adapters/registry.js.map +1 -1
  17. package/dist/src/adapters/smtp.d.ts +213 -0
  18. package/dist/src/adapters/vault-provider.d.ts +114 -0
  19. package/dist/src/adapters/vault-provider.js +3 -3
  20. package/dist/src/adapters/zzz.d.ts +66 -0
  21. package/dist/src/adapters/zzz.js +299 -0
  22. package/dist/src/adapters/zzz.js.map +1 -0
  23. package/dist/src/channels/batch.d.ts +109 -0
  24. package/dist/src/channels/cli.d.ts +193 -0
  25. package/dist/src/channels/conformance.d.ts +92 -0
  26. package/dist/src/channels/contract.d.ts +623 -0
  27. package/dist/src/channels/payload-view.d.ts +35 -0
  28. package/dist/src/channels/render-queue.d.ts +149 -0
  29. package/dist/src/channels/tagging.d.ts +196 -0
  30. package/dist/src/channels/telegram.d.ts +1832 -0
  31. package/dist/src/channels/web.d.ts +341 -0
  32. package/dist/src/cli/adapter.d.ts +90 -0
  33. package/dist/src/cli/adapter.js +25 -15
  34. package/dist/src/cli/adapter.js.map +1 -1
  35. package/dist/src/cli/amend.d.ts +59 -0
  36. package/dist/src/cli/args.d.ts +43 -0
  37. package/dist/src/cli/attest.d.ts +41 -0
  38. package/dist/src/cli/audit-card.d.ts +62 -0
  39. package/dist/src/cli/audit.d.ts +59 -0
  40. package/dist/src/cli/channel-telegram.d.ts +806 -0
  41. package/dist/src/cli/channel-web.d.ts +131 -0
  42. package/dist/src/cli/channel.d.ts +71 -0
  43. package/dist/src/cli/checkpoint-tap.d.ts +169 -0
  44. package/dist/src/cli/codex.d.ts +2 -0
  45. package/dist/src/cli/codex.js +172 -0
  46. package/dist/src/cli/codex.js.map +1 -0
  47. package/dist/src/cli/coverage.d.ts +61 -0
  48. package/dist/src/cli/daemon.d.ts +120 -0
  49. package/dist/src/cli/doctor.d.ts +129 -0
  50. package/dist/src/cli/doctor.js +119 -5
  51. package/dist/src/cli/doctor.js.map +1 -1
  52. package/dist/src/cli/env.d.ts +65 -0
  53. package/dist/src/cli/execute.d.ts +202 -0
  54. package/dist/src/cli/exit-codes.d.ts +73 -0
  55. package/dist/src/cli/feedback.d.ts +60 -0
  56. package/dist/src/cli/gate-window.d.ts +40 -0
  57. package/dist/src/cli/gate.d.ts +68 -0
  58. package/dist/src/cli/git-scope.d.ts +190 -0
  59. package/dist/src/cli/gloss-attach.d.ts +85 -0
  60. package/dist/src/cli/gloss-codex-child.d.ts +9 -0
  61. package/dist/src/cli/gloss-codex.d.ts +24 -0
  62. package/dist/src/cli/gloss-options.d.ts +42 -0
  63. package/dist/src/cli/gloss.d.ts +265 -0
  64. package/dist/src/cli/help.d.ts +103 -0
  65. package/dist/src/cli/help.js +173 -51
  66. package/dist/src/cli/help.js.map +1 -1
  67. package/dist/src/cli/hook-codex.d.ts +78 -0
  68. package/dist/src/cli/hook-codex.js +167 -0
  69. package/dist/src/cli/hook-codex.js.map +1 -0
  70. package/dist/src/cli/hook.d.ts +331 -0
  71. package/dist/src/cli/hook.js +186 -80
  72. package/dist/src/cli/hook.js.map +1 -1
  73. package/dist/src/cli/import.d.ts +35 -0
  74. package/dist/src/cli/init.d.ts +84 -0
  75. package/dist/src/cli/init.js +2 -2
  76. package/dist/src/cli/init.js.map +1 -1
  77. package/dist/src/cli/instructions.d.ts +23 -0
  78. package/dist/src/cli/journal.d.ts +41 -0
  79. package/dist/src/cli/log-advance.d.ts +287 -0
  80. package/dist/src/cli/log-advance.js +102 -11
  81. package/dist/src/cli/log-advance.js.map +1 -1
  82. package/dist/src/cli/log-anchor.d.ts +176 -0
  83. package/dist/src/cli/log-checkpoint.d.ts +22 -0
  84. package/dist/src/cli/log-sync.d.ts +243 -0
  85. package/dist/src/cli/log-verbs.d.ts +16 -0
  86. package/dist/src/cli/log-verbs.js +7 -1
  87. package/dist/src/cli/log-verbs.js.map +1 -1
  88. package/dist/src/cli/long-help.d.ts +70 -0
  89. package/dist/src/cli/main.d.ts +77 -0
  90. package/dist/src/cli/main.js +155 -5
  91. package/dist/src/cli/main.js.map +1 -1
  92. package/dist/src/cli/mcp.d.ts +52 -0
  93. package/dist/src/cli/paths.d.ts +56 -0
  94. package/dist/src/cli/payload.d.ts +58 -0
  95. package/dist/src/cli/policy.d.ts +43 -0
  96. package/dist/src/cli/preflight.d.ts +363 -0
  97. package/dist/src/cli/preflight.js +294 -7
  98. package/dist/src/cli/preflight.js.map +1 -1
  99. package/dist/src/cli/progress.d.ts +78 -0
  100. package/dist/src/cli/prompt.d.ts +209 -0
  101. package/dist/src/cli/quickstart.d.ts +46 -0
  102. package/dist/src/cli/quickstart.js +297 -0
  103. package/dist/src/cli/quickstart.js.map +1 -0
  104. package/dist/src/cli/records.d.ts +34 -0
  105. package/dist/src/cli/render.d.ts +22 -0
  106. package/dist/src/cli/sandbox.d.ts +51 -0
  107. package/dist/src/cli/scaffold.d.ts +79 -0
  108. package/dist/src/cli/setup-adapter.d.ts +137 -0
  109. package/dist/src/cli/setup-adapter.js +38 -4
  110. package/dist/src/cli/setup-adapter.js.map +1 -1
  111. package/dist/src/cli/setup-channel.d.ts +117 -0
  112. package/dist/src/cli/setup-checkpoint.d.ts +57 -0
  113. package/dist/src/cli/setup-common.d.ts +275 -0
  114. package/dist/src/cli/setup-flow.d.ts +287 -0
  115. package/dist/src/cli/setup-service.d.ts +96 -0
  116. package/dist/src/cli/setup.d.ts +202 -0
  117. package/dist/src/cli/style.d.ts +320 -0
  118. package/dist/src/cli/token.d.ts +39 -0
  119. package/dist/src/cli/up.d.ts +155 -0
  120. package/dist/src/cli/up.js +4 -2
  121. package/dist/src/cli/up.js.map +1 -1
  122. package/dist/src/cli/usage.d.ts +37 -0
  123. package/dist/src/cli/values.d.ts +40 -0
  124. package/dist/src/cli/vault.d.ts +59 -0
  125. package/dist/src/cli/vault.js +2 -2
  126. package/dist/src/cli/vault.js.map +1 -1
  127. package/dist/src/cli/verb-registry.d.ts +76 -0
  128. package/dist/src/cli/verb-registry.js +176 -8
  129. package/dist/src/cli/verb-registry.js.map +1 -1
  130. package/dist/src/cli/wordmark.d.ts +31 -0
  131. package/dist/src/cli/wordmark.js +2 -2
  132. package/dist/src/codex/doctor.d.ts +13 -0
  133. package/dist/src/codex/doctor.js +41 -0
  134. package/dist/src/codex/doctor.js.map +1 -0
  135. package/dist/src/codex/manifest.d.ts +49 -0
  136. package/dist/src/codex/manifest.js +103 -0
  137. package/dist/src/codex/manifest.js.map +1 -0
  138. package/dist/src/codex/templates.d.ts +41 -0
  139. package/dist/src/codex/templates.js +319 -0
  140. package/dist/src/codex/templates.js.map +1 -0
  141. package/dist/src/codex/trust.d.ts +19 -0
  142. package/dist/src/codex/trust.js +183 -0
  143. package/dist/src/codex/trust.js.map +1 -0
  144. package/dist/src/codex/workspace-plan.d.ts +131 -0
  145. package/dist/src/codex/workspace-plan.js +561 -0
  146. package/dist/src/codex/workspace-plan.js.map +1 -0
  147. package/dist/src/core/actor.d.ts +2 -0
  148. package/dist/src/core/actor.js +5 -0
  149. package/dist/src/core/actor.js.map +1 -0
  150. package/dist/src/core/advance-cycle.d.ts +170 -0
  151. package/dist/src/core/agents-md.d.ts +276 -0
  152. package/dist/src/core/apply-patch.d.ts +49 -0
  153. package/dist/src/core/apply-patch.js +266 -0
  154. package/dist/src/core/apply-patch.js.map +1 -0
  155. package/dist/src/core/attest.d.ts +420 -0
  156. package/dist/src/core/attest.js +13 -1
  157. package/dist/src/core/attest.js.map +1 -1
  158. package/dist/src/core/audit.d.ts +492 -0
  159. package/dist/src/core/budgets.d.ts +238 -0
  160. package/dist/src/core/checkpoint.d.ts +500 -0
  161. package/dist/src/core/child-env.d.ts +88 -0
  162. package/dist/src/core/clock.d.ts +52 -0
  163. package/dist/src/core/command-class.d.ts +543 -0
  164. package/dist/src/core/command-class.js +43 -8
  165. package/dist/src/core/command-class.js.map +1 -1
  166. package/dist/src/core/coverage-sources/adapter.d.ts +40 -0
  167. package/dist/src/core/coverage-sources/gh.d.ts +48 -0
  168. package/dist/src/core/coverage-sources/git.d.ts +101 -0
  169. package/dist/src/core/coverage.d.ts +217 -0
  170. package/dist/src/core/credential-spec.d.ts +72 -0
  171. package/dist/src/core/dark-session.d.ts +331 -0
  172. package/dist/src/core/decision-refusal.d.ts +185 -0
  173. package/dist/src/core/env-file.d.ts +450 -0
  174. package/dist/src/core/execute.d.ts +858 -0
  175. package/dist/src/core/execute.js +44 -6
  176. package/dist/src/core/execute.js.map +1 -1
  177. package/dist/src/core/frontmatter.d.ts +78 -0
  178. package/dist/src/core/gate-window.d.ts +312 -0
  179. package/dist/src/core/gate.d.ts +1364 -0
  180. package/dist/src/core/gate.js +68 -13
  181. package/dist/src/core/gate.js.map +1 -1
  182. package/dist/src/core/git-run.d.ts +73 -0
  183. package/dist/src/core/harness-version.d.ts +157 -0
  184. package/dist/src/core/harness-version.js +2 -1
  185. package/dist/src/core/harness-version.js.map +1 -1
  186. package/dist/src/core/harness-wait.d.ts +55 -0
  187. package/dist/src/core/head-retry.d.ts +107 -0
  188. package/dist/src/core/instance.d.ts +253 -0
  189. package/dist/src/core/intake-limits.d.ts +247 -0
  190. package/dist/src/core/jcs.d.ts +52 -0
  191. package/dist/src/core/journal.d.ts +144 -0
  192. package/dist/src/core/live-draw.d.ts +436 -0
  193. package/dist/src/core/log-reconcile.d.ts +89 -0
  194. package/dist/src/core/log-subscribe.d.ts +36 -0
  195. package/dist/src/core/log-subscribe.js +162 -0
  196. package/dist/src/core/log-subscribe.js.map +1 -0
  197. package/dist/src/core/log.d.ts +278 -0
  198. package/dist/src/core/loop.d.ts +274 -0
  199. package/dist/src/core/loop.js +11 -0
  200. package/dist/src/core/loop.js.map +1 -1
  201. package/dist/src/core/md-fence.d.ts +41 -0
  202. package/dist/src/core/money.d.ts +147 -0
  203. package/dist/src/core/payload-census.d.ts +74 -0
  204. package/dist/src/core/payload-store.d.ts +175 -0
  205. package/dist/src/core/payload.d.ts +71 -0
  206. package/dist/src/core/policy-diff.d.ts +292 -0
  207. package/dist/src/core/policy-diff.js +27 -4
  208. package/dist/src/core/policy-diff.js.map +1 -1
  209. package/dist/src/core/policy-expectations.d.ts +199 -0
  210. package/dist/src/core/policy-explain.d.ts +150 -0
  211. package/dist/src/core/policy-explain.js +31 -3
  212. package/dist/src/core/policy-explain.js.map +1 -1
  213. package/dist/src/core/policy-load.d.ts +527 -0
  214. package/dist/src/core/policy-load.js +15 -3
  215. package/dist/src/core/policy-load.js.map +1 -1
  216. package/dist/src/core/policy-match.d.ts +281 -0
  217. package/dist/src/core/policy-match.js +20 -9
  218. package/dist/src/core/policy-match.js.map +1 -1
  219. package/dist/src/core/policy-proposal.d.ts +265 -0
  220. package/dist/src/core/prompt-layout.d.ts +221 -0
  221. package/dist/src/core/protected-path-guard.d.ts +453 -0
  222. package/dist/src/core/protected-path-guard.js +514 -35
  223. package/dist/src/core/protected-path-guard.js.map +1 -1
  224. package/dist/src/core/registration.d.ts +25 -0
  225. package/dist/src/core/reindex.d.ts +99 -0
  226. package/dist/src/core/sampler.d.ts +313 -0
  227. package/dist/src/core/sandbox.d.ts +290 -0
  228. package/dist/src/core/seal.d.ts +165 -0
  229. package/dist/src/core/state.d.ts +505 -0
  230. package/dist/src/core/task-file.d.ts +185 -0
  231. package/dist/src/core/telegram-config.d.ts +93 -0
  232. package/dist/src/core/token.d.ts +409 -0
  233. package/dist/src/core/token.js +21 -38
  234. package/dist/src/core/token.js.map +1 -1
  235. package/dist/src/core/validate.d.ts +138 -0
  236. package/dist/src/core/values.d.ts +137 -0
  237. package/dist/src/core/vault.d.ts +291 -0
  238. package/dist/src/core/verified-snapshot.d.ts +204 -0
  239. package/dist/src/core/verify.d.ts +336 -0
  240. package/dist/src/core/version.d.ts +8 -0
  241. package/dist/src/core/wysiwys.d.ts +370 -0
  242. package/dist/src/daemon/advance-child.d.ts +39 -0
  243. package/dist/src/daemon/advance.d.ts +466 -0
  244. package/dist/src/daemon/audit.d.ts +87 -0
  245. package/dist/src/daemon/daemon.d.ts +1180 -0
  246. package/dist/src/daemon/dark-session.d.ts +64 -0
  247. package/dist/src/daemon/draw-child.d.ts +36 -0
  248. package/dist/src/daemon/draw.d.ts +154 -0
  249. package/dist/src/daemon/git-evidence.d.ts +173 -0
  250. package/dist/src/daemon/git-evidence.js +1 -1
  251. package/dist/src/daemon/projection.d.ts +180 -0
  252. package/dist/src/daemon/prune.d.ts +207 -0
  253. package/dist/src/mcp/http.d.ts +113 -0
  254. package/dist/src/mcp/server.d.ts +265 -0
  255. package/dist/src/mcp/server.js +9 -1
  256. package/dist/src/mcp/server.js.map +1 -1
  257. package/docs/adapter-api.md +106 -0
  258. package/docs/cli-reference.md +389 -36
  259. package/docs/codex-enforced-session.md +30 -0
  260. package/package.json +12 -2
  261. package/schema/codex-instance.schema.json +82 -0
  262. package/schema/event.schema.json +2 -1
  263. package/schema/fixtures/codex-instance/invalid/unpinned-codex-version.json +40 -0
  264. package/schema/fixtures/codex-instance/valid/canonical.json +40 -0
  265. package/schema/policy.schema.json +21 -1
  266. package/templates/codex/README.md +9 -0
@@ -0,0 +1,492 @@
1
+ /**
2
+ * The audit lifecycle (SPEC.md §5.2, §9.1, §12): `audit.sampled` →
3
+ * `audit.reviewed` → (on a denial) `reconciliation.required` →
4
+ * `reconciliation.satisfied`.
5
+ *
6
+ * ## What a retrospective denial can and cannot do (amended SPEC.md §5.2, APRV-127)
7
+ *
8
+ * The action already happened. The runtime cannot undo it, and any design that
9
+ * pretended otherwise would be lying to the person who denied it. What it can do
10
+ * is **oblige and record**: a denial appends an obligation naming the action, its
11
+ * class, and the review that denied, and the obligation stays open, and loud,
12
+ * until a HUMAN says it is discharged. Which obligation depends on whether the
13
+ * action was declared reversible — see {@link obligationFor}, including why a
14
+ * self-reported `reversible` may choose the shape and can never remove one.
15
+ *
16
+ * This is also why the autonomy split has a floor. `supervised-retro` refuses an
17
+ * action declaring `reversible: false` (`core/policy-match.ts`'s irreversibility
18
+ * floor pushes it to `manual`), because retrospective review of something that
19
+ * cannot be undone is regret with a paper trail. The floor is a floor and not a
20
+ * proof: it acts on a claim the acting party makes about itself, so it catches
21
+ * the honest declaration and never the lie. The obligation machinery here is what
22
+ * remains when the floor did not apply and the review said no anyway.
23
+ *
24
+ * Two halves, deliberately asymmetric:
25
+ *
26
+ * - **Sampling is the runtime's.** It is mechanical, it is retrospective, and it
27
+ * escalates a supervised action that already executed into a human's review
28
+ * queue. {@link sampleSupervised} appends `audit.sampled` with a `system:`
29
+ * actor. Selection is `core/sampler.ts`'s keyed HMAC, so no agent can predict
30
+ * or steer it.
31
+ * - **Review is a human's.** {@link reviewSample} appends `audit.reviewed` and
32
+ * refuses any actor that is not `human:<id>`, by the same rule that governs
33
+ * `grant`, `reject`, `revoke`, `policy attest`, and `execution resolve`. A
34
+ * runtime that could mark its own samples reviewed would be a supervision
35
+ * backlog that empties itself, which is precisely the failure the sampled
36
+ * backlog exists to make visible.
37
+ *
38
+ * ## Eligibility is derived, never self-reported (global invariant 4)
39
+ *
40
+ * A candidate is an `execution.started` record whose action's class, as recorded
41
+ * in the `task.registered` declaration the log already holds, resolves to
42
+ * `supervised` under the live policy. Two things follow, both load-bearing:
43
+ *
44
+ * - the class comes from the registration record rather than from the
45
+ * `execution.started` payload, and the autonomy comes from re-running
46
+ * `core/policy-match.ts` rather than from any field claiming an autonomy. No
47
+ * payload key an authoring party writes can move an action out of the
48
+ * candidate set;
49
+ * - eligibility is recomputed from the log every sweep, so it does not depend on
50
+ * any remembered flag, and a candidate cannot exclude itself by writing
51
+ * anything into its own event.
52
+ *
53
+ * The manual path is excluded because it never resolves `supervised`: a manual
54
+ * action's start is authorized by a token and its class resolves `manual`, so it
55
+ * is not a candidate and is not double-counted.
56
+ *
57
+ * ## Exactly once, without remembering anything
58
+ *
59
+ * Every sweep re-derives the whole candidate set and subtracts the subjects the
60
+ * log already carries an `audit.sampled` for, keyed on the subject record's
61
+ * `hash` (unique per record by construction, and stable across re-reads). A
62
+ * daemon restart, a second daemon, and a manual sweep all converge on the same
63
+ * set, and none of them can double-sample. Every append passes `expectedHead`,
64
+ * so a check made against one log cannot land on another (SPEC.md §11.1
65
+ * invariant 5).
66
+ *
67
+ * ## Time
68
+ *
69
+ * `audit.*` is gate-typed (SPEC.md §8), so no public function here takes a `ts`:
70
+ * the timestamp is read from the injected clock at the write boundary, and the
71
+ * party being audited does not author the clock it is judged by.
72
+ */
73
+ import { type ClockOptions } from "./clock.js";
74
+ import { type AppendError, type EventRecord } from "./log.js";
75
+ import { type PolicyLoadResult } from "./policy-load.js";
76
+ import { type Sampler } from "./sampler.js";
77
+ import type { ValidateOptions } from "./validate.js";
78
+ /**
79
+ * SPEC.md §8: the sampler is the runtime, so its actor is `system:`. Distinct
80
+ * from `system:gate` (expiries) and `system:daemon` (envelope drift) so a reader
81
+ * can tell which part of the runtime spoke without reading the payload.
82
+ */
83
+ export declare const AUDIT_ACTOR = "system:audit";
84
+ /**
85
+ * The closed set of audit refusal codes. Frozen public API in the same sense the
86
+ * gate's and the executor's are: a supervisor branches on these strings, so
87
+ * adding one is a spec change and renaming one is a breaking change.
88
+ */
89
+ export declare const AUDIT_REFUSAL_CODES: readonly [
90
+ /** Review was attempted by an actor that is not `human:<id>`. */
91
+ "actor-not-human",
92
+ /** No `audit.sampled` record matches the subject named. */
93
+ "not-sampled",
94
+ /** That sample already has a later `audit.reviewed`. */
95
+ "already-reviewed",
96
+ /** An action key with more than one unreviewed sample; name the seq instead. */
97
+ "ambiguous-subject",
98
+ /** No `reconciliation.required` record at the seq named (APRV-127). */
99
+ "not-obliged",
100
+ /** That obligation already has a `reconciliation.satisfied` (APRV-127). */
101
+ "already-satisfied",
102
+ /**
103
+ * A verb that requires a reason was given none. Two shapes, one code: a
104
+ * reconciliation satisfied with a blank note (APRV-127), and a review whose
105
+ * `reaction` is `loved` or `disliked` with a blank note (APRV-239). Both are
106
+ * an assertion nobody can check, and both are evaluated after the actor check
107
+ * and before the log is read.
108
+ */
109
+ "note-required",
110
+ /**
111
+ * A review that says the action should not have happened and that the human
112
+ * liked or loved it (APRV-239). Evaluated beside `note-required`, before the
113
+ * log is read; nothing is appended.
114
+ *
115
+ * The two fields point opposite ways and only one of them is enforcement, so
116
+ * the safe reading is not "believe the verdict and drop the grade": a record
117
+ * carrying both would be read by a person later as evidence of whichever half
118
+ * suited them, and by an agent as a signal that a denial is survivable if the
119
+ * operator is pleased. The reviewer is asked to say which they meant.
120
+ */
121
+ "reaction-conflicts-verdict",
122
+ /**
123
+ * A `gated-revert` obligation whose satisfaction names no completed revert
124
+ * (APRV-127). The obligation is to undo the action THROUGH THE GATE, and the
125
+ * evidence of that is an `execution.completed` in this same log.
126
+ */
127
+ "revert-required",
128
+ /**
129
+ * The denial was recorded and its obligation was not (APRV-127). The log is
130
+ * NOT inconsistent — `audit.reviewed` stands and says `denied` — but the
131
+ * obligation it should have created is missing and must be created by
132
+ * reviewing again once the head settles.
133
+ */
134
+ "obligation-not-appended",
135
+ /** The log could not be read, or holds a line that is not a record. */
136
+ "log-unreadable",
137
+ /** The log's final line is unterminated (a crashed write). */
138
+ "log-torn-tail",
139
+ /** The chain does not verify; nothing is derived from an untrustworthy log. */
140
+ "log-corrupt",
141
+ /** The append itself failed; `append` carries the underlying error. */
142
+ "append-failed"];
143
+ export type AuditRefusalCode = (typeof AUDIT_REFUSAL_CODES)[number];
144
+ export interface AuditRefusal {
145
+ ok: false;
146
+ code: AuditRefusalCode;
147
+ message: string;
148
+ /** The seq of the record that produced the refusal, when there is one. */
149
+ seq?: number;
150
+ /** The underlying append error, when `code` is `append-failed`. */
151
+ append?: AppendError;
152
+ }
153
+ /** Options shared by the audit verbs. No `ts`: `audit.*` is gate-typed. */
154
+ export interface AuditOptions extends ClockOptions, ValidateOptions {
155
+ /** Policy location, with `loadPolicy`'s semantics. */
156
+ policy?: {
157
+ dir?: string;
158
+ file?: string;
159
+ };
160
+ /** Environment the sampling secret is read from. Injected by tests. */
161
+ env?: NodeJS.ProcessEnv;
162
+ }
163
+ /** One supervised execution eligible for retrospective review. */
164
+ export interface AuditCandidate {
165
+ /** `seq` of the `execution.started` record. */
166
+ seq: number;
167
+ /** `hash` of that record: the HMAC input and the dedupe key. */
168
+ hash: string;
169
+ ts: string;
170
+ actionKey: string;
171
+ task: string | null;
172
+ /** The class the registration declared, re-resolved to `supervised`. */
173
+ class: string;
174
+ }
175
+ /**
176
+ * Every `execution.started` whose action resolves `supervised` under `load`, in
177
+ * log order.
178
+ *
179
+ * Pure: no I/O, no clock, no environment. Records with no action key, and keys
180
+ * no `task.registered` record declares, are skipped rather than guessed at — an
181
+ * undeclared key has no class, and inventing one would put a fact in the sample
182
+ * that nobody wrote.
183
+ */
184
+ export declare function supervisedExecutions(records: readonly EventRecord[], load: PolicyLoadResult): AuditCandidate[];
185
+ /** One `audit.sampled` record, with the review that closes it (or none). */
186
+ export interface SampledSubject {
187
+ /** `seq` of the `audit.sampled` record itself. */
188
+ seq: number;
189
+ ts: string;
190
+ actionKey: string | null;
191
+ task: string | null;
192
+ /** `hash` of the subject record the sample named, when it named one. */
193
+ subjectHash: string | null;
194
+ /** `seq` of the subject record the sample named, when it named one. */
195
+ subjectSeq: number | null;
196
+ /** `seq` of the later `audit.reviewed`, or `null` when still open. */
197
+ reviewedSeq: number | null;
198
+ }
199
+ /**
200
+ * Every `audit.sampled` in the log, each tagged with the `audit.reviewed` that
201
+ * closes it.
202
+ *
203
+ * A review closes a sample only when it comes **after** it in the chain and
204
+ * names the same action key. An earlier review is a review of an earlier sample;
205
+ * treating it as covering this one would silently empty the backlog, which is
206
+ * exactly the failure a sampled-audit backlog exists to prevent. This mirrors
207
+ * `channels/render-queue.ts`'s matching rule, so the CLI and the queue
208
+ * projection never disagree about what is outstanding.
209
+ */
210
+ export declare function sampledSubjects(records: readonly EventRecord[]): SampledSubject[];
211
+ /** Samples with no later review, oldest first. The human's audit backlog. */
212
+ export declare function openSamples(records: readonly EventRecord[]): SampledSubject[];
213
+ /** The candidates a sweep would sample now: eligible, selected, not yet sampled. */
214
+ export declare function pendingSamples(records: readonly EventRecord[], load: PolicyLoadResult, sampler: Sampler): AuditCandidate[];
215
+ /** One `audit.sampled` this sweep appended. */
216
+ export interface SampleAppended {
217
+ record: EventRecord;
218
+ candidate: AuditCandidate;
219
+ }
220
+ export interface SampleSweepResult {
221
+ ok: true;
222
+ /** The sampler in force. Carries the reason when sampling is off. */
223
+ sampler: Sampler;
224
+ appended: SampleAppended[];
225
+ /** Appends that were refused. Reported, never retried in place. */
226
+ refusals: AuditRefusal[];
227
+ }
228
+ export type SampleResult = SampleSweepResult | AuditRefusal;
229
+ /**
230
+ * Sample every supervised execution the log does not yet carry an
231
+ * `audit.sampled` for, and append one event per selection.
232
+ *
233
+ * Re-reads the verified log before every append so the head each
234
+ * compare-and-append is made against is the head the decision was made from. A
235
+ * `head-moved` refusal is collected and reported rather than retried: only the
236
+ * next sweep, which re-derives the whole question from the log as it now is,
237
+ * knows whether the candidate is still a candidate.
238
+ *
239
+ * Returns `ok` with an empty `appended` list when sampling is disabled; the
240
+ * reason travels on `sampler`. A disabled sampler is not a refusal, because
241
+ * nothing was asked for and nothing failed. See `core/sampler.ts` on why a
242
+ * missing secret disables sampling rather than escalating everything.
243
+ */
244
+ export declare function sampleSupervised(logPath: string, cwd: string, options?: AuditOptions): SampleResult;
245
+ /** How a caller named the sample to review. */
246
+ export type SubjectRef = {
247
+ kind: "seq";
248
+ seq: number;
249
+ } | {
250
+ kind: "action-key";
251
+ actionKey: string;
252
+ };
253
+ /** Parse the CLI's one positional: a bare integer is a seq, anything else a key. */
254
+ export declare function parseSubjectRef(text: string): SubjectRef;
255
+ export interface ReviewResult {
256
+ ok: true;
257
+ record: EventRecord;
258
+ subject: SampledSubject;
259
+ /**
260
+ * The `reconciliation.required` this review created, on a denial only
261
+ * (APRV-127). `null` for an `ok` verdict, which obliges nothing.
262
+ */
263
+ obligation: EventRecord | null;
264
+ }
265
+ /** What a reviewer concluded (amended SPEC.md §5.2, APRV-127). */
266
+ export type ReviewVerdict = "ok" | "denied";
267
+ /**
268
+ * The graded reaction a review or a grant MAY carry (amended SPEC.md §5.2,
269
+ * APRV-237/APRV-239), in the order the schema's enum lists them: worst to best.
270
+ *
271
+ * **This is not enforcement, and it lives here rather than in an enforcement
272
+ * module for that reason.** `verdict` is the field the runtime acts on;
273
+ * `reaction` is what the human thought, travelling human-to-agent, and SPEC.md
274
+ * §11.1 invariant 10 says no routing, class matching, sampling, budget, token,
275
+ * gate-window or execution decision may read it. `tests/values-inert.test.ts`
276
+ * enforces that as a static guard over the enforcement modules, which is why the
277
+ * tuple is exported from `core/audit.ts` (the projection's home) and imported by
278
+ * the surfaces that show it, and by nothing that decides.
279
+ *
280
+ * The vocabulary is closed on purpose. Four words are a grade a person can give
281
+ * in one tap and an agent can read back without interpretation; an open field
282
+ * would accumulate synonyms across surfaces until "meh" and "indifferent" were
283
+ * two different signals. The absence of the field is absence: it is never read
284
+ * as `indifferent`, which is a thing a person had to actually say.
285
+ */
286
+ export declare const REACTIONS: readonly ["disliked", "indifferent", "liked", "loved"];
287
+ export type Reaction = (typeof REACTIONS)[number];
288
+ /** Whether a string is one of the four graded reactions. Used at the CLI boundary. */
289
+ export declare function isReaction(value: string): value is Reaction;
290
+ /** The shape a denial's obligation takes. */
291
+ export type Obligation = "gated-revert" | "policy-finding";
292
+ export interface ReviewOptions extends AuditOptions {
293
+ /**
294
+ * The verdict. Defaults to `"ok"`: a review whose caller says nothing about
295
+ * what it concluded records the observation it always did, and the ABSENCE of
296
+ * a verdict is never read as a denial.
297
+ */
298
+ verdict?: ReviewVerdict;
299
+ /**
300
+ * The graded reaction, recorded beside the verdict when the reviewer gave one
301
+ * (APRV-239). Omitted means omitted: nothing is written, and no reader may
302
+ * substitute `indifferent` for a person who said nothing.
303
+ */
304
+ reaction?: Reaction;
305
+ }
306
+ /**
307
+ * The obligation a denial creates, chosen by the action's DECLARED
308
+ * reversibility (amended SPEC.md §5.2/§7, APRV-127).
309
+ *
310
+ * - `reversible: true` → `gated-revert`. The action can be undone, so the
311
+ * obligation is to undo it *through the gate*: the revert is itself a
312
+ * side-effecting action, and routing it through the gate is what closes the
313
+ * loop inside the log rather than inside a promise.
314
+ * - `reversible: false` → `policy-finding`. There is nothing to revert. What is
315
+ * left is the finding that the class should not have permitted this without a
316
+ * human, and the sanctioned response is tightening the class; the obligation
317
+ * is the review of that tightening.
318
+ * - **declared nothing** → `policy-finding`, the same as `false`. This is the
319
+ * fail-closed direction, and the reason is worth stating: obliging a revert of
320
+ * an action nobody said could be reverted would record an obligation that may
321
+ * be impossible to discharge, and an impossible obligation is one that gets
322
+ * closed dishonestly. A policy finding is always dischargeable, and it is the
323
+ * heavier of the two: it puts the CLASS on the table rather than one action.
324
+ *
325
+ * ## Self-reported, and only ever in the safe direction
326
+ *
327
+ * `reversible` is written by the party whose action is under review, so global
328
+ * invariant 4 applies: it may never reduce scrutiny. Here it does not. It
329
+ * selects the SHAPE of an obligation that exists either way; it cannot remove
330
+ * one, delay one, or decide whether the denial happened. The one thing a false
331
+ * `reversible: true` buys is a revert obligation instead of a policy finding —
332
+ * and the revert obligation is the one whose satisfaction this runtime checks
333
+ * against the log (`revert-required`), so the lie makes the claimant's own exit
334
+ * harder rather than easier.
335
+ */
336
+ export declare function obligationFor(reversible: boolean | null): Obligation;
337
+ /**
338
+ * Append `audit.reviewed` for one open sample.
339
+ *
340
+ * HUMAN-ONLY, by the same rule as `grant`/`reject`/`revoke`: the whole content
341
+ * of the event is that a person looked. An agent- or system-authored review
342
+ * would be the party under oversight closing its own audit item, and a backlog
343
+ * that can be emptied by the thing it supervises measures nothing.
344
+ *
345
+ * No attestation is required, for the reason `execution resolve` states: review
346
+ * records an observation and exercises no policy authority. It authorizes
347
+ * nothing, spends no budget, and mints no token.
348
+ *
349
+ * `--note` is optional and recorded verbatim when present. It is not mandatory
350
+ * the way `execution resolve`'s is, because that verb writes an *outcome* the
351
+ * runtime does not know while this one writes only "seen".
352
+ */
353
+ export declare function reviewSample(logPath: string, ref: SubjectRef, actor: string, note: string | null, options?: ReviewOptions): ReviewResult | AuditRefusal;
354
+ /** One `reconciliation.required`, with the satisfaction that closes it. */
355
+ export interface ReconciliationObligation {
356
+ /** `seq` of the `reconciliation.required` record. */
357
+ seq: number;
358
+ ts: string;
359
+ actionKey: string;
360
+ task: string | null;
361
+ class: string;
362
+ /** `seq` of the `audit.reviewed` that denied. */
363
+ reviewSeq: number;
364
+ obligation: Obligation;
365
+ reversible: boolean | null;
366
+ /** `seq` of the `reconciliation.satisfied`, or `null` while still open. */
367
+ satisfiedSeq: number | null;
368
+ }
369
+ /**
370
+ * Every reconciliation obligation the log carries, each tagged with the
371
+ * satisfaction that closes it.
372
+ *
373
+ * A satisfaction closes an obligation only when it comes **after** it in the
374
+ * chain and names its seq — the same "later, and names it" rule
375
+ * {@link sampledSubjects} applies to reviews, and for the same reason: a
376
+ * backlog that an earlier record could close is a backlog that empties itself.
377
+ *
378
+ * A malformed `reconciliation.required` (no action key, no class, no usable
379
+ * obligation shape) is SKIPPED rather than guessed at. Such a record cannot
380
+ * reach the log through this runtime — the event schema requires all three — so
381
+ * one that is there arrived some other way, and inventing the missing field
382
+ * would put a fact in the backlog that nobody wrote.
383
+ */
384
+ export declare function reconciliationObligations(records: readonly EventRecord[]): ReconciliationObligation[];
385
+ /** Obligations with no later satisfaction, oldest first. The loud backlog. */
386
+ export declare function openObligations(records: readonly EventRecord[]): ReconciliationObligation[];
387
+ export interface SatisfyResult {
388
+ ok: true;
389
+ record: EventRecord;
390
+ obligation: ReconciliationObligation;
391
+ }
392
+ /** What a human says they did to discharge an obligation. */
393
+ export interface SatisfyInput {
394
+ /** What was done. REQUIRED — see the event schema on why. */
395
+ note: string;
396
+ /**
397
+ * For a `gated-revert` obligation, the action key of the revert. The log must
398
+ * carry an `execution.completed` for it.
399
+ */
400
+ revertActionKey?: string;
401
+ }
402
+ /**
403
+ * Close one reconciliation obligation.
404
+ *
405
+ * **HUMAN-ONLY**, by the same rule that governs `grant`, `reject`, `revoke` and
406
+ * `audit.reviewed`, and enforced twice: here in code and again by the event
407
+ * schema. The entire content of the record is that a person judged the
408
+ * obligation discharged. A runtime that could satisfy its own obligations would
409
+ * be a reconciliation backlog that empties itself, which is precisely the
410
+ * silence an unreconciled denial exists to break.
411
+ *
412
+ * Two checks beyond the actor, and both are about evidence rather than trust:
413
+ *
414
+ * - **A note is required.** `audit.reviewed` may record only "seen"; this record
415
+ * asserts that something was DONE, and an assertion nobody described is one no
416
+ * auditor can check.
417
+ * - **A `gated-revert` obligation requires a completed revert IN THIS LOG.** The
418
+ * obligation was "undo it through the gate", so the discharge is a gated
419
+ * action that ran, and the runtime looks for its `execution.completed` rather
420
+ * than accepting a sentence saying it happened. That is what closes the loop
421
+ * in the chain. A `policy-finding` obligation has no such artifact — the
422
+ * sanctioned response is a policy amendment, which is a separate human
423
+ * ceremony with its own `policy.updated` record — so the note is the discharge
424
+ * there, and the note is required.
425
+ *
426
+ * No attestation is required, for the reason `audit review` and `execution
427
+ * resolve` state: this record exercises no policy authority, authorizes nothing,
428
+ * spends no budget, and mints no token.
429
+ */
430
+ export declare function satisfyObligation(logPath: string, obligationSeq: number, actor: string, input: SatisfyInput, options?: AuditOptions): SatisfyResult | AuditRefusal;
431
+ /** Which human gesture an entry came from. */
432
+ export type FeedbackSource = "review" | "decision";
433
+ /**
434
+ * One thing a human said about an action, as `approval feedback` prints it.
435
+ *
436
+ * Everything here is derived from records the caller already verified. Nothing
437
+ * is looked up in a file, no policy is resolved, and no clock is read: two
438
+ * callers handed the same records get the same list in the same order.
439
+ */
440
+ export interface FeedbackEntry {
441
+ /** `seq` of the record carrying the reaction or note. */
442
+ seq: number;
443
+ ts: string;
444
+ source: FeedbackSource;
445
+ /** `audit.reviewed` or `approval.granted`, spelled as the log spells it. */
446
+ event: string;
447
+ /** The human who said it: the actor on the record itself. */
448
+ actor: string;
449
+ /** The graded reaction, or `null` when the record carries none. */
450
+ reaction: Reaction | null;
451
+ /** The human's words, or `null` when there were none. */
452
+ note: string | null;
453
+ /** The enforcement field, on a review only. `null` on a grant. */
454
+ verdict: ReviewVerdict | null;
455
+ actionKey: string | null;
456
+ task: string | null;
457
+ /** The class from the `task.registered` declaration, never from a payload claim. */
458
+ class: string | null;
459
+ /**
460
+ * The agent whose work this is about, NOT the human who reacted.
461
+ *
462
+ * Sourced from the `task.registered` record that declared the action key, and
463
+ * failing that from the `execution.started` that ran it. Never from a payload
464
+ * field: an actor is a property of who appended a record, and a self-reported
465
+ * one would let the party under oversight choose whose feedback this reads as
466
+ * (SPEC.md §11.1 invariant 4).
467
+ */
468
+ agentActor: string | null;
469
+ /** `seq` of the `audit.sampled` a review closed, or `null` on a grant. */
470
+ sampleSeq: number | null;
471
+ }
472
+ /**
473
+ * Every reaction and every note a human wrote about an action, oldest first.
474
+ *
475
+ * The HUMAN-TO-AGENT direction of the log (amended SPEC.md §5.2). Two sources,
476
+ * because a human says what they thought in two places: at the gate, answering a
477
+ * request (`approval.granted`), and afterwards, reviewing a sampled action
478
+ * (`audit.reviewed`). Rejections and revocations carry no reaction at all, so
479
+ * they are not a source: their reason IS their note, and the record already says
480
+ * what happened.
481
+ *
482
+ * **An entry with neither a reaction nor a note is omitted.** A grant with no
483
+ * words is the ordinary case, most grants are, and listing thousands of them as
484
+ * blank rows would bury the handful where somebody actually said something.
485
+ * Absence of feedback is not feedback.
486
+ *
487
+ * Reads only the records it is given, and callers pass VERIFIED records: this is
488
+ * a projection in the sense the rest of this module uses the word, it writes
489
+ * nothing, decides nothing, and no enforcement path reads it (SPEC.md §11.1
490
+ * invariant 10).
491
+ */
492
+ export declare function humanFeedback(records: readonly EventRecord[]): FeedbackEntry[];