@affiant/core 0.1.0-alpha.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 (96) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +354 -0
  3. package/dist/context.d.ts +136 -0
  4. package/dist/context.d.ts.map +1 -0
  5. package/dist/context.js +30 -0
  6. package/dist/context.js.map +1 -0
  7. package/dist/docket/entry.d.ts +421 -0
  8. package/dist/docket/entry.d.ts.map +1 -0
  9. package/dist/docket/entry.js +155 -0
  10. package/dist/docket/entry.js.map +1 -0
  11. package/dist/docket/expiry.d.ts +82 -0
  12. package/dist/docket/expiry.d.ts.map +1 -0
  13. package/dist/docket/expiry.js +106 -0
  14. package/dist/docket/expiry.js.map +1 -0
  15. package/dist/docket/memory.d.ts +163 -0
  16. package/dist/docket/memory.d.ts.map +1 -0
  17. package/dist/docket/memory.js +528 -0
  18. package/dist/docket/memory.js.map +1 -0
  19. package/dist/docket/store.d.ts +387 -0
  20. package/dist/docket/store.d.ts.map +1 -0
  21. package/dist/docket/store.js +51 -0
  22. package/dist/docket/store.js.map +1 -0
  23. package/dist/errors.d.ts +153 -0
  24. package/dist/errors.d.ts.map +1 -0
  25. package/dist/errors.js +164 -0
  26. package/dist/errors.js.map +1 -0
  27. package/dist/gate/coverage.d.ts +152 -0
  28. package/dist/gate/coverage.d.ts.map +1 -0
  29. package/dist/gate/coverage.js +114 -0
  30. package/dist/gate/coverage.js.map +1 -0
  31. package/dist/gate/decide.d.ts +207 -0
  32. package/dist/gate/decide.d.ts.map +1 -0
  33. package/dist/gate/decide.js +559 -0
  34. package/dist/gate/decide.js.map +1 -0
  35. package/dist/gate/gate.d.ts +212 -0
  36. package/dist/gate/gate.d.ts.map +1 -0
  37. package/dist/gate/gate.js +175 -0
  38. package/dist/gate/gate.js.map +1 -0
  39. package/dist/gate/pipeline.d.ts +285 -0
  40. package/dist/gate/pipeline.d.ts.map +1 -0
  41. package/dist/gate/pipeline.js +515 -0
  42. package/dist/gate/pipeline.js.map +1 -0
  43. package/dist/gate/policy.d.ts +272 -0
  44. package/dist/gate/policy.d.ts.map +1 -0
  45. package/dist/gate/policy.js +396 -0
  46. package/dist/gate/policy.js.map +1 -0
  47. package/dist/gate/wrap.d.ts +107 -0
  48. package/dist/gate/wrap.d.ts.map +1 -0
  49. package/dist/gate/wrap.js +164 -0
  50. package/dist/gate/wrap.js.map +1 -0
  51. package/dist/index.d.ts +95 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +111 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/model/affidavit.d.ts +354 -0
  56. package/dist/model/affidavit.d.ts.map +1 -0
  57. package/dist/model/affidavit.js +417 -0
  58. package/dist/model/affidavit.js.map +1 -0
  59. package/dist/model/amendments.d.ts +160 -0
  60. package/dist/model/amendments.d.ts.map +1 -0
  61. package/dist/model/amendments.js +183 -0
  62. package/dist/model/amendments.js.map +1 -0
  63. package/dist/model/canonical.d.ts +311 -0
  64. package/dist/model/canonical.d.ts.map +1 -0
  65. package/dist/model/canonical.js +665 -0
  66. package/dist/model/canonical.js.map +1 -0
  67. package/dist/model/money.d.ts +127 -0
  68. package/dist/model/money.d.ts.map +1 -0
  69. package/dist/model/money.js +177 -0
  70. package/dist/model/money.js.map +1 -0
  71. package/dist/model/provenance.d.ts +315 -0
  72. package/dist/model/provenance.d.ts.map +1 -0
  73. package/dist/model/provenance.js +223 -0
  74. package/dist/model/provenance.js.map +1 -0
  75. package/dist/ports.d.ts +269 -0
  76. package/dist/ports.d.ts.map +1 -0
  77. package/dist/ports.js +34 -0
  78. package/dist/ports.js.map +1 -0
  79. package/dist/store-memory.d.ts +21 -0
  80. package/dist/store-memory.d.ts.map +1 -0
  81. package/dist/store-memory.js +20 -0
  82. package/dist/store-memory.js.map +1 -0
  83. package/dist/telemetry-keys.d.ts +65 -0
  84. package/dist/telemetry-keys.d.ts.map +1 -0
  85. package/dist/telemetry-keys.js +72 -0
  86. package/dist/telemetry-keys.js.map +1 -0
  87. package/dist/telemetry.d.ts +77 -0
  88. package/dist/telemetry.d.ts.map +1 -0
  89. package/dist/telemetry.js +43 -0
  90. package/dist/telemetry.js.map +1 -0
  91. package/dist/testing.d.ts +574 -0
  92. package/dist/testing.d.ts.map +1 -0
  93. package/dist/testing.js +1291 -0
  94. package/dist/testing.js.map +1 -0
  95. package/package.json +75 -0
  96. package/telemetry-keys.json +92 -0
@@ -0,0 +1,559 @@
1
+ /**
2
+ * Decisions: who may make one, what it attests to, what it does to the row, and how
3
+ * a refused one is resubmitted.
4
+ *
5
+ * **Rules served: AZ-1** (every decided row carries an attestation record naming who
6
+ * agreed, when, and to which entry), **AZ-2** (tenant-scoped, fail-closed decision
7
+ * authorization, checked by the framework before any transition), **AZ-3** (what
8
+ * identity may attest what — a machine caller may never attest `member`), **AZ-4** (a
9
+ * blocked entry refuses every decision), **AZ-5** (the Docket is the sole record of
10
+ * approval authority: the only way to `executed` is a report against an approved,
11
+ * attested row), **AZ-6** (nothing here is conditional on a port, a model or a
12
+ * transport being available, so there is no degraded path that skips a check),
13
+ * **AZ-7** (the gate never performs the write — there is no executor port and no
14
+ * method that calls one), **DK-1** (the guarded compare-and-set, expiry as state with
15
+ * the late decision's amendments preserved, the execution outcome, resubmission
16
+ * lineage), **DK-2** (`null` clears, absent leaves untouched), **DK-5** (rehydration
17
+ * order), **AF-4** (an accepted amendment recomputes the three numbers), **PV-2** (an
18
+ * amended field's tag carries a `reviewer-act` binding naming the decision).
19
+ *
20
+ * ## The order the checks run in, and why it is this order
21
+ *
22
+ * 1. **No resolved principal → refused, before the store is touched.** AZ-2's
23
+ * "fail closed, never *identity unknown, allow*" is not only about the answer; it
24
+ * is about not doing any work on an entry for a caller who has not been
25
+ * identified. A read that happened before the refusal is a read an attacker can
26
+ * time.
27
+ * 2. **The entry is fetched inside the caller's tenant, and the row that comes back
28
+ * is checked against it.** A row in another tenant is reported as
29
+ * `entry-not-found`, exactly as an id that never existed — never "not authorized
30
+ * for that tenant", which would be an oracle for guessing ids. The scope goes to
31
+ * the store *and* the row's own `tenantId` is compared here, because AZ-2 makes
32
+ * this the framework's check: a host store with a scope bug would otherwise fail
33
+ * open with nothing above it noticing.
34
+ * 3. **The host's authorization port.** Its answer is the host's own — role,
35
+ * ownership, separation of duties. A port that throws is a refusal.
36
+ * 4. **What the entry reads *now*.** Expiry is state (DK-1): a row past its deadline
37
+ * reads `expired` whether or not the host's sweep has run, and a decision on it is
38
+ * refused with the amendments it carried preserved for a resubmission — provided
39
+ * the caller could have attested at all, because those values come back as a
40
+ * person's act on the resubmission (PV-3).
41
+ * 5. **The attestation.** Built from the principal, and *only* from the principal:
42
+ * there is no parameter through which a caller can name whose signature this is.
43
+ * 6. **The transition**, a guarded compare-and-set that is applied once or not at
44
+ * all.
45
+ *
46
+ * ## Why there is no `execute`
47
+ *
48
+ * AZ-7 says no package in an implementation writes to a host's store, and the gate
49
+ * has no executor port to call. The path to `execution: "executed"` is
50
+ * {@link markExecuted} — the host's own executor telling the Docket what happened.
51
+ * That is also why a `service` principal is admitted there and refused as a decider
52
+ * here: reporting an outcome is a statement of fact about work the host did, and a
53
+ * decision is an act of authority a machine may not perform on a person's behalf
54
+ * (AZ-3).
55
+ *
56
+ * @packageDocumentation
57
+ */
58
+ import { readStatus } from "../docket/entry.js";
59
+ import { AffiantError } from "../errors.js";
60
+ import { applyAmendments, resolveAmendments } from "../model/amendments.js";
61
+ import { mintTag, supersede } from "../model/provenance.js";
62
+ import { runPipeline } from "./pipeline.js";
63
+ // ---------------------------------------------------------------------------
64
+ // decide
65
+ // ---------------------------------------------------------------------------
66
+ /**
67
+ * Approve, amend or reject the entry `entryId` names, as `ctx.principal` (DK-1,
68
+ * AZ-1, AZ-2, AZ-3).
69
+ *
70
+ * @returns The row as it stands after the transition.
71
+ * @throws AffiantError `"decision-unauthorized"` when the context carries no
72
+ * resolved principal, when the host's authorization port says no, or when a
73
+ * machine caller with nothing to relay tries to attest (AZ-2, AZ-3);
74
+ * `"entry-not-found"` when no entry with that id is visible in the caller's
75
+ * tenant; `"decision-expired"` when the entry has passed its deadline — the
76
+ * decision's amendments are preserved on the row first (DK-1);
77
+ * `"decision-not-pending"` when it has already been decided or is blocked
78
+ * (AZ-4); `"decision-lost-race"` when a competing decision won the guarded
79
+ * compare-and-set.
80
+ * @throws RangeError when an amendment map holds `undefined` under a key, or names a
81
+ * field the Affidavit does not propose. Neither is a refusal the gate hands
82
+ * back to a caller: they are caller programming errors, and an `AffiantError`
83
+ * code would invite a host to catch and continue.
84
+ */
85
+ export async function decide(entryId, decision, ctx, deps) {
86
+ const now = deps.clock.now();
87
+ const scope = { tenantId: ctx.tenantId };
88
+ // (i) AZ-2, fail closed — before any store call at all.
89
+ const principal = requirePrincipal(ctx, entryId, "decide", deps, now);
90
+ // (ii) The tenant is the boundary, and a miss is a miss (AZ-2).
91
+ const entry = await requireEntry(entryId, ctx, "decide", deps, now);
92
+ // (iii) The host's own answer.
93
+ await requireAuthorized(principal, entry, ctx, "decide", deps, now);
94
+ // (iv) What the entry reads now (DK-1).
95
+ const amendments = decision.kind === "approve" ? (decision.amendments ?? null) : null;
96
+ const reads = readStatus(entry, now);
97
+ if (reads === "expired") {
98
+ throw await refuseExpired(entryId, scope, entry, amendments, principal, now, deps);
99
+ }
100
+ if (reads !== "pending") {
101
+ throw new AffiantError("decision-not-pending", `DK-1: Docket entry ${JSON.stringify(entryId)} reads ${reads}; a decision is accepted ` +
102
+ `only while an entry is pending, and a recorded decision is never overwritten.`, { entryId, status: reads });
103
+ }
104
+ if (entry.blocked !== null) {
105
+ // AZ-4: an entry the implementation will not decide refuses every decision on it
106
+ // and is never degraded to a requirement this version does know how to run.
107
+ throw new AffiantError("decision-not-pending", `AZ-4: Docket entry ${JSON.stringify(entryId)} is blocked ` +
108
+ `(${entry.blocked.code}); every decision on it is refused, and it is never ` +
109
+ `degraded to a weaker requirement.`, {
110
+ entryId,
111
+ blocked: entry.blocked.code,
112
+ // Narrowed on the code, not sniffed for a property: each arm carries only
113
+ // the context its own code makes meaningful (AZ-4, CV-4).
114
+ ...(entry.blocked.code === "requirement-not-implemented"
115
+ ? { level: entry.blocked.level }
116
+ : { category: entry.blocked.category, toolName: entry.blocked.toolName }),
117
+ });
118
+ }
119
+ // (v) Who is being held to this (AZ-1, AZ-3).
120
+ const attestor = attestorOf(principal);
121
+ if (attestor === null) {
122
+ throw refuseUnauthorized(entryId, ctx, "decide", "machine-attestation", `AZ-3: a machine caller cannot attest a decision. A service principal decides only on ` +
123
+ `behalf of a person it names, over a relay it names — both \`assertedMember\` and ` +
124
+ `\`relay\` — and the result attests member-via-relay. There is no path by which a ` +
125
+ `service attests member.`, deps, now);
126
+ }
127
+ const attestation = { by: attestor, at: now, entryId };
128
+ // (vi) The amendment, if there is one (DK-2, AF-4, PV-2).
129
+ const amended = decision.kind === "approve" && amendments !== null
130
+ ? applyAmendments(entry.affidavit, amendments, {
131
+ entryId,
132
+ decisionAt: now,
133
+ by: subjectOf(attestor),
134
+ })
135
+ : null;
136
+ // (vii) The guarded compare-and-set (DK-1).
137
+ const patch = {
138
+ status: decision.kind === "approve" ? "approved" : "rejected",
139
+ execution: decision.kind === "approve" ? "unexecuted" : null,
140
+ decision: { kind: decision.kind, reason: decision.reason ?? null, at: now },
141
+ amendments,
142
+ attestation,
143
+ decidedAt: now,
144
+ // Beside the proposal, never over it: the row keeps what the agent swore to and
145
+ // gains what the reviewer accepted (DK-4, AF-4).
146
+ ...(amended === null ? {} : { amendedAffidavit: amended }),
147
+ };
148
+ const result = await deps.store.transition(entryId, scope, "pending", patch);
149
+ if (result === "not-found") {
150
+ // The row was purged between the read and the write. Same answer as an id that
151
+ // never existed: the caller learns nothing they did not already know.
152
+ throw notFound(entryId, ctx);
153
+ }
154
+ if (result === "already-decided") {
155
+ throw new AffiantError("decision-lost-race", `DK-1: another decision on Docket entry ${JSON.stringify(entryId)} was applied first. ` +
156
+ `A transition out of pending happens once or not at all — this one is refused, not ` +
157
+ `queued and not applied on top.`, { entryId });
158
+ }
159
+ if (result === "expired") {
160
+ // The store's guard saw a state this function's own read did not. The only way
161
+ // that happens is a deadline crossed in between, so re-read to say so precisely
162
+ // rather than reporting a race that did not occur.
163
+ const current = await deps.store.get(entryId, scope);
164
+ if (current === null)
165
+ throw notFound(entryId, ctx);
166
+ if (readStatus(current, deps.clock.now()) === "expired") {
167
+ throw await refuseExpired(entryId, scope, current, amendments, principal, now, deps);
168
+ }
169
+ throw new AffiantError("decision-not-pending", `DK-1: Docket entry ${JSON.stringify(entryId)} is no longer pending.`, { entryId, status: readStatus(current, deps.clock.now()) });
170
+ }
171
+ deps.telemetry.emit({
172
+ key: "docket.transition",
173
+ at: now,
174
+ attributes: {
175
+ "entry.id": entryId,
176
+ "gen_ai.conversation.id": ctx.conversationId,
177
+ from: "pending",
178
+ to: result.status,
179
+ execution: result.execution,
180
+ "decision.kind": decision.kind,
181
+ "attestation.kind": attestor.kind,
182
+ amended: amended !== null,
183
+ },
184
+ });
185
+ return result;
186
+ }
187
+ // ---------------------------------------------------------------------------
188
+ // markExecuted
189
+ // ---------------------------------------------------------------------------
190
+ /**
191
+ * Record what the host's executor did with an approved write (DK-1, AZ-5, AZ-7).
192
+ *
193
+ * `status` stays `approved` — the approval happened and is not undone by a failed
194
+ * write; only `execution` and `executionDetail` move. This is the **only** public
195
+ * path to `execution: "executed"`, and the gate never calls an executor to reach it:
196
+ * a host reads its approved-and-unexecuted rows (DK-5), does the write itself, and
197
+ * says what happened.
198
+ *
199
+ * A `service` principal is admitted here and refused as a decider (AZ-3). The
200
+ * asymmetry is the point: reporting an outcome is a statement of fact about work the
201
+ * host performed, which a machine is the right party to make, while a decision is an
202
+ * act of authority that a machine may never make in a person's name. The tenant check
203
+ * and the host's authorization port still apply, so "which service may report on this
204
+ * entry" is still the host's answer and not an open door.
205
+ *
206
+ * **Reported once.** The execution transition is a guarded compare-and-set out of
207
+ * `"unexecuted"`, like every other transition on a row (DK-1): a second report is
208
+ * refused and the first stands. Overwriting would let an approved-and-committed row
209
+ * later read `failed` — an edit in place of a recorded fact (DK-4), and the loss of
210
+ * exactly the distinction DK-1 requires the row to keep. So a host that retries a
211
+ * write reports **once**, when it knows the outcome; the retries are the host's
212
+ * business (AZ-5), the outcome is the Docket's.
213
+ *
214
+ * @throws AffiantError `"decision-unauthorized"`, `"entry-not-found"`,
215
+ * `"decision-not-pending"` when the row is not `approved`, or
216
+ * `"execution-already-recorded"` when it already carries an outcome.
217
+ */
218
+ export async function markExecuted(entryId, outcome, detail, ctx, deps) {
219
+ const now = deps.clock.now();
220
+ const scope = { tenantId: ctx.tenantId };
221
+ const principal = requirePrincipal(ctx, entryId, "mark-executed", deps, now);
222
+ const entry = await requireEntry(entryId, ctx, "mark-executed", deps, now);
223
+ await requireAuthorized(principal, entry, ctx, "mark-executed", deps, now);
224
+ const result = await deps.store.recordExecution(entryId, scope, outcome, detail, "unexecuted");
225
+ if (result === "not-found")
226
+ throw notFound(entryId, ctx);
227
+ if (result === "execution-already-recorded") {
228
+ const recorded = await deps.store.get(entryId, scope);
229
+ throw new AffiantError("execution-already-recorded", `DK-4, DK-1: Docket entry ${JSON.stringify(entryId)} already carries an execution ` +
230
+ `outcome, so this report is refused rather than written over it. A recorded fact is ` +
231
+ `never edited in place, and an approved-and-committed write has to stay ` +
232
+ `distinguishable from an approved-but-failed one. A host that retries a write reports ` +
233
+ `once, when it knows the outcome.`, { entryId, recorded: recorded?.execution ?? null, outcome });
234
+ }
235
+ if (result === "not-approved") {
236
+ throw new AffiantError("decision-not-pending", `DK-1, AZ-5: Docket entry ${JSON.stringify(entryId)} is not approved, so there is no ` +
237
+ `authorised write for an executor to have performed. An execution outcome is only ` +
238
+ `ever recorded against an approved, attested row.`, { entryId, status: readStatus(entry, now), outcome });
239
+ }
240
+ deps.telemetry.emit({
241
+ key: "docket.transition",
242
+ at: now,
243
+ attributes: {
244
+ "entry.id": entryId,
245
+ "gen_ai.conversation.id": ctx.conversationId,
246
+ from: "approved",
247
+ to: result.status,
248
+ execution: result.execution,
249
+ "decision.kind": null,
250
+ "attestation.kind": result.attestation?.by.kind ?? null,
251
+ amended: result.amendments !== null,
252
+ },
253
+ });
254
+ return result;
255
+ }
256
+ // ---------------------------------------------------------------------------
257
+ // resubmit
258
+ // ---------------------------------------------------------------------------
259
+ /**
260
+ * File the expired entry `entryId` names again, as a **new** entry whose lineage
261
+ * points back at it (DK-1).
262
+ *
263
+ * A resubmission is never a reopening. The superseded entry keeps its terminal state
264
+ * and gains a successor link, so the history reads forward (DK-4) and nothing that
265
+ * was once decided is quietly edited. The new proposal carries the same operation and
266
+ * the same sworn fields, with the amendments the refused late decision left on the
267
+ * row prefilled as values — each prefilled field tagged `UserStated` with a
268
+ * `reviewer-act` binding naming the superseded entry (PV-2), so a reader of the new
269
+ * card can see which values came from a person's earlier correction rather than from
270
+ * the machine.
271
+ *
272
+ * The whole pipeline runs again: the policy chain gets another say, the deadline is
273
+ * stamped afresh from that verdict (GT-4), and the substance gate applies (GT-3). A
274
+ * resubmission is a new proposal, not a replay of an old approval.
275
+ *
276
+ * @throws AffiantError `"decision-unauthorized"`, `"entry-not-found"`, or
277
+ * `"decision-not-pending"` when the entry does not read `expired`.
278
+ * @throws RangeError when the preserved amendment map names a field the Affidavit
279
+ * does not propose.
280
+ */
281
+ export async function resubmit(entryId, ctx, deps) {
282
+ const now = deps.clock.now();
283
+ const scope = { tenantId: ctx.tenantId };
284
+ const principal = requirePrincipal(ctx, entryId, "resubmit", deps, now);
285
+ const entry = await requireEntry(entryId, ctx, "resubmit", deps, now);
286
+ await requireAuthorized(principal, entry, ctx, "resubmit", deps, now);
287
+ const reads = readStatus(entry, now);
288
+ if (reads !== "expired") {
289
+ throw new AffiantError("decision-not-pending", `DK-1: Docket entry ${JSON.stringify(entryId)} reads ${reads}; only an expired entry is ` +
290
+ `resubmitted. A pending one is still waiting for its decision, and a decided one has ` +
291
+ `had it.`, { entryId, status: reads });
292
+ }
293
+ const filed = await runPipeline(resubmissionProposal(entry), ctx, deps);
294
+ // The successor link goes on afterwards and on the *other* row: an appended later
295
+ // fact on a terminal entry (DK-4), never an edit of the decision it recorded.
296
+ await deps.store.recordSupersession(entryId, scope, filed.entry.entryId);
297
+ return filed;
298
+ }
299
+ /** The proposal a resubmission of `entry` files: same operation, amendments prefilled. */
300
+ function resubmissionProposal(entry) {
301
+ const sworn = entry.affidavit;
302
+ const fieldNames = sworn.fields.map((field) => field.name);
303
+ if (sworn.operationType === "update" && sworn.entityId === null) {
304
+ throw new RangeError("AF-3: an update Affidavit names the entity it updates; this row names none, so there " +
305
+ "is no write for a resubmission to propose");
306
+ }
307
+ const operation = sworn.operationType === "update" && sworn.entityId !== null
308
+ ? {
309
+ kind: "update",
310
+ entityType: sworn.entityType,
311
+ entityId: sworn.entityId,
312
+ fields: fieldNames,
313
+ }
314
+ : { kind: "create", entityType: sworn.entityType, entityId: null, fields: fieldNames };
315
+ // What a *refused late decision* left behind, with the act that left it (DK-1).
316
+ // An approval's accepted amendments are a different fact and cannot be here: only
317
+ // an expired row is resubmitted, and an expired row was never approved.
318
+ const preserved = entry.preservedAmendments;
319
+ const prior = preserved?.amendments ?? null;
320
+ // `resolveAmendments` is DK-2's discipline: `null` is a clear, an absent key says
321
+ // nothing, and `undefined` under a key is refused rather than guessed at.
322
+ const prefills = new Map((prior === null ? [] : resolveAmendments(prior)).map((entry_) => [entry_.name, entry_]));
323
+ for (const name of prefills.keys()) {
324
+ if (!fieldNames.includes(name)) {
325
+ throw new RangeError(`the amendments preserved on Docket entry ${JSON.stringify(entry.entryId)} name field ` +
326
+ `${JSON.stringify(name)}, which its Affidavit does not propose; there is nothing to ` +
327
+ `prefill`);
328
+ }
329
+ }
330
+ // PV-2: the binding names the entry the correction was made on **and the instant
331
+ // the correction was made**, which the row carries because `preserveAmendments`
332
+ // recorded the refused decision's own act. Dating it to the row's deadline instead
333
+ // would place a person's correction at the moment the gate refused it, and dating
334
+ // it to this call would place it whenever somebody happened to press resubmit.
335
+ //
336
+ // `preserved` is non-null whenever `prefills` is non-empty — they come from the
337
+ // same fact — so there is no case where a prefilled value has no act behind it.
338
+ const binding = preserved === null
339
+ ? null
340
+ : { kind: "reviewer-act", ref: { entryId: entry.entryId, decisionAt: preserved.at } };
341
+ const preparedFields = sworn.fields.map((field) => {
342
+ const prefill = prefills.get(field.name);
343
+ if (prefill === undefined || preserved === null || binding === null) {
344
+ return {
345
+ name: field.name,
346
+ kind: field.kind,
347
+ value: field.value,
348
+ provenance: field.provenance,
349
+ isMandatory: field.isMandatory,
350
+ };
351
+ }
352
+ return {
353
+ name: field.name,
354
+ kind: field.kind,
355
+ value: prefill.amendment.kind === "clear" ? null : prefill.amendment.value,
356
+ provenance: supersede(field.provenance, mintTag({
357
+ source: "UserStated",
358
+ confidence: 1,
359
+ // The act's instant, not this call's: a value a person typed at 09:05 is
360
+ // theirs from 09:05, whoever resubmits it and whenever (PV-2).
361
+ at: preserved.at,
362
+ note: `Prefilled from the amendment ${preserved.by} carried on Docket entry ` +
363
+ `${entry.entryId}`,
364
+ conversationTurn: sworn.conversationTurn,
365
+ binding,
366
+ })),
367
+ isMandatory: field.isMandatory,
368
+ };
369
+ });
370
+ return {
371
+ operation,
372
+ // The tool that proposed the write, off the row (CV-4): a resubmission of an
373
+ // uncovered tool's proposal is filed blocked again rather than resubmitting clean.
374
+ toolName: entry.toolName,
375
+ schema: null,
376
+ args: null,
377
+ preparedFields,
378
+ operationLabel: null,
379
+ supersedes: entry.entryId,
380
+ priorAmendments: prior,
381
+ };
382
+ }
383
+ // ---------------------------------------------------------------------------
384
+ // Identity and attestation (AZ-1, AZ-2, AZ-3)
385
+ // ---------------------------------------------------------------------------
386
+ /**
387
+ * The principal on `ctx`, or a refusal.
388
+ *
389
+ * Called before every store access on every entry point here. `null` means the host
390
+ * has not resolved an identity, which is not the same as anonymous and is never
391
+ * treated as permission (AZ-2).
392
+ */
393
+ function requirePrincipal(ctx, entryId, path, deps, now) {
394
+ if (ctx.principal !== null)
395
+ return ctx.principal;
396
+ throw refuseUnauthorized(entryId, ctx, path, "identity-unresolved", `AZ-2: identity unresolved — the turn context carries no principal, so there is nobody ` +
397
+ `to hold to a decision on Docket entry ${JSON.stringify(entryId)}. The gate fails closed ` +
398
+ `here, before it reads the Docket: "identity unknown" is never "allow".`, deps, now);
399
+ }
400
+ /**
401
+ * The entry inside the caller's tenant, or `entry-not-found` — never an oracle (AZ-2).
402
+ *
403
+ * The scoped read is asked for **and** the answer is checked. AZ-2 says the tenant
404
+ * boundary is "checked by the framework … a rule the framework enforces is the only
405
+ * version of this check that every host gets" — and a check that consists solely of
406
+ * passing a `tenantId` to `store.get` is a check the *store* performs. A host store
407
+ * with a scope bug then fails open and the gate does not notice. So the row's own
408
+ * `tenantId` is compared here, after the read, whatever the store returned: two
409
+ * independent enforcements of one rule, which is what "fail closed" is worth.
410
+ */
411
+ async function requireEntry(entryId, ctx, path, deps, now) {
412
+ const entry = await deps.store.get(entryId, { tenantId: ctx.tenantId });
413
+ if (entry !== null && entry.tenantId === ctx.tenantId)
414
+ return entry;
415
+ // The host is told an attempt was made; the caller is told only that there is no
416
+ // such entry, which is also the answer a caller in another tenant gets. The two
417
+ // reasons are separated for the host alone: `tenant-mismatch` means the store
418
+ // answered a scoped read with another tenant's row, which is a bug in that store
419
+ // and the one thing this second check exists to surface.
420
+ deps.telemetry.emit({
421
+ key: "decision.unauthorized",
422
+ at: now,
423
+ attributes: {
424
+ "entry.id": entryId,
425
+ "gen_ai.conversation.id": ctx.conversationId,
426
+ reason: entry === null ? "entry-not-found" : "tenant-mismatch",
427
+ "principal.kind": ctx.principal?.kind ?? "unresolved",
428
+ path,
429
+ },
430
+ });
431
+ throw notFound(entryId, ctx);
432
+ }
433
+ /** The host's own answer to "may this principal act on this entry" (AZ-2). */
434
+ async function requireAuthorized(principal, entry, ctx, path, deps, now) {
435
+ let admitted;
436
+ try {
437
+ admitted = await deps.authorization.mayDecide(principal, entry);
438
+ }
439
+ catch {
440
+ // A port that throws is a refusal, never an approval: an authorization callback
441
+ // that fell over has not said yes.
442
+ admitted = false;
443
+ }
444
+ if (admitted)
445
+ return;
446
+ throw refuseUnauthorized(entry.entryId, ctx, path, "not-authorized", `AZ-2: the host's authorization port did not admit this principal for Docket entry ` +
447
+ `${JSON.stringify(entry.entryId)}.`, deps, now);
448
+ }
449
+ export function attestorOf(principal) {
450
+ if (principal.kind === "member") {
451
+ return { kind: "member", id: principal.id };
452
+ }
453
+ const relay = principal.relay;
454
+ const memberId = principal.assertedMember;
455
+ if (relay === undefined || memberId === undefined)
456
+ return null;
457
+ return {
458
+ kind: "member-via-relay",
459
+ memberId,
460
+ relay: {
461
+ principal: principal.id,
462
+ channelIdentity: relay.channelIdentity,
463
+ messageId: relay.messageId,
464
+ },
465
+ };
466
+ }
467
+ /** Who an attestation is about: the person, however they reached the gate. */
468
+ function subjectOf(attestor) {
469
+ switch (attestor.kind) {
470
+ case "member":
471
+ return attestor.id;
472
+ case "member-via-relay":
473
+ return attestor.memberId;
474
+ default:
475
+ return attestor.policyId;
476
+ }
477
+ }
478
+ // ---------------------------------------------------------------------------
479
+ // Refusals
480
+ // ---------------------------------------------------------------------------
481
+ /** Emit the AZ-2 event and build the refusal. Thrown by the caller, so control flow reads. */
482
+ function refuseUnauthorized(entryId, ctx, path, reason, message, deps, now) {
483
+ deps.telemetry.emit({
484
+ key: "decision.unauthorized",
485
+ at: now,
486
+ attributes: {
487
+ "entry.id": entryId,
488
+ "gen_ai.conversation.id": ctx.conversationId,
489
+ reason,
490
+ // The kind, never the id: an event stream is not an audit record, and the
491
+ // record of who decided is the attestation on the row (AZ-1).
492
+ "principal.kind": ctx.principal?.kind ?? "unresolved",
493
+ path,
494
+ },
495
+ });
496
+ return new AffiantError("decision-unauthorized", message, { entryId, reason });
497
+ }
498
+ /**
499
+ * Preserve the amendments a late decision carried and refuse it (DK-1).
500
+ *
501
+ * The preservation is a separate store write on purpose: the compare-and-set that
502
+ * refused the decision must not also write to the row, or "applied once or not at
503
+ * all" stops being true. What is written is the map and nothing else — not a status,
504
+ * not a decision record, not an attestation. Nobody decided anything here.
505
+ *
506
+ * Two conditions on writing it at all, both about not letting a refused call put
507
+ * something on the record that a later resubmission would treat as a person's act:
508
+ *
509
+ * - the map's field names are checked against the Affidavit first, exactly as
510
+ * `applyAmendments` checks them on the path that was not late, so a caller learns
511
+ * about a bad field name here rather than in whoever resubmits the entry;
512
+ * - the caller must be able to attest at all (AZ-3). A resubmission prefills these
513
+ * values with a `UserStated` tag, and PV-3 forbids a machine from putting words in
514
+ * a person's mouth — so a machine caller with nothing to relay leaves nothing
515
+ * behind, even though its refusal is the expiry, not its identity.
516
+ */
517
+ async function refuseExpired(entryId, scope, entry, amendments, principal, now, deps) {
518
+ let preserved = false;
519
+ if (amendments !== null && Object.keys(amendments).length > 0) {
520
+ requireAmendableFields(entry.affidavit, amendments);
521
+ const attestor = attestorOf(principal);
522
+ if (attestor !== null) {
523
+ // The refused decision's **own** instant and principal (DK-1, PV-2): a
524
+ // resubmission binds each prefilled field's tag to this act, and dating it to
525
+ // the row's deadline would place the correction at a moment nobody typed.
526
+ const result = await deps.store.preserveAmendments(entryId, scope, amendments, {
527
+ at: now,
528
+ by: subjectOf(attestor),
529
+ });
530
+ preserved = typeof result !== "string";
531
+ }
532
+ }
533
+ return new AffiantError("decision-expired", `DK-1: Docket entry ${JSON.stringify(entryId)} passed its deadline at ${entry.expiresAt} ` +
534
+ `and reads expired, whether or not a sweep has run. The decision is refused` +
535
+ (preserved
536
+ ? `; the amendments it carried are preserved on the row for a resubmission.`
537
+ : `.`), { entryId, expiresAt: entry.expiresAt, amendmentsPreserved: preserved });
538
+ }
539
+ /**
540
+ * Refuse an amendment map that names a field the Affidavit does not propose (DK-2).
541
+ *
542
+ * A `RangeError` and not an `AffiantError`, and the same message `applyAmendments`
543
+ * raises: the {@link ErrorCode} registry names refusals the gate makes about a
544
+ * proposal's substance or a decider's identity, and a field name that is not there is
545
+ * a caller passing an index out of range.
546
+ */
547
+ function requireAmendableFields(affidavit, map) {
548
+ for (const resolved of resolveAmendments(map)) {
549
+ if (!affidavit.fields.some((field) => field.name === resolved.name)) {
550
+ throw new RangeError(`amendment names field ${JSON.stringify(resolved.name)}, which this Affidavit does ` +
551
+ `not propose`);
552
+ }
553
+ }
554
+ }
555
+ /** The one answer a caller outside the tenant ever gets, and the answer a bad id gets. */
556
+ function notFound(entryId, ctx) {
557
+ return new AffiantError("entry-not-found", `no Docket entry ${JSON.stringify(entryId)} is visible in this tenant.`, { entryId, tenantId: ctx.tenantId });
558
+ }
559
+ //# sourceMappingURL=decide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decide.js","sourceRoot":"","sources":["../../src/gate/decide.ts"],"names":[],"mappings":"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"}