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,623 @@
1
+ /**
2
+ * The channel plugin contract (SPEC.md §9, §10.3, §10.4, §11).
3
+ *
4
+ * A channel is **transport**. It takes a render-ready request from the runtime,
5
+ * puts it in front of a human, and hands back the gesture the human made. It
6
+ * holds no state (§10.3: "Decisions become log events; channels hold no state"),
7
+ * it never reads the log, it never writes the log, and it never decides
8
+ * anything. Everything a channel could get wrong about *authority* is therefore
9
+ * removed from a channel by construction:
10
+ *
11
+ * - **It cannot invent a field.** Every displayable datum on {@link
12
+ * ChannelRequest} is a {@link TaggedField}: either `computed` (the runtime
13
+ * derived it, and `source` names the derivation) or `claimed` (the party under
14
+ * oversight authored it, and `author` names them). There is no untagged
15
+ * member, so "render this string" is not a thing a channel can do without
16
+ * first knowing which side of the verification boundary the string came from.
17
+ * SPEC.md §9 and §10.3 both say the same sentence twice: rendering claimed
18
+ * fields with the visual authority of computed fields is a conformance
19
+ * failure. This type makes the mistake require deliberate effort.
20
+ * - **It cannot approve anything.** {@link ChannelDecision} is a *report* of a
21
+ * human gesture. Turning it into an `approval.granted` is
22
+ * {@link recordChannelDecision}'s job, and that function does exactly one
23
+ * thing: call `core/gate.ts`'s human-only `decide()`. Every gate rule — human
24
+ * actor, attestation on grant, TTL lapse, budget re-check, compare-and-append,
25
+ * idempotency — applies unchanged, because there is no second path.
26
+ * - **It cannot hold a secret.** A grant mints a single-use execution token.
27
+ * {@link recordChannelDecision} returns it to *its caller* (the runtime) in a
28
+ * field that is deliberately not part of {@link DecisionOutcome}, which is the
29
+ * only value handed back to the channel. A channel that logged its own
30
+ * outcomes would log nothing sensitive.
31
+ *
32
+ * ## Manual requests and the full payload (SPEC.md §10.4)
33
+ *
34
+ * > For `manual` actions, channels MUST present the full payload or a faithful
35
+ * > rendering of it, clearly delineated from any agent-written summary, before
36
+ * > collecting a decision.
37
+ *
38
+ * {@link createChannelRequest} refuses to build a `manual` request whose
39
+ * `fullPayload` is null. A channel therefore cannot be handed a manual request
40
+ * that has nothing to show; the failure surfaces at construction, inside the
41
+ * runtime, rather than as a channel silently rendering a summary alone.
42
+ *
43
+ * ## What is deliberately not here
44
+ *
45
+ * No I/O beyond {@link recordChannelDecision}'s delegation to the gate; no
46
+ * clock; no rendering. Building a {@link ChannelRequest} from a log is
47
+ * `channels/tagging.ts`, batching is `channels/batch.ts`, and the shared
48
+ * pass/fail suite every channel implementation must survive is
49
+ * `channels/conformance.ts`.
50
+ */
51
+ import type { AttestationStatus } from "../core/attest.js";
52
+ import type { BudgetVerdict } from "../core/budgets.js";
53
+ import { type DecideOptions, type GateRefusal } from "../core/gate.js";
54
+ import type { EventRecord } from "../core/log.js";
55
+ import type { Autonomy } from "../core/policy-load.js";
56
+ import type { Provenance } from "../core/policy-match.js";
57
+ import { type RequestState } from "../core/state.js";
58
+ /**
59
+ * The canonical `source` values the runtime tagger stamps on computed fields.
60
+ *
61
+ * `TaggedField`'s `source` is typed `string` rather than this union on purpose:
62
+ * an adapter or a satellite runtime may derive a field from a derivation this
63
+ * repo has not named, and forcing it to lie about the provenance would be worse
64
+ * than admitting a name we do not recognize. These are the names
65
+ * `channels/tagging.ts` uses, and the ones a reviewer should expect to see.
66
+ */
67
+ export declare const COMPUTED_SOURCES: readonly [
68
+ /** Read from a verified log record (`core/state.ts`). */
69
+ "log",
70
+ /** Resolved against the attested policy (`core/policy-match.ts`, `policy-explain.ts`). */
71
+ "policy-match",
72
+ /** Evaluated by `core/budgets.ts` at display time. */
73
+ "budgets",
74
+ /** Compared against the latest attestation (`core/attest.ts`). */
75
+ "attestation",
76
+ /**
77
+ * Loaded and validated by `core/policy-load.ts` at display time (APRV-109) —
78
+ * the advisory on an attestation prompt, recomputed from the live policy
79
+ * bytes rather than read back off the proposal that recorded one.
80
+ */
81
+ "policy-load",
82
+ /** Recomputed from the payload bytes and checked against the bound hash. */
83
+ "payload-binding",
84
+ /**
85
+ * Re-derived from the hash-checked payload bytes by `core/command-class.ts`
86
+ * — the same module whose answer selected the class (APRV-143).
87
+ *
88
+ * Distinct from `payload-binding`, which names the hash agreement itself.
89
+ * This names the classifier's reading OF those bytes, which is a second
90
+ * derivation over the same material and can be wrong in ways the hash cannot
91
+ * catch: a channel that labelled it `payload-binding` would be borrowing the
92
+ * binding's authority for an answer the binding does not cover.
93
+ */
94
+ "classifier",
95
+ /** Arithmetic on the display-time instant (TTL remaining). */
96
+ "clock"];
97
+ export type ComputedSource = (typeof COMPUTED_SOURCES)[number];
98
+ /**
99
+ * One displayable datum, labelled with which side of the verification boundary
100
+ * it came from (SPEC.md §9).
101
+ *
102
+ * `computed`: the runtime derived it from the log, the policy, or the payload
103
+ * bytes. `source` names *which* derivation, so a channel can say "class:
104
+ * financial.spend (policy)" rather than implying the runtime vouches for a
105
+ * string an agent typed.
106
+ *
107
+ * `claimed`: the party under oversight authored it. `author` is their actor id.
108
+ * SPEC.md §11's ratchet applies to every one of these: they may raise scrutiny
109
+ * and never lower it, so a channel may render them prominently, but never as
110
+ * fact.
111
+ */
112
+ export type TaggedField<T> = {
113
+ kind: "computed";
114
+ value: T;
115
+ source: string;
116
+ } | {
117
+ kind: "claimed";
118
+ value: T;
119
+ author: string;
120
+ };
121
+ /**
122
+ * The words that ride beside a rendered `gloss`, on every channel that renders
123
+ * one (APRV-144 for Telegram, APRV-197 for the terminal).
124
+ *
125
+ * Belt and braces with the `(author)` parenthetical: a reader skimming a wall
126
+ * of lines sees the word "model" inside the sentence they are about to believe,
127
+ * not only in the small print at the end of it. It lives here, next to the
128
+ * field it labels, because two channels rendering the same field under two
129
+ * different labels is how one of them ends up looking authoritative.
130
+ */
131
+ export declare const GLOSS_UNVERIFIED_SUFFIX = "(model, unverified)";
132
+ /**
133
+ * What a person is told, in one line, when the gate would not take their
134
+ * decision (APRV-235).
135
+ *
136
+ * One function, every surface. A Telegram message edit, a web page and a
137
+ * terminal are three renderings of one fact, and before this they were three
138
+ * sentences — or, on the terminal that watched a `policy-drift` refusal on
139
+ * 2026-09-02, one sentence in a place the person who had tapped could not see.
140
+ * A human who taps on their phone and then reads the operator's terminal should
141
+ * find the same words in both, because the alternative is deciding which one to
142
+ * believe.
143
+ *
144
+ * Written to the approver, not to the log: it says what happened to THEIR
145
+ * answer and what, if anything, they should do next. The machine-readable fact
146
+ * is `code`, which every caller has and none of them should be paraphrasing.
147
+ * The wording of the first three is APRV-206's, moved here unchanged.
148
+ */
149
+ export declare function refusedDecisionLine(code: string): string;
150
+ /** Tag `value` as runtime-derived, naming the derivation that produced it. */
151
+ export declare function computed<T>(value: T, source: ComputedSource | string): TaggedField<T>;
152
+ /** Tag `value` as authored by `author`, the party under oversight. */
153
+ export declare function claimed<T>(value: T, author: string): TaggedField<T>;
154
+ /** Is `value` a well-formed {@link TaggedField}? Used by the conformance suite. */
155
+ export declare function isTaggedField(value: unknown): value is TaggedField<unknown>;
156
+ /**
157
+ * The payload bytes a manual approval binds to, plus a faithful rendering of
158
+ * them (SPEC.md §10.4).
159
+ *
160
+ * `hash` is recomputed here from `value` by `core/payload.ts` and checked
161
+ * against the `payload_hash` the log recorded, which is what makes this a
162
+ * *computed* field rather than one more agent claim: material that does not
163
+ * hash to the bound value never reaches a channel at all.
164
+ *
165
+ * `truncated` is the honest admission that `text` is shorter than `value`. A
166
+ * truncated rendering is still legal for a single request (a channel may offer
167
+ * "show more"), but it is what {@link ../channels/batch.js assembleBatch}
168
+ * refuses to fold into a batch — see the B7 operationalization there.
169
+ */
170
+ export interface PayloadRendering {
171
+ /** The concrete payload value, exactly as it will be executed. */
172
+ value: unknown;
173
+ /** A faithful text rendering of `value`, for channels that display text. */
174
+ text: string;
175
+ /** SHA-256/JCS of `value`, recomputed; equal to the log's `payload_hash`. */
176
+ hash: string;
177
+ /** `text` omits part of `value`. */
178
+ truncated: boolean;
179
+ }
180
+ /** Where the request sits in the hash chain (SPEC.md §8, §9 "chain position"). */
181
+ export interface ChainPosition {
182
+ /** `seq` of the `approval.requested` record. */
183
+ seq: number;
184
+ /** That record's hash. */
185
+ hash: string;
186
+ /** `seq` of the log head at the moment this request was built. */
187
+ head_seq: number;
188
+ }
189
+ /**
190
+ * A pending manual request, ready to render — and nothing else.
191
+ *
192
+ * Every member is a {@link TaggedField}. That is the point of the type: a
193
+ * channel iterating this object cannot reach a bare value, so the question
194
+ * "computed or claimed?" is answered before the question "how do I display it?"
195
+ * can be asked. Adding an untagged member to this interface would be the defect
196
+ * this whole module exists to prevent.
197
+ */
198
+ export interface ChannelRequest {
199
+ /** The action's idempotency key (`core/gate.ts`). */
200
+ action_key: TaggedField<string>;
201
+ /** The Backlog.md task id, or `null` when the log records none. */
202
+ task: TaggedField<string | null>;
203
+ /** The declared side-effect class, as the log records it (SPEC.md §7). */
204
+ class: TaggedField<string>;
205
+ /** Autonomy resolved against the attested policy at display time. */
206
+ autonomy: TaggedField<Autonomy>;
207
+ /** How that resolution was reached (`rule`, `default`, `fail-closed`, …). */
208
+ provenance: TaggedField<Provenance>;
209
+ /** The agent's cost estimate. Claimed: it is a promise, not a measurement. */
210
+ est_cost_usd: TaggedField<number>;
211
+ /** The agent's one-line description of the effect. Claimed. */
212
+ summary: TaggedField<string | null>;
213
+ /** `route.rationale`, when the log carries one. Claimed. */
214
+ rationale?: TaggedField<string>;
215
+ /** `route.confidence`, when the log carries one. Claimed, and never a gate. */
216
+ confidence?: TaggedField<number>;
217
+ /**
218
+ * What a compound shell command does, segment by segment (APRV-144):
219
+ * `git add … · git commit · git push origin main:records-…`.
220
+ *
221
+ * **Computed**, and from the payload bytes alone: it is derived by
222
+ * `core/command-class.ts`'s own tokenizer, the one whose reading chose the
223
+ * class, so a channel showing it cannot describe a command differently from
224
+ * the module that gated it. Present only for a command-shaped payload the
225
+ * tokenizer can read; absent, never guessed, for every other shape.
226
+ */
227
+ command_breakdown?: TaggedField<string>;
228
+ /**
229
+ * The protected path that selected `policy.edit`, and the rule that matched
230
+ * it (APRV-143): `.github/workflows/ci.yml (rule protected-path)`.
231
+ *
232
+ * **Computed.** For a shell payload the classifier is re-run over the bound
233
+ * command; for a file-tool payload `isProtectedPath` is re-run over the bound
234
+ * target. Either way the answer is recomputed from the bytes the approval
235
+ * binds to rather than read off a claim, which is what puts it on this side
236
+ * of the boundary. Absent when no protected path selected the class.
237
+ */
238
+ protected_path?: TaggedField<string>;
239
+ /**
240
+ * A one-sentence description of the action, written by a language model
241
+ * (APRV-144). **Claimed, and unverified twice over**: nothing checks it, and
242
+ * its author is not even a party the log knows about.
243
+ *
244
+ * Attached at RENDER time by a channel listener and by nothing else. The gate
245
+ * never sees it, the payload hash does not cover it, the log does not record
246
+ * it, and no code path anywhere branches on its content — the only thing that
247
+ * turns on it is whether the line appears. It is a reading aid whose absence
248
+ * costs nothing but the seconds a human spends parsing the command
249
+ * themselves, which is why every failure mode of producing one resolves to
250
+ * absence.
251
+ *
252
+ * A tagger never sets this. `channels/tagging.ts` derives fields from the
253
+ * log, the policy and the bound bytes; a model's sentence is none of those,
254
+ * and putting it on the runtime side of the boundary would be the exact
255
+ * defect SPEC.md §9 exists to prevent.
256
+ */
257
+ gloss?: TaggedField<string>;
258
+ /**
259
+ * What a proposed policy amendment changes about class resolution, in
260
+ * before -> after form (APRV-109).
261
+ *
262
+ * **Computed**, by `core/policy-diff.ts` over two policy documents whose
263
+ * bytes the runtime hashed itself: the live file, and a baseline accepted
264
+ * only when its own SHA-256 equals the latest attestation. Present on an
265
+ * attestation prompt and absent everywhere else.
266
+ *
267
+ * A prompt that carried only a hash would ask a human to sign for sixty-four
268
+ * characters. The rule this field exists to enforce is in
269
+ * `core/policy-proposal.ts`: a diff too large for the channel REFUSES the
270
+ * ceremony to the terminal path rather than arriving here truncated.
271
+ */
272
+ policy_diff?: TaggedField<string>;
273
+ /**
274
+ * Whether a proposed policy loads, and what breaks when it does not
275
+ * (APRV-109).
276
+ *
277
+ * **Computed**, by `core/policy-load.ts` over the same bytes. It is on the
278
+ * prompt because a policy that does not load fails closed to all-manual for
279
+ * every class, and the incident that produced `policy amend` was an operator
280
+ * attesting bytes whose consequences nobody had shown them.
281
+ */
282
+ policy_load?: TaggedField<string>;
283
+ /** The content binding recorded on `approval.requested` (SPEC.md §6.2). */
284
+ payload_hash: TaggedField<string>;
285
+ /**
286
+ * The delivery address for the token this grant would mint (APRV-105):
287
+ * `sealed to x25519:<first 16 hex of the key's digest>`.
288
+ *
289
+ * **Computed**, and present only when the request published a
290
+ * `token_recipient_key` — that is, only under `token_delivery: sealed`. It is
291
+ * on this side of the boundary because the runtime reads the key off the
292
+ * verified log and digests it here; the requester supplies a key, not this
293
+ * line, and cannot make the line say anything else.
294
+ *
295
+ * It is shown because an approver is entitled to know that granting will put a
296
+ * readable token in the requesting process's hands rather than only on this
297
+ * screen. It changes nothing about the decision's authority: the key ADDRESSES
298
+ * and does not AUTHORIZE, so a grant still mints, still binds to the payload,
299
+ * and is still single-use. Absent for every manual-delivery request, which is
300
+ * every request until an operator amends the policy.
301
+ */
302
+ token_delivery?: TaggedField<string>;
303
+ /**
304
+ * The bytes the approval binds to (SPEC.md §10.4). Non-null is enforced at
305
+ * construction for `manual` autonomy: see {@link createChannelRequest}.
306
+ */
307
+ fullPayload: TaggedField<PayloadRendering | null>;
308
+ /** Budget verdicts as of the display instant (`core/budgets.ts`). */
309
+ budgets: TaggedField<BudgetVerdict[]>;
310
+ /** Whether the live policy still matches the attestation (`core/attest.ts`). */
311
+ attestation: TaggedField<AttestationStatus>;
312
+ /** The `approval.requested` timestamp, assigned by the runtime (SPEC.md §8). */
313
+ requested_ts: TaggedField<string>;
314
+ /** Milliseconds of TTL left, or `null` when the policy declares no TTL. */
315
+ ttl_remaining_ms: TaggedField<number | null>;
316
+ /**
317
+ * One line telling the approver how old this question is and how long an
318
+ * answer will still reach anyone (APRV-106):
319
+ *
320
+ * ```
321
+ * requested 32 min ago · requester waits until 09:23 UTC
322
+ * requested 32 min ago · expires 09:23 UTC
323
+ * ```
324
+ *
325
+ * **Computed.** Both halves are arithmetic on instants read from the
326
+ * verified log against the display instant: the age from the
327
+ * `approval.requested` record's runtime-assigned `ts`, and the deadline from
328
+ * either the policy's TTL or, for a request that declared one, the
329
+ * requester's own `wait_until`.
330
+ *
331
+ * That second source is the only place a requester-authored value reaches
332
+ * this line, and it is safe in the direction that matters. `wait_until` is
333
+ * always EARLIER than the TTL (a process that waits longer than the TTL is
334
+ * waiting for something that has already lapsed), so it can only make the
335
+ * question look more urgent, never less. It bounds nothing, charges nothing
336
+ * and gates nothing — SPEC.md §11.1's ratchet holds, because the only
337
+ * scrutiny it can move is upward.
338
+ *
339
+ * The line exists because the incident behind APRV-106 was a human answering
340
+ * a question thirty minutes after its asker had stopped listening. The
341
+ * withdrawal removes that question from the queue; this tells an approver who
342
+ * is looking at the message right now how much time is actually left.
343
+ */
344
+ waiting: TaggedField<string>;
345
+ /** Position in the hash chain. */
346
+ chain: TaggedField<ChainPosition>;
347
+ /** The derived approval state; always `requested` for a live pending item. */
348
+ state: TaggedField<RequestState>;
349
+ }
350
+ /** Refusals {@link createChannelRequest} can return. Frozen, per §11.1(6). */
351
+ export declare const CHANNEL_REQUEST_REFUSAL_CODES: readonly [
352
+ /** A `manual` request was built with no full payload to present (§10.4). */
353
+ "manual-payload-required",
354
+ /** A member arrived that is not a {@link TaggedField}. */
355
+ "untagged-field"];
356
+ export type ChannelRequestRefusalCode = (typeof CHANNEL_REQUEST_REFUSAL_CODES)[number];
357
+ export interface ChannelRequestRefusal {
358
+ ok: false;
359
+ code: ChannelRequestRefusalCode;
360
+ message: string;
361
+ }
362
+ export type CreateChannelRequestResult = {
363
+ ok: true;
364
+ request: ChannelRequest;
365
+ } | ChannelRequestRefusal;
366
+ /**
367
+ * Build a {@link ChannelRequest}, enforcing the two invariants a type alone
368
+ * cannot.
369
+ *
370
+ * 1. **§10.4**: a `manual` request MUST carry a full payload. A manual request
371
+ * with `fullPayload.value === null` is refused `manual-payload-required` and
372
+ * no object is produced, so no channel can be handed one.
373
+ * 2. **§9**: every member is tagged. The interface says so, but a JavaScript
374
+ * caller (a satellite runtime, a test, an adapter compiled from looser
375
+ * sources) can still hand over a bare value; that is refused
376
+ * `untagged-field` rather than passed through to a renderer that would
377
+ * display it with unearned authority.
378
+ */
379
+ export declare function createChannelRequest(fields: ChannelRequest): CreateChannelRequestResult;
380
+ /**
381
+ * Every displayable member of `request` is a {@link TaggedField}.
382
+ *
383
+ * The runtime half of "untagged fields are unrepresentable": the type says it
384
+ * at compile time, this says it at run time, and `channels/conformance.ts`
385
+ * calls it on both the request handed to a channel and the split the channel
386
+ * reports having rendered. Throws (rather than returning) because it is an
387
+ * assertion helper used inside test suites.
388
+ */
389
+ export declare function assertTagged(request: ChannelRequest): void;
390
+ /**
391
+ * A set of pending requests presented under one human gesture (SPEC.md §10.3).
392
+ *
393
+ * The log never batches: each member gets its own `approval.granted` /
394
+ * `approval.rejected`. `deliveryId` is assigned by the channel at `notify` and
395
+ * is what ties those separate events back to the one gesture.
396
+ */
397
+ export interface ChannelBatch {
398
+ requests: ChannelRequest[];
399
+ /** Assigned by the channel at `notify`; absent until then. */
400
+ deliveryId?: DeliveryId;
401
+ }
402
+ /** A channel's identifier for one delivery (message id, prompt id, …). */
403
+ export type DeliveryId = string;
404
+ /**
405
+ * The event payload field carrying a batch's channel delivery id (SPEC.md
406
+ * §10.3: each event carries "the batch's channel delivery id in its payload").
407
+ *
408
+ * First-class since APRV-38: `decide()` takes `batchDeliveryId` and writes this
409
+ * field on `approval.granted` / `approval.rejected`, and the event schema
410
+ * constrains it. What it replaced is described at
411
+ * {@link BATCH_DELIVERY_NOTE_PREFIX}.
412
+ */
413
+ export declare const BATCH_DELIVERY_ID_FIELD = "batch_delivery_id";
414
+ /**
415
+ * The legacy `note` prefix that carried a batch delivery id before APRV-38.
416
+ *
417
+ * ## The dual-read window (amended SPEC.md §10.3)
418
+ *
419
+ * APRV-22 had no gate parameter and no schema entry to work with, so the id
420
+ * rode inside the one caller-controlled payload field there was: `note`, whose
421
+ * first line read `batch_delivery_id=<id>`, optionally followed by a newline
422
+ * and the human's own words. Logs written by those builds exist and are
423
+ * append-only, so the encoding cannot be migrated away: it can only stop being
424
+ * written. That is exactly what happens now. {@link recordChannelDecision}
425
+ * writes the first-class field and leaves `note` to the human, while
426
+ * {@link batchDeliveryIdOf} reads both and prefers the field. Readers MUST
427
+ * accept both encodings for the life of v0.1.
428
+ *
429
+ * {@link batchNote} is retained so a caller with a v0.1-era log to reproduce
430
+ * can still produce the old shape. Nothing in this repository calls it on the
431
+ * write path.
432
+ */
433
+ export declare const BATCH_DELIVERY_NOTE_PREFIX = "batch_delivery_id=";
434
+ /**
435
+ * Encode `batchDeliveryId` (and an optional human note) into a `note` string.
436
+ *
437
+ * The pre-APRV-38 encoding, kept for round-trip fidelity with logs that carry
438
+ * it. New decisions use the first-class payload field instead.
439
+ */
440
+ export declare function batchNote(batchDeliveryId: DeliveryId, note?: string): string;
441
+ /**
442
+ * The batch delivery id recorded on `record`, or `null` for a unit decision.
443
+ *
444
+ * Reads both encodings (see {@link BATCH_DELIVERY_NOTE_PREFIX}), preferring the
445
+ * first-class `batch_delivery_id` field. The fallback is what keeps audit
446
+ * granularity intact across a log that spans the change: a batch grant written
447
+ * last month and one written today resolve to the same id here.
448
+ */
449
+ export declare function batchDeliveryIdOf(record: EventRecord): DeliveryId | null;
450
+ /** A human gesture, as reported by a channel. Never an authorization. */
451
+ export interface ChannelDecision {
452
+ action_key: string;
453
+ /**
454
+ * What the human did. `revoke` is deliberately absent: withdrawing a standing
455
+ * authorization is a considered act performed against the log through the
456
+ * CLI, not something to collect from an inline button next to "Approve".
457
+ */
458
+ decision: "grant" | "reject";
459
+ /** The human's free-text note, if the channel collected one. */
460
+ note?: string;
461
+ /** The delivery this gesture answered. */
462
+ deliveryId: DeliveryId;
463
+ /** Set when the delivery was a batch (SPEC.md §10.3). */
464
+ batchDeliveryId?: DeliveryId;
465
+ }
466
+ /**
467
+ * What the runtime tells the channel became of a reported decision.
468
+ *
469
+ * Note what is *not* here: the raw execution token. A grant mints one
470
+ * (`core/token.ts`), and it is returned to the runtime by
471
+ * {@link recordChannelDecision} in {@link ChannelDecisionResult.token}, never in
472
+ * this value. A channel learns that a grant landed, not how to spend it.
473
+ */
474
+ export type DecisionOutcome = {
475
+ ok: true;
476
+ action_key: string;
477
+ decision: "grant" | "reject";
478
+ state: RequestState;
479
+ /** The appended `approval.granted` / `approval.rejected` record. */
480
+ record: EventRecord;
481
+ /**
482
+ * A single-use execution token reached THIS surface (grant only). Never
483
+ * its value.
484
+ *
485
+ * False on a grant that minted one and withheld it: a harness-executed
486
+ * request mints none at all (APRV-106), and a self-delivered one seals it
487
+ * to the requester's own address and hands this caller no copy
488
+ * (APRV-211). Neither is a grant without authorization; both are grants
489
+ * whose token was never this surface's to hold.
490
+ */
491
+ tokenIssued: boolean;
492
+ } | GateRefusal;
493
+ /** A channel's self-report. `detail` explains a `false`; SPEC.md §10.2 polls it. */
494
+ export interface ChannelHealth {
495
+ ok: boolean;
496
+ detail?: string;
497
+ }
498
+ /**
499
+ * The plugin interface every channel implements (SPEC.md §10.3's
500
+ * `notify(request) -> delivery_id`, `poll()/webhook() -> decision`).
501
+ *
502
+ * `onDecision` is the poll/webhook half inverted: the channel discovers the
503
+ * gesture however it likes (a prompt returning, an HTTP callback, a Telegram
504
+ * button) and calls the registered handler. The handler is the runtime's, and
505
+ * what it does is call {@link recordChannelDecision}. A channel that wanted to
506
+ * write the log itself would have to import the gate, and the conformance suite
507
+ * would not care — but the review would.
508
+ */
509
+ export interface Channel {
510
+ /** Stable identifier: `cli`, `web`, `telegram`. Recorded for audit. */
511
+ name: string;
512
+ /** Present a request (or a batch) to a human. Returns the delivery id. */
513
+ notify(request: ChannelRequest | ChannelBatch): Promise<DeliveryId> | DeliveryId;
514
+ /** Register the runtime's decision handler. Called once, before `notify`. */
515
+ onDecision(handler: (decision: ChannelDecision) => DecisionOutcome): void;
516
+ /** Liveness/config self-report. */
517
+ health(): ChannelHealth;
518
+ /**
519
+ * Annotate a delivery whose request is no longer answerable, and take away
520
+ * whatever gesture it offered (APRV-106). Optional.
521
+ *
522
+ * A withdrawn request leaves every queue by derivation — it is no longer
523
+ * `requested`, and that one predicate is what every channel builds its queue
524
+ * from — so a channel that implements nothing here is still correct: it will
525
+ * never present the request again. What it will not do is fix the message
526
+ * ALREADY on the approver's phone, which still shows two buttons for a
527
+ * question nobody is waiting on. Push channels should implement this;
528
+ * pull channels (`cli`, `web`) re-render from the queue every time and have
529
+ * nothing to retract.
530
+ *
531
+ * Best effort by contract: the runtime calls it and carries on. It collects
532
+ * no gesture, returns no decision, and touches no log.
533
+ */
534
+ retract?(deliveryId: DeliveryId, reason: string): Promise<void> | void;
535
+ }
536
+ /** One field as a channel actually rendered it. */
537
+ export interface RenderedField {
538
+ /** The {@link ChannelRequest} member this came from. */
539
+ field: string;
540
+ /** How the channel presented it. Must equal the field's own `kind`. */
541
+ kind: "computed" | "claimed";
542
+ /** What the human saw. */
543
+ text: string;
544
+ }
545
+ /** What a channel says it put in front of a human, for one request. */
546
+ export interface RenderedRequest {
547
+ action_key: string;
548
+ fields: RenderedField[];
549
+ /**
550
+ * The full-payload region, verbatim and delineated from the summary
551
+ * (SPEC.md §10.4). `null` means the channel rendered no payload — legal only
552
+ * off the manual path.
553
+ */
554
+ fullPayloadText: string | null;
555
+ /** Set when this request was rendered as part of a batch. */
556
+ batchDeliveryId?: DeliveryId;
557
+ }
558
+ /**
559
+ * A channel that can be asked what it rendered, for tests only.
560
+ *
561
+ * Conformance cannot read a Telegram message or a terminal's scrollback, so a
562
+ * channel under test reports its own rendering split and the suite checks it
563
+ * against the tagged request. That is an honesty-assuming check — a channel
564
+ * could lie about what it rendered — and it is worth having anyway: the failure
565
+ * mode it catches is a channel that *believes* a claimed field is computed,
566
+ * which is a code path, not a lie. Implementations should build
567
+ * {@link lastRendered} from the same function that builds the real output, not
568
+ * from a parallel description of it.
569
+ */
570
+ export interface TestableChannel extends Channel {
571
+ /** The most recent rendering: one entry per request, batch members included. */
572
+ lastRendered(): RenderedRequest[];
573
+ }
574
+ /** Is this channel introspectable by the conformance suite? */
575
+ export declare function isTestableChannel(channel: Channel): channel is TestableChannel;
576
+ /** Who is recording. A `human:` id; the gate refuses anything else. */
577
+ export interface ChannelActorOptions {
578
+ /** The approver's identity (`human:<id>`; SPEC.md §11 — config-declared). */
579
+ actor: string;
580
+ /** The channel that collected the gesture, for audit context in the note. */
581
+ channel?: string;
582
+ }
583
+ /**
584
+ * {@link recordChannelDecision}'s result: the channel-safe outcome, plus the
585
+ * secret the channel must never see.
586
+ */
587
+ export interface ChannelDecisionResult {
588
+ /** Hand this back to the channel. Carries no token. */
589
+ outcome: DecisionOutcome;
590
+ /**
591
+ * The raw single-use execution token, on a successful grant only (APRV-17).
592
+ * The runtime keeps it; the log holds only its SHA-256. Splitting it out of
593
+ * `outcome` is what lets a channel's `onDecision` handler return the outcome
594
+ * without ever holding the token.
595
+ */
596
+ token?: string;
597
+ }
598
+ /**
599
+ * Turn a reported gesture into a log event — by calling the gate, and by doing
600
+ * nothing else.
601
+ *
602
+ * There is no second decision path in this codebase and this function is not
603
+ * one: it is a translation from {@link ChannelDecision} to `decide()`'s
604
+ * arguments. Every gate rule therefore still holds, and every gate refusal code
605
+ * still surfaces verbatim in {@link DecisionOutcome}:
606
+ *
607
+ * - `actor-not-human` — the configured actor is not `human:…`. A channel cannot
608
+ * escalate itself by claiming to be one, because the actor comes from the
609
+ * runtime's configuration, not from the {@link ChannelDecision}.
610
+ * - `already-decided` — the duplicate-callback case every push channel has
611
+ * (a Telegram button pressed twice, a webhook redelivered). It refuses, and
612
+ * the log keeps the first human answer.
613
+ * - `expired`, `budget-exceeded`, `policy-not-attested`, `append-failed`
614
+ * (`head-moved`) — unchanged, all of them.
615
+ *
616
+ * `batchDeliveryId`, when present, is passed to the gate as such and lands in
617
+ * the event payload as `batch_delivery_id` (amended SPEC.md §10.3). The human's
618
+ * `note` is left carrying the human's words alone. See
619
+ * {@link BATCH_DELIVERY_NOTE_PREFIX} for the encoding this replaced and for the
620
+ * dual-read window readers stay inside for the life of v0.1.
621
+ */
622
+ export declare function recordChannelDecision(logPath: string, decision: ChannelDecision, actorOptions: ChannelActorOptions, gateOptions?: DecideOptions): ChannelDecisionResult;
623
+ export declare function recordAttestationDecision(logPath: string, decision: ChannelDecision, actorOptions: ChannelActorOptions, gateOptions?: DecideOptions): ChannelDecisionResult;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The channel-side facade over the canonical renderer (APRV-119).
3
+ *
4
+ * Everything this module used to hold — the email view (APRV-100), the diff view
5
+ * (APRV-124), the command view and its injective escape marking (APRV-126), the
6
+ * classifier-derived breakdown and protected-path lines (APRV-143, APRV-144) —
7
+ * now lives in `core/wysiwys.ts`, absorbed into {@link canonicalRender}. It
8
+ * moved because the gate consults it: `core/gate.ts` computes the
9
+ * `display_hash` a request records at the write boundary from the same function
10
+ * the channels render with, and core cannot import channels.
11
+ *
12
+ * What is left here is the one function that needs a channel type, plus the
13
+ * re-exports that keep every existing import path working. A channel imports
14
+ * this; nothing else does.
15
+ */
16
+ import type { PayloadRendering } from "./contract.js";
17
+ export * from "../core/wysiwys.js";
18
+ /**
19
+ * The text a channel puts inside its payload region (SPEC.md §10.4, §9).
20
+ *
21
+ * For a whole payload this is {@link canonicalRender}'s text verbatim, so the
22
+ * three channels present the same reading of the same bytes and the log's
23
+ * `display_hash` names it. Claimed material — the summary, the estimate, the
24
+ * rationale, a model's gloss — is never inside this region; each channel renders
25
+ * it above, under its own claimed heading.
26
+ *
27
+ * A **truncated** rendering has no canonical form and does not get one. The
28
+ * tagging layer cut `text` short at the caller's `maxPayloadChars`, so the bytes
29
+ * on screen are not the bytes the token will execute, and giving a partial
30
+ * payload the canonical block's authority is exactly the substitution WYSIWYS
31
+ * forbids. The pre-existing truncated text is returned unchanged, the channel's
32
+ * own "TRUNCATED — do not grant on it" marker still surrounds it, and
33
+ * `channels/batch.ts` still refuses to fold such a member into a batch.
34
+ */
35
+ export declare function payloadRegionText(rendering: PayloadRendering, actionClass: string): string;