@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.
- package/LICENSE +202 -0
- package/README.md +354 -0
- package/dist/context.d.ts +136 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +30 -0
- package/dist/context.js.map +1 -0
- package/dist/docket/entry.d.ts +421 -0
- package/dist/docket/entry.d.ts.map +1 -0
- package/dist/docket/entry.js +155 -0
- package/dist/docket/entry.js.map +1 -0
- package/dist/docket/expiry.d.ts +82 -0
- package/dist/docket/expiry.d.ts.map +1 -0
- package/dist/docket/expiry.js +106 -0
- package/dist/docket/expiry.js.map +1 -0
- package/dist/docket/memory.d.ts +163 -0
- package/dist/docket/memory.d.ts.map +1 -0
- package/dist/docket/memory.js +528 -0
- package/dist/docket/memory.js.map +1 -0
- package/dist/docket/store.d.ts +387 -0
- package/dist/docket/store.d.ts.map +1 -0
- package/dist/docket/store.js +51 -0
- package/dist/docket/store.js.map +1 -0
- package/dist/errors.d.ts +153 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +164 -0
- package/dist/errors.js.map +1 -0
- package/dist/gate/coverage.d.ts +152 -0
- package/dist/gate/coverage.d.ts.map +1 -0
- package/dist/gate/coverage.js +114 -0
- package/dist/gate/coverage.js.map +1 -0
- package/dist/gate/decide.d.ts +207 -0
- package/dist/gate/decide.d.ts.map +1 -0
- package/dist/gate/decide.js +559 -0
- package/dist/gate/decide.js.map +1 -0
- package/dist/gate/gate.d.ts +212 -0
- package/dist/gate/gate.d.ts.map +1 -0
- package/dist/gate/gate.js +175 -0
- package/dist/gate/gate.js.map +1 -0
- package/dist/gate/pipeline.d.ts +285 -0
- package/dist/gate/pipeline.d.ts.map +1 -0
- package/dist/gate/pipeline.js +515 -0
- package/dist/gate/pipeline.js.map +1 -0
- package/dist/gate/policy.d.ts +272 -0
- package/dist/gate/policy.d.ts.map +1 -0
- package/dist/gate/policy.js +396 -0
- package/dist/gate/policy.js.map +1 -0
- package/dist/gate/wrap.d.ts +107 -0
- package/dist/gate/wrap.d.ts.map +1 -0
- package/dist/gate/wrap.js +164 -0
- package/dist/gate/wrap.js.map +1 -0
- package/dist/index.d.ts +95 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +111 -0
- package/dist/index.js.map +1 -0
- package/dist/model/affidavit.d.ts +354 -0
- package/dist/model/affidavit.d.ts.map +1 -0
- package/dist/model/affidavit.js +417 -0
- package/dist/model/affidavit.js.map +1 -0
- package/dist/model/amendments.d.ts +160 -0
- package/dist/model/amendments.d.ts.map +1 -0
- package/dist/model/amendments.js +183 -0
- package/dist/model/amendments.js.map +1 -0
- package/dist/model/canonical.d.ts +311 -0
- package/dist/model/canonical.d.ts.map +1 -0
- package/dist/model/canonical.js +665 -0
- package/dist/model/canonical.js.map +1 -0
- package/dist/model/money.d.ts +127 -0
- package/dist/model/money.d.ts.map +1 -0
- package/dist/model/money.js +177 -0
- package/dist/model/money.js.map +1 -0
- package/dist/model/provenance.d.ts +315 -0
- package/dist/model/provenance.d.ts.map +1 -0
- package/dist/model/provenance.js +223 -0
- package/dist/model/provenance.js.map +1 -0
- package/dist/ports.d.ts +269 -0
- package/dist/ports.d.ts.map +1 -0
- package/dist/ports.js +34 -0
- package/dist/ports.js.map +1 -0
- package/dist/store-memory.d.ts +21 -0
- package/dist/store-memory.d.ts.map +1 -0
- package/dist/store-memory.js +20 -0
- package/dist/store-memory.js.map +1 -0
- package/dist/telemetry-keys.d.ts +65 -0
- package/dist/telemetry-keys.d.ts.map +1 -0
- package/dist/telemetry-keys.js +72 -0
- package/dist/telemetry-keys.js.map +1 -0
- package/dist/telemetry.d.ts +77 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +43 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/testing.d.ts +574 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +1291 -0
- package/dist/testing.js.map +1 -0
- package/package.json +75 -0
- 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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"}
|