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.
- package/README.md +584 -553
- package/SPEC.md +42 -13
- package/dist/src/adapters/agentmail.d.ts +426 -0
- package/dist/src/adapters/agentmail.js +2 -2
- package/dist/src/adapters/conformance.d.ts +149 -0
- package/dist/src/adapters/contract.d.ts +628 -0
- package/dist/src/adapters/contract.js +110 -16
- package/dist/src/adapters/contract.js.map +1 -1
- package/dist/src/adapters/email.d.ts +324 -0
- package/dist/src/adapters/env-passphrase.d.ts +93 -0
- package/dist/src/adapters/public.d.ts +11 -0
- package/dist/src/adapters/public.js +11 -0
- package/dist/src/adapters/public.js.map +1 -0
- package/dist/src/adapters/registry.d.ts +59 -0
- package/dist/src/adapters/registry.js +2 -1
- package/dist/src/adapters/registry.js.map +1 -1
- package/dist/src/adapters/smtp.d.ts +213 -0
- package/dist/src/adapters/vault-provider.d.ts +114 -0
- package/dist/src/adapters/vault-provider.js +3 -3
- package/dist/src/adapters/zzz.d.ts +66 -0
- package/dist/src/adapters/zzz.js +299 -0
- package/dist/src/adapters/zzz.js.map +1 -0
- package/dist/src/channels/batch.d.ts +109 -0
- package/dist/src/channels/cli.d.ts +193 -0
- package/dist/src/channels/conformance.d.ts +92 -0
- package/dist/src/channels/contract.d.ts +623 -0
- package/dist/src/channels/payload-view.d.ts +35 -0
- package/dist/src/channels/render-queue.d.ts +149 -0
- package/dist/src/channels/tagging.d.ts +196 -0
- package/dist/src/channels/telegram.d.ts +1832 -0
- package/dist/src/channels/web.d.ts +341 -0
- package/dist/src/cli/adapter.d.ts +90 -0
- package/dist/src/cli/adapter.js +25 -15
- package/dist/src/cli/adapter.js.map +1 -1
- package/dist/src/cli/amend.d.ts +59 -0
- package/dist/src/cli/args.d.ts +43 -0
- package/dist/src/cli/attest.d.ts +41 -0
- package/dist/src/cli/audit-card.d.ts +62 -0
- package/dist/src/cli/audit.d.ts +59 -0
- package/dist/src/cli/channel-telegram.d.ts +806 -0
- package/dist/src/cli/channel-web.d.ts +131 -0
- package/dist/src/cli/channel.d.ts +71 -0
- package/dist/src/cli/checkpoint-tap.d.ts +169 -0
- package/dist/src/cli/codex.d.ts +2 -0
- package/dist/src/cli/codex.js +172 -0
- package/dist/src/cli/codex.js.map +1 -0
- package/dist/src/cli/coverage.d.ts +61 -0
- package/dist/src/cli/daemon.d.ts +120 -0
- package/dist/src/cli/doctor.d.ts +129 -0
- package/dist/src/cli/doctor.js +119 -5
- package/dist/src/cli/doctor.js.map +1 -1
- package/dist/src/cli/env.d.ts +65 -0
- package/dist/src/cli/execute.d.ts +202 -0
- package/dist/src/cli/exit-codes.d.ts +73 -0
- package/dist/src/cli/feedback.d.ts +60 -0
- package/dist/src/cli/gate-window.d.ts +40 -0
- package/dist/src/cli/gate.d.ts +68 -0
- package/dist/src/cli/git-scope.d.ts +190 -0
- package/dist/src/cli/gloss-attach.d.ts +85 -0
- package/dist/src/cli/gloss-codex-child.d.ts +9 -0
- package/dist/src/cli/gloss-codex.d.ts +24 -0
- package/dist/src/cli/gloss-options.d.ts +42 -0
- package/dist/src/cli/gloss.d.ts +265 -0
- package/dist/src/cli/help.d.ts +103 -0
- package/dist/src/cli/help.js +173 -51
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/hook-codex.d.ts +78 -0
- package/dist/src/cli/hook-codex.js +167 -0
- package/dist/src/cli/hook-codex.js.map +1 -0
- package/dist/src/cli/hook.d.ts +331 -0
- package/dist/src/cli/hook.js +186 -80
- package/dist/src/cli/hook.js.map +1 -1
- package/dist/src/cli/import.d.ts +35 -0
- package/dist/src/cli/init.d.ts +84 -0
- package/dist/src/cli/init.js +2 -2
- package/dist/src/cli/init.js.map +1 -1
- package/dist/src/cli/instructions.d.ts +23 -0
- package/dist/src/cli/journal.d.ts +41 -0
- package/dist/src/cli/log-advance.d.ts +287 -0
- package/dist/src/cli/log-advance.js +102 -11
- package/dist/src/cli/log-advance.js.map +1 -1
- package/dist/src/cli/log-anchor.d.ts +176 -0
- package/dist/src/cli/log-checkpoint.d.ts +22 -0
- package/dist/src/cli/log-sync.d.ts +243 -0
- package/dist/src/cli/log-verbs.d.ts +16 -0
- package/dist/src/cli/log-verbs.js +7 -1
- package/dist/src/cli/log-verbs.js.map +1 -1
- package/dist/src/cli/long-help.d.ts +70 -0
- package/dist/src/cli/main.d.ts +77 -0
- package/dist/src/cli/main.js +155 -5
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/cli/mcp.d.ts +52 -0
- package/dist/src/cli/paths.d.ts +56 -0
- package/dist/src/cli/payload.d.ts +58 -0
- package/dist/src/cli/policy.d.ts +43 -0
- package/dist/src/cli/preflight.d.ts +363 -0
- package/dist/src/cli/preflight.js +294 -7
- package/dist/src/cli/preflight.js.map +1 -1
- package/dist/src/cli/progress.d.ts +78 -0
- package/dist/src/cli/prompt.d.ts +209 -0
- package/dist/src/cli/quickstart.d.ts +46 -0
- package/dist/src/cli/quickstart.js +297 -0
- package/dist/src/cli/quickstart.js.map +1 -0
- package/dist/src/cli/records.d.ts +34 -0
- package/dist/src/cli/render.d.ts +22 -0
- package/dist/src/cli/sandbox.d.ts +51 -0
- package/dist/src/cli/scaffold.d.ts +79 -0
- package/dist/src/cli/setup-adapter.d.ts +137 -0
- package/dist/src/cli/setup-adapter.js +38 -4
- package/dist/src/cli/setup-adapter.js.map +1 -1
- package/dist/src/cli/setup-channel.d.ts +117 -0
- package/dist/src/cli/setup-checkpoint.d.ts +57 -0
- package/dist/src/cli/setup-common.d.ts +275 -0
- package/dist/src/cli/setup-flow.d.ts +287 -0
- package/dist/src/cli/setup-service.d.ts +96 -0
- package/dist/src/cli/setup.d.ts +202 -0
- package/dist/src/cli/style.d.ts +320 -0
- package/dist/src/cli/token.d.ts +39 -0
- package/dist/src/cli/up.d.ts +155 -0
- package/dist/src/cli/up.js +4 -2
- package/dist/src/cli/up.js.map +1 -1
- package/dist/src/cli/usage.d.ts +37 -0
- package/dist/src/cli/values.d.ts +40 -0
- package/dist/src/cli/vault.d.ts +59 -0
- package/dist/src/cli/vault.js +2 -2
- package/dist/src/cli/vault.js.map +1 -1
- package/dist/src/cli/verb-registry.d.ts +76 -0
- package/dist/src/cli/verb-registry.js +176 -8
- package/dist/src/cli/verb-registry.js.map +1 -1
- package/dist/src/cli/wordmark.d.ts +31 -0
- package/dist/src/cli/wordmark.js +2 -2
- package/dist/src/codex/doctor.d.ts +13 -0
- package/dist/src/codex/doctor.js +41 -0
- package/dist/src/codex/doctor.js.map +1 -0
- package/dist/src/codex/manifest.d.ts +49 -0
- package/dist/src/codex/manifest.js +103 -0
- package/dist/src/codex/manifest.js.map +1 -0
- package/dist/src/codex/templates.d.ts +41 -0
- package/dist/src/codex/templates.js +319 -0
- package/dist/src/codex/templates.js.map +1 -0
- package/dist/src/codex/trust.d.ts +19 -0
- package/dist/src/codex/trust.js +183 -0
- package/dist/src/codex/trust.js.map +1 -0
- package/dist/src/codex/workspace-plan.d.ts +131 -0
- package/dist/src/codex/workspace-plan.js +561 -0
- package/dist/src/codex/workspace-plan.js.map +1 -0
- package/dist/src/core/actor.d.ts +2 -0
- package/dist/src/core/actor.js +5 -0
- package/dist/src/core/actor.js.map +1 -0
- package/dist/src/core/advance-cycle.d.ts +170 -0
- package/dist/src/core/agents-md.d.ts +276 -0
- package/dist/src/core/apply-patch.d.ts +49 -0
- package/dist/src/core/apply-patch.js +266 -0
- package/dist/src/core/apply-patch.js.map +1 -0
- package/dist/src/core/attest.d.ts +420 -0
- package/dist/src/core/attest.js +13 -1
- package/dist/src/core/attest.js.map +1 -1
- package/dist/src/core/audit.d.ts +492 -0
- package/dist/src/core/budgets.d.ts +238 -0
- package/dist/src/core/checkpoint.d.ts +500 -0
- package/dist/src/core/child-env.d.ts +88 -0
- package/dist/src/core/clock.d.ts +52 -0
- package/dist/src/core/command-class.d.ts +543 -0
- package/dist/src/core/command-class.js +43 -8
- package/dist/src/core/command-class.js.map +1 -1
- package/dist/src/core/coverage-sources/adapter.d.ts +40 -0
- package/dist/src/core/coverage-sources/gh.d.ts +48 -0
- package/dist/src/core/coverage-sources/git.d.ts +101 -0
- package/dist/src/core/coverage.d.ts +217 -0
- package/dist/src/core/credential-spec.d.ts +72 -0
- package/dist/src/core/dark-session.d.ts +331 -0
- package/dist/src/core/decision-refusal.d.ts +185 -0
- package/dist/src/core/env-file.d.ts +450 -0
- package/dist/src/core/execute.d.ts +858 -0
- package/dist/src/core/execute.js +44 -6
- package/dist/src/core/execute.js.map +1 -1
- package/dist/src/core/frontmatter.d.ts +78 -0
- package/dist/src/core/gate-window.d.ts +312 -0
- package/dist/src/core/gate.d.ts +1364 -0
- package/dist/src/core/gate.js +68 -13
- package/dist/src/core/gate.js.map +1 -1
- package/dist/src/core/git-run.d.ts +73 -0
- package/dist/src/core/harness-version.d.ts +157 -0
- package/dist/src/core/harness-version.js +2 -1
- package/dist/src/core/harness-version.js.map +1 -1
- package/dist/src/core/harness-wait.d.ts +55 -0
- package/dist/src/core/head-retry.d.ts +107 -0
- package/dist/src/core/instance.d.ts +253 -0
- package/dist/src/core/intake-limits.d.ts +247 -0
- package/dist/src/core/jcs.d.ts +52 -0
- package/dist/src/core/journal.d.ts +144 -0
- package/dist/src/core/live-draw.d.ts +436 -0
- package/dist/src/core/log-reconcile.d.ts +89 -0
- package/dist/src/core/log-subscribe.d.ts +36 -0
- package/dist/src/core/log-subscribe.js +162 -0
- package/dist/src/core/log-subscribe.js.map +1 -0
- package/dist/src/core/log.d.ts +278 -0
- package/dist/src/core/loop.d.ts +274 -0
- package/dist/src/core/loop.js +11 -0
- package/dist/src/core/loop.js.map +1 -1
- package/dist/src/core/md-fence.d.ts +41 -0
- package/dist/src/core/money.d.ts +147 -0
- package/dist/src/core/payload-census.d.ts +74 -0
- package/dist/src/core/payload-store.d.ts +175 -0
- package/dist/src/core/payload.d.ts +71 -0
- package/dist/src/core/policy-diff.d.ts +292 -0
- package/dist/src/core/policy-diff.js +27 -4
- package/dist/src/core/policy-diff.js.map +1 -1
- package/dist/src/core/policy-expectations.d.ts +199 -0
- package/dist/src/core/policy-explain.d.ts +150 -0
- package/dist/src/core/policy-explain.js +31 -3
- package/dist/src/core/policy-explain.js.map +1 -1
- package/dist/src/core/policy-load.d.ts +527 -0
- package/dist/src/core/policy-load.js +15 -3
- package/dist/src/core/policy-load.js.map +1 -1
- package/dist/src/core/policy-match.d.ts +281 -0
- package/dist/src/core/policy-match.js +20 -9
- package/dist/src/core/policy-match.js.map +1 -1
- package/dist/src/core/policy-proposal.d.ts +265 -0
- package/dist/src/core/prompt-layout.d.ts +221 -0
- package/dist/src/core/protected-path-guard.d.ts +453 -0
- package/dist/src/core/protected-path-guard.js +514 -35
- package/dist/src/core/protected-path-guard.js.map +1 -1
- package/dist/src/core/registration.d.ts +25 -0
- package/dist/src/core/reindex.d.ts +99 -0
- package/dist/src/core/sampler.d.ts +313 -0
- package/dist/src/core/sandbox.d.ts +290 -0
- package/dist/src/core/seal.d.ts +165 -0
- package/dist/src/core/state.d.ts +505 -0
- package/dist/src/core/task-file.d.ts +185 -0
- package/dist/src/core/telegram-config.d.ts +93 -0
- package/dist/src/core/token.d.ts +409 -0
- package/dist/src/core/token.js +21 -38
- package/dist/src/core/token.js.map +1 -1
- package/dist/src/core/validate.d.ts +138 -0
- package/dist/src/core/values.d.ts +137 -0
- package/dist/src/core/vault.d.ts +291 -0
- package/dist/src/core/verified-snapshot.d.ts +204 -0
- package/dist/src/core/verify.d.ts +336 -0
- package/dist/src/core/version.d.ts +8 -0
- package/dist/src/core/wysiwys.d.ts +370 -0
- package/dist/src/daemon/advance-child.d.ts +39 -0
- package/dist/src/daemon/advance.d.ts +466 -0
- package/dist/src/daemon/audit.d.ts +87 -0
- package/dist/src/daemon/daemon.d.ts +1180 -0
- package/dist/src/daemon/dark-session.d.ts +64 -0
- package/dist/src/daemon/draw-child.d.ts +36 -0
- package/dist/src/daemon/draw.d.ts +154 -0
- package/dist/src/daemon/git-evidence.d.ts +173 -0
- package/dist/src/daemon/git-evidence.js +1 -1
- package/dist/src/daemon/projection.d.ts +180 -0
- package/dist/src/daemon/prune.d.ts +207 -0
- package/dist/src/mcp/http.d.ts +113 -0
- package/dist/src/mcp/server.d.ts +265 -0
- package/dist/src/mcp/server.js +9 -1
- package/dist/src/mcp/server.js.map +1 -1
- package/docs/adapter-api.md +106 -0
- package/docs/cli-reference.md +389 -36
- package/docs/codex-enforced-session.md +30 -0
- package/package.json +12 -2
- package/schema/codex-instance.schema.json +82 -0
- package/schema/event.schema.json +2 -1
- package/schema/fixtures/codex-instance/invalid/unpinned-codex-version.json +40 -0
- package/schema/fixtures/codex-instance/valid/canonical.json +40 -0
- package/schema/policy.schema.json +21 -1
- package/templates/codex/README.md +9 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `.approval/QUEUE.md` — the queue projection of SPEC.md §9.1.
|
|
3
|
+
*
|
|
4
|
+
* > **The queue** (`.approval/QUEUE.md`): a rendered, read-only markdown view of
|
|
5
|
+
* > pending requests (task, actions, declared effects, cost, TTL countdown) plus
|
|
6
|
+
* > the sampled-audit backlog. Regenerated on every relevant event. This is the
|
|
7
|
+
* > screenshot; it is never the truth.
|
|
8
|
+
*
|
|
9
|
+
* Three properties are the whole point of this module.
|
|
10
|
+
*
|
|
11
|
+
* **It is a pure function of (verified log, policy, `now`).** No ambient clock,
|
|
12
|
+
* no locale, no hostname, no environment, no random temp name in the bytes. The
|
|
13
|
+
* evaluation instant is a parameter — the same discipline `channels/tagging.ts`
|
|
14
|
+
* already keeps — so an identical log rendered at an identical `now` produces
|
|
15
|
+
* identical bytes, and a rendering can be reproduced later from the log alone.
|
|
16
|
+
* Every number here is formatted by hand with integer arithmetic for the same
|
|
17
|
+
* reason: `toLocaleString` would make the output depend on the machine.
|
|
18
|
+
*
|
|
19
|
+
* **It re-derives nothing.** Entries come from
|
|
20
|
+
* {@link buildPendingQueue}, which is the one place a {@link ChannelRequest} is
|
|
21
|
+
* built. So the class, the autonomy, the provenance, the budgets, the
|
|
22
|
+
* attestation and the TTL a reader sees in QUEUE.md are the same answers the
|
|
23
|
+
* gate itself would give — not a second implementation that could drift. This
|
|
24
|
+
* module's entire job is text.
|
|
25
|
+
*
|
|
26
|
+
* **It never writes the log.** {@link writeQueue} writes exactly one file, and
|
|
27
|
+
* it is `QUEUE.md`.
|
|
28
|
+
*
|
|
29
|
+
* ## Why this lives in `src/channels/`, not `src/core/`
|
|
30
|
+
*
|
|
31
|
+
* It consumes `channels/contract.ts`'s tagged requests through
|
|
32
|
+
* `channels/tagging.ts`. Putting it in `core/` would make core import channels,
|
|
33
|
+
* inverting the dependency the codebase is built on: core decides, channels
|
|
34
|
+
* display, and this file is display — a read-only markdown surface that collects
|
|
35
|
+
* no gesture and holds no authority. It sits beside `tagging.ts` and `batch.ts`
|
|
36
|
+
* because it is the third consumer of the same tagged data, and it deliberately
|
|
37
|
+
* does not implement {@link ../channels/contract.js Channel}: QUEUE.md notifies
|
|
38
|
+
* nobody and answers nothing.
|
|
39
|
+
*
|
|
40
|
+
* ## B3: computed vs claimed
|
|
41
|
+
*
|
|
42
|
+
* SPEC.md §9: "Every displayed field is one of two kinds and MUST be visibly
|
|
43
|
+
* distinguished". Here that is structural, not typographic: computed fields are
|
|
44
|
+
* rendered as `computed · <source>` lines under **Computed by the runtime**, and
|
|
45
|
+
* claimed fields under a separate **Claimed by `<actor>` (not verified)** block
|
|
46
|
+
* that names its author. A reader skimming the file cannot mistake an agent's
|
|
47
|
+
* cost estimate for a budget verdict, because they are not in the same list.
|
|
48
|
+
*
|
|
49
|
+
* ## The full payload is NOT in this file — flagged for human review
|
|
50
|
+
*
|
|
51
|
+
* SPEC.md §10.4 requires channels to present the full payload before collecting
|
|
52
|
+
* a decision. QUEUE.md collects no decision: it is a read-only summary, and the
|
|
53
|
+
* decision surfaces are the channels (`approval grant`, the web page, Telegram),
|
|
54
|
+
* each of which presents the bytes at decision time. Inlining payloads here
|
|
55
|
+
* would put every pending payload — recipients, bodies, argv — into a file that
|
|
56
|
+
* is regenerated on every event, checked into nothing, and read by anyone with
|
|
57
|
+
* the working directory, with no gesture ever collected from it. So the queue
|
|
58
|
+
* carries the **binding** (`payload_hash`) and points at the channels for the
|
|
59
|
+
* bytes, and the rendered header says exactly that to the human reading it.
|
|
60
|
+
*
|
|
61
|
+
* Which is a different statement from "the renderer cannot see the payload".
|
|
62
|
+
* Since APRV-28 it can: `channels/tagging.ts` reads the payload store beside the
|
|
63
|
+
* log (SPEC.md §6.2's "the payload itself is stored or referenced by the request
|
|
64
|
+
* so channels can display it"), so a request whose bytes were supplied at intake
|
|
65
|
+
* is *summarizable* here and appears in the pending section — which is why this
|
|
66
|
+
* file's pending count now agrees with the queue every channel shows, where
|
|
67
|
+
* before it silently disagreed. The bytes still do not appear in this file.
|
|
68
|
+
* Requests whose material nobody holds remain in {@link QueueRender.skipped},
|
|
69
|
+
* rendered in their own section with the reason, never silently dropped.
|
|
70
|
+
*/
|
|
71
|
+
import type { LogHead } from "../core/log.js";
|
|
72
|
+
import { type TagOptions } from "./tagging.js";
|
|
73
|
+
/**
|
|
74
|
+
* Rendering options. A superset of {@link TagOptions} with nothing added: the
|
|
75
|
+
* renderer's inputs are exactly the tagger's inputs, plus `now`, because it
|
|
76
|
+
* derives nothing the tagger does not already derive.
|
|
77
|
+
*/
|
|
78
|
+
export type RenderQueueOptions = TagOptions;
|
|
79
|
+
/**
|
|
80
|
+
* Why the renderer refused.
|
|
81
|
+
*
|
|
82
|
+
* The three log codes are `channels/tagging.ts`'s and `core/state.ts`'s,
|
|
83
|
+
* verbatim, so a corrupt log is reported as corruption by every layer with one
|
|
84
|
+
* vocabulary. `write-failed` is {@link writeQueue}'s alone — the renderer itself
|
|
85
|
+
* cannot fail for any other reason, because it is a pure function.
|
|
86
|
+
*/
|
|
87
|
+
export declare const RENDER_QUEUE_REFUSAL_CODES: readonly ["log-unreadable", "log-torn-tail", "log-corrupt", "write-failed"];
|
|
88
|
+
export type RenderQueueRefusalCode = (typeof RENDER_QUEUE_REFUSAL_CODES)[number];
|
|
89
|
+
export interface RenderQueueRefusal {
|
|
90
|
+
ok: false;
|
|
91
|
+
code: RenderQueueRefusalCode;
|
|
92
|
+
message: string;
|
|
93
|
+
}
|
|
94
|
+
/** A successful render: the bytes, plus what went into them. */
|
|
95
|
+
export interface QueueRender {
|
|
96
|
+
ok: true;
|
|
97
|
+
/** The complete file contents. Deterministic for a given (log, policy, now). */
|
|
98
|
+
markdown: string;
|
|
99
|
+
/** The chain head the render derives from; `null` for an empty log. */
|
|
100
|
+
head: LogHead | null;
|
|
101
|
+
/** Pending requests rendered, in log order. */
|
|
102
|
+
pending: number;
|
|
103
|
+
/** Live requests that could not be tagged, listed with their reason. */
|
|
104
|
+
skipped: number;
|
|
105
|
+
/** `audit.sampled` events with no later `audit.reviewed`. */
|
|
106
|
+
auditBacklog: number;
|
|
107
|
+
}
|
|
108
|
+
export type RenderQueueResult = QueueRender | RenderQueueRefusal;
|
|
109
|
+
export interface QueueWrite extends Omit<QueueRender, "markdown"> {
|
|
110
|
+
/** Where the file was written. */
|
|
111
|
+
path: string;
|
|
112
|
+
/** Bytes written (UTF-8). */
|
|
113
|
+
bytes: number;
|
|
114
|
+
}
|
|
115
|
+
export type WriteQueueResult = QueueWrite | RenderQueueRefusal;
|
|
116
|
+
/**
|
|
117
|
+
* Render the queue.
|
|
118
|
+
*
|
|
119
|
+
* Deterministic in the strong sense: for a fixed log, policy and `now`, the
|
|
120
|
+
* returned string is byte-identical across processes and machines. Nothing here
|
|
121
|
+
* reads a clock, a locale, an environment variable, or a hostname.
|
|
122
|
+
*
|
|
123
|
+
* Expiry is not this module's judgment: `channels/tagging.ts` derives state
|
|
124
|
+
* through `core/state.ts` with the policy TTL and the same `now`, so a request
|
|
125
|
+
* whose TTL has elapsed is `expired`, not `requested`, and never reaches the
|
|
126
|
+
* pending section. The countdown a reader sees therefore never reaches zero on
|
|
127
|
+
* a listed entry.
|
|
128
|
+
*
|
|
129
|
+
* The verified read happens twice — once here for the head and the audit
|
|
130
|
+
* records, once inside {@link buildPendingQueue} — which is a deliberate trade:
|
|
131
|
+
* a second walk of the chain costs a few milliseconds on a rendering path, and
|
|
132
|
+
* the alternative is widening the tagger's public result to carry records it
|
|
133
|
+
* has no other reason to expose.
|
|
134
|
+
*/
|
|
135
|
+
export declare function renderQueue(logPath: string, options: RenderQueueOptions, now: string): RenderQueueResult;
|
|
136
|
+
/**
|
|
137
|
+
* Render and write `.approval/QUEUE.md` atomically.
|
|
138
|
+
*
|
|
139
|
+
* Temp file in the destination directory, `fsync`, then `rename` — a reader
|
|
140
|
+
* either sees the previous complete rendering or the new one, never a half-
|
|
141
|
+
* written queue. The temp name is the only non-deterministic byte anywhere in
|
|
142
|
+
* this module and it never reaches the file's contents; it is removed on every
|
|
143
|
+
* failure path, so a failed render leaves no debris beside the queue.
|
|
144
|
+
*
|
|
145
|
+
* Writes this one file and nothing else. In particular it does not touch the
|
|
146
|
+
* log: the log is opened read-only by the verified read and is not reopened
|
|
147
|
+
* here.
|
|
148
|
+
*/
|
|
149
|
+
export declare function writeQueue(logPath: string, queuePath: string, options: RenderQueueOptions, now: string): WriteQueueResult;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The runtime-side tagger: log + policy in, render-ready request out
|
|
3
|
+
* (SPEC.md §9, §10.3, §10.4).
|
|
4
|
+
*
|
|
5
|
+
* This is the only place a {@link ChannelRequest} is built, and it is on the
|
|
6
|
+
* runtime side of the boundary on purpose. Every `computed` field here is
|
|
7
|
+
* derived by the same modules the gate itself uses — `core/state.ts` for the
|
|
8
|
+
* verified read and the approval derivation, `core/policy-match.ts` /
|
|
9
|
+
* `policy-explain.ts` for autonomy, `core/budgets.ts` for the verdicts,
|
|
10
|
+
* `core/attest.ts` for the attestation status, `core/payload.ts` for the
|
|
11
|
+
* content binding — so what a channel displays as "computed" is the same answer
|
|
12
|
+
* the gate would give, not a second implementation that could disagree with it.
|
|
13
|
+
* Every `claimed` field is copied out of a log record and stamped with the actor
|
|
14
|
+
* who authored that record.
|
|
15
|
+
*
|
|
16
|
+
* ## Why this takes a log *path*, not records
|
|
17
|
+
*
|
|
18
|
+
* SPEC.md §11.1(1): enforcement paths read only verified records. A channel
|
|
19
|
+
* request is what a human's decision is made from, so it is an enforcement
|
|
20
|
+
* surface in the sense that matters — a request built from a spliced log would
|
|
21
|
+
* put a fabricated action in front of an approver. Accepting an
|
|
22
|
+
* `EventRecord[]` would let a caller hand over anything; taking the path and
|
|
23
|
+
* calling {@link readVerifiedRecords} here means the chain is walked, the hashes
|
|
24
|
+
* recomputed and the schemas checked before a single field is tagged, and a log
|
|
25
|
+
* that does not verify produces a refusal rather than a queue entry.
|
|
26
|
+
*
|
|
27
|
+
* ## Where the full payload comes from — flagged for human review
|
|
28
|
+
*
|
|
29
|
+
* v0.1's log records a `payload_hash`, never the payload bytes: the binding is
|
|
30
|
+
* a commitment, and putting the bytes in an append-only log would make every
|
|
31
|
+
* approved payload permanent and world-readable to anyone with the log. So the
|
|
32
|
+
* material to render comes from the payload store beside the log
|
|
33
|
+
* (`core/payload-store.ts`, APRV-28), or from a caller-supplied override
|
|
34
|
+
* ({@link TagOptions.payload}) where an operator holds the bytes somewhere else,
|
|
35
|
+
* and this module **verifies it against the recorded hash** before tagging it
|
|
36
|
+
* `computed` — material that does not hash to the bound value is refused
|
|
37
|
+
* `payload-mismatch` and never reaches a channel. That verification is what
|
|
38
|
+
* makes `fullPayload` a computed field rather than one more agent claim, and it
|
|
39
|
+
* is the same check `core/token.ts` makes at spend time.
|
|
40
|
+
*
|
|
41
|
+
* Determinism: no clock. `now` is a parameter, so a queue rendering is
|
|
42
|
+
* replayable exactly as it was rendered.
|
|
43
|
+
*/
|
|
44
|
+
import { type ChannelRequest } from "./contract.js";
|
|
45
|
+
/**
|
|
46
|
+
* Where the payload material for an action comes from.
|
|
47
|
+
*
|
|
48
|
+
* Returns `undefined` when the caller holds no material for that key — which
|
|
49
|
+
* falls back to the payload store, and then, if that holds nothing either, is a
|
|
50
|
+
* refusal for a manual request (§10.4) and merely a missing field otherwise.
|
|
51
|
+
* Never throws: an adapter that cannot produce material says so by returning
|
|
52
|
+
* `undefined`.
|
|
53
|
+
*
|
|
54
|
+
* The bound `payload_hash` is passed as a second argument for sources that are
|
|
55
|
+
* addressed by content rather than by key; sources that key on the action alone
|
|
56
|
+
* ignore it.
|
|
57
|
+
*/
|
|
58
|
+
export type PayloadSource = (actionKey: string, payloadHash: string) => unknown;
|
|
59
|
+
export interface TagOptions {
|
|
60
|
+
/** Where `APPROVAL.md` lives. Same semantics as `core/gate.ts`'s option. */
|
|
61
|
+
policy?: {
|
|
62
|
+
dir?: string;
|
|
63
|
+
file?: string;
|
|
64
|
+
};
|
|
65
|
+
/** Schema directory, passed to the verified read and the policy load. */
|
|
66
|
+
schemaDir?: string;
|
|
67
|
+
/**
|
|
68
|
+
* The payload bytes to render, checked against the recorded binding.
|
|
69
|
+
*
|
|
70
|
+
* An **override**: when it is absent, or returns `undefined` for a key, the
|
|
71
|
+
* payload store beside the log answers instead (APRV-28). An operator with a
|
|
72
|
+
* `--payload-dir` therefore still wins for the keys it covers, and gets the
|
|
73
|
+
* store for the rest.
|
|
74
|
+
*/
|
|
75
|
+
payload?: PayloadSource;
|
|
76
|
+
/**
|
|
77
|
+
* Where the payload store lives. Defaults to `.approval/payloads/` beside the
|
|
78
|
+
* log, resolved by `core/payload-store.ts` from the log path the caller
|
|
79
|
+
* already passed. `null` disables the fallback entirely, which is what a
|
|
80
|
+
* caller that wants to prove the store is not answering asks for.
|
|
81
|
+
*/
|
|
82
|
+
payloadStoreDir?: string | null;
|
|
83
|
+
/**
|
|
84
|
+
* Truncate the rendered payload text at this many characters. Unset means no
|
|
85
|
+
* truncation. A truncated rendering is legal for a unit request and is what
|
|
86
|
+
* `channels/batch.ts` refuses to fold into a batch (SPEC.md §10.3, B7).
|
|
87
|
+
*/
|
|
88
|
+
maxPayloadChars?: number;
|
|
89
|
+
}
|
|
90
|
+
/** Why the tagger refused. Frozen per SPEC.md §11.1(6). */
|
|
91
|
+
export declare const CHANNEL_TAG_REFUSAL_CODES: readonly [
|
|
92
|
+
/** The log could not be opened. */
|
|
93
|
+
"log-unreadable",
|
|
94
|
+
/** The log's final line is unterminated (a crashed write). */
|
|
95
|
+
"log-torn-tail",
|
|
96
|
+
/** The chain does not verify; nothing may be rendered from it. */
|
|
97
|
+
"log-corrupt",
|
|
98
|
+
/** No `approval.requested` record for this action key. */
|
|
99
|
+
"not-requested",
|
|
100
|
+
/** There is a request, but it is decided or expired — nothing to approve. */
|
|
101
|
+
"not-awaiting",
|
|
102
|
+
/** The request carries no usable `payload.class`; policy cannot be resolved. */
|
|
103
|
+
"class-missing",
|
|
104
|
+
/** The request carries no `payload_hash`; there is no binding to display. */
|
|
105
|
+
"payload-hash-missing",
|
|
106
|
+
/** No payload material was supplied for a manual request (§10.4). */
|
|
107
|
+
"payload-unavailable",
|
|
108
|
+
/** The supplied material does not hash to the bound `payload_hash`. */
|
|
109
|
+
"payload-mismatch",
|
|
110
|
+
/** The supplied material cannot be canonicalized (a cycle, a NaN, …). */
|
|
111
|
+
"payload-unrenderable",
|
|
112
|
+
/** {@link createChannelRequest} refused the assembled request. */
|
|
113
|
+
"request-invalid",
|
|
114
|
+
/**
|
|
115
|
+
* An attestation prompt's policy bytes are no longer the bytes on disk
|
|
116
|
+
* (APRV-109).
|
|
117
|
+
*
|
|
118
|
+
* Skipped rather than rendered: the hash, the diff and the advisory the
|
|
119
|
+
* proposal recorded all describe a file that has since changed, and a prompt
|
|
120
|
+
* showing them would ask a human to sign for bytes nobody is holding. The
|
|
121
|
+
* repair is to propose the amendment again, which re-derives all three from
|
|
122
|
+
* the file as it now stands.
|
|
123
|
+
*/
|
|
124
|
+
"proposal-stale"];
|
|
125
|
+
export type ChannelTagRefusalCode = (typeof CHANNEL_TAG_REFUSAL_CODES)[number];
|
|
126
|
+
export interface ChannelTagRefusal {
|
|
127
|
+
ok: false;
|
|
128
|
+
code: ChannelTagRefusalCode;
|
|
129
|
+
message: string;
|
|
130
|
+
}
|
|
131
|
+
export type BuildChannelRequestResult = {
|
|
132
|
+
ok: true;
|
|
133
|
+
request: ChannelRequest;
|
|
134
|
+
} | ChannelTagRefusal;
|
|
135
|
+
/**
|
|
136
|
+
* Build the render-ready request for one action key.
|
|
137
|
+
*
|
|
138
|
+
* Computed, and what derives each:
|
|
139
|
+
*
|
|
140
|
+
* | field | derivation | `source` |
|
|
141
|
+
* | --- | --- | --- |
|
|
142
|
+
* | `class`, `task`, `payload_hash`, `requested_ts`, `chain`, `state` | the verified log | `log` |
|
|
143
|
+
* | `autonomy`, `provenance` | `explain()` over the attested policy | `policy-match` |
|
|
144
|
+
* | `budgets` | `evaluateBudgetsWithTask()` at `now` | `budgets` |
|
|
145
|
+
* | `attestation` | `checkAttestation()` against the live policy file | `attestation` |
|
|
146
|
+
* | `fullPayload` | supplied material, hash-checked | `payload-binding` |
|
|
147
|
+
* | `command_breakdown`, `protected_path` | the classifier, re-run over the hash-checked material | `classifier` |
|
|
148
|
+
* | `ttl_remaining_ms`, `waiting` | arithmetic on `now` | `clock` |
|
|
149
|
+
*
|
|
150
|
+
* Claimed, and who authored each: `summary` and `est_cost_usd` carry the actor
|
|
151
|
+
* of the `approval.requested` record — the party that submitted the declaration
|
|
152
|
+
* — and `rationale` / `confidence` carry the registering actor.
|
|
153
|
+
*
|
|
154
|
+
* Refuses an unknown or undecidable key rather than rendering a partial one:
|
|
155
|
+
* `not-requested` (no such request), `not-awaiting` (already granted, rejected,
|
|
156
|
+
* revoked or expired), and the payload codes above. An unverifiable log refuses
|
|
157
|
+
* `log-corrupt` before anything is derived.
|
|
158
|
+
*/
|
|
159
|
+
export declare function buildChannelRequest(logPath: string, actionKey: string, options: TagOptions, now: string): BuildChannelRequestResult;
|
|
160
|
+
/**
|
|
161
|
+
* `just now`, `4 min ago`, `2h 05m ago` — how long the question has waited.
|
|
162
|
+
*
|
|
163
|
+
* Exported since APRV-216 so the Telegram queue summary states a request's age
|
|
164
|
+
* in the same words the request's own prompt does. One phrasing and one
|
|
165
|
+
* rounding: a summary calling a question `2h 05m` old beside a prompt that
|
|
166
|
+
* calls it something else leaves a reader deciding which of the two the
|
|
167
|
+
* runtime meant.
|
|
168
|
+
*/
|
|
169
|
+
export declare function ageText(ms: number): string;
|
|
170
|
+
/** One key the queue could not render, and why. */
|
|
171
|
+
export interface SkippedRequest {
|
|
172
|
+
action_key: string;
|
|
173
|
+
code: ChannelTagRefusalCode;
|
|
174
|
+
message: string;
|
|
175
|
+
}
|
|
176
|
+
export type PendingQueueResult = {
|
|
177
|
+
ok: true;
|
|
178
|
+
/** Every live request awaiting a human decision, in log order. */
|
|
179
|
+
requests: ChannelRequest[];
|
|
180
|
+
/**
|
|
181
|
+
* Keys that are live but could not be rendered — most often a manual
|
|
182
|
+
* request whose payload material the caller does not hold. Surfaced
|
|
183
|
+
* rather than silently dropped: a request missing from a queue is a
|
|
184
|
+
* request nobody will approve, and an operator must be able to see why.
|
|
185
|
+
*/
|
|
186
|
+
skipped: SkippedRequest[];
|
|
187
|
+
} | ChannelTagRefusal;
|
|
188
|
+
/**
|
|
189
|
+
* Build the pending queue: every action key with a live `approval.requested`.
|
|
190
|
+
*
|
|
191
|
+
* Order is log order (oldest request first), which is the order SPEC.md §9's
|
|
192
|
+
* queue projection asks for. One verified read serves the whole queue, and one
|
|
193
|
+
* policy load serves every entry, so an entry cannot disagree with its
|
|
194
|
+
* neighbour about what the policy says.
|
|
195
|
+
*/
|
|
196
|
+
export declare function buildPendingQueue(logPath: string, options: TagOptions, now: string): PendingQueueResult;
|