@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,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createGate` — the object a host builds once, and the wire-up checks it refuses at.
|
|
3
|
+
*
|
|
4
|
+
* **Rules served: CV-1** (a misconfiguration the framework can detect fails at
|
|
5
|
+
* wire-up with a stated error; no option turns the gate off), **GT-2** (every entry
|
|
6
|
+
* point takes the turn context as a parameter), **GT-5** (a policy that can declare a
|
|
7
|
+
* risk threshold needs a host-supplied scorer, and its absence is caught here rather
|
|
8
|
+
* than on the unlucky request that first reaches the threshold branch), **GT-4**
|
|
9
|
+
* (`defaultTtlMs` is required and so is every policy's own default: `expiresAt` is
|
|
10
|
+
* not nullable, so every filed entry carries a deadline and there is no wiring in
|
|
11
|
+
* which one is missing), **CV-4** (`declareUncovered`), **DK-3** (`expireDue` is
|
|
12
|
+
* host-scheduled — this package owns no timer).
|
|
13
|
+
*
|
|
14
|
+
* ## What is deliberately not on this object
|
|
15
|
+
*
|
|
16
|
+
* There is no `execute`, and no executor port in {@link GateOptions} for one to be
|
|
17
|
+
* built from. AZ-7 says no package in an implementation writes to a host's store, so
|
|
18
|
+
* the gate has nothing to call: the only path to `execution: "executed"` is
|
|
19
|
+
* {@link Gate.markExecuted}, the host's own executor reporting what it did.
|
|
20
|
+
*
|
|
21
|
+
* ## Two ways in
|
|
22
|
+
*
|
|
23
|
+
* {@link Gate.wrap} is Sequence A: a chat turn, a tool the model calls, the pipeline
|
|
24
|
+
* from the top. {@link Gate.file} is Sequence C: a capture that arrived over a trusted
|
|
25
|
+
* relay's MCP surface with its provenance already settled, entering at the projection
|
|
26
|
+
* step. They are the same pipeline; the second skips the two steps that have nothing
|
|
27
|
+
* to do.
|
|
28
|
+
*
|
|
29
|
+
* @packageDocumentation
|
|
30
|
+
*/
|
|
31
|
+
import type { TurnContext } from "../context.js";
|
|
32
|
+
import type { DocketEntry } from "../docket/entry.js";
|
|
33
|
+
import type { DocketStore, Page, PageResult, Scope, SessionStore } from "../docket/store.js";
|
|
34
|
+
import type { JsonValue } from "../model/affidavit.js";
|
|
35
|
+
import type { Clock, FieldInterceptor, FieldSchema, InferencePort, Operation, ProjectionPort, RiskScorer, TelemetryPort } from "../ports.js";
|
|
36
|
+
import type { AuthorizationPort } from "../ports.js";
|
|
37
|
+
import type { CoverageRegistry, ToolDefinition, UncoveredCategory } from "./coverage.js";
|
|
38
|
+
import type { Decision, ExecutionReport } from "./decide.js";
|
|
39
|
+
import type { FiledEntry, PreparedField } from "./pipeline.js";
|
|
40
|
+
import type { ApprovalPolicy } from "./policy.js";
|
|
41
|
+
import type { GatedTool } from "./wrap.js";
|
|
42
|
+
/**
|
|
43
|
+
* Everything a host supplies. The four ports and the deadline are required; the rest
|
|
44
|
+
* have defaults that are the safe reading of "the host said nothing".
|
|
45
|
+
*
|
|
46
|
+
* `policies` defaults to none, which files everything `ReviewerConfirmation` — a
|
|
47
|
+
* person confirms every write. `interceptors` defaults to none. `telemetry` defaults
|
|
48
|
+
* to a port that drops events. `clock` defaults to the system clock, which is the one
|
|
49
|
+
* dependency a fixture always replaces.
|
|
50
|
+
*/
|
|
51
|
+
export interface GateOptions {
|
|
52
|
+
/** The Docket (DK-1). */
|
|
53
|
+
readonly store: DocketStore;
|
|
54
|
+
/**
|
|
55
|
+
* The rehydration surface, if the host has one (DK-5). Not used by the pipeline;
|
|
56
|
+
* {@link Gate.rehydrate} refuses when it is absent.
|
|
57
|
+
*/
|
|
58
|
+
readonly sessions?: SessionStore;
|
|
59
|
+
/** The host's structured inference (GT-1 step 3). */
|
|
60
|
+
readonly inference: InferencePort;
|
|
61
|
+
/** The host's previous-value lookup (AF-3). */
|
|
62
|
+
readonly projection: ProjectionPort;
|
|
63
|
+
/** Who may decide an entry (AZ-2). Consulted on every decision, execution report and resubmission. */
|
|
64
|
+
readonly authorization: AuthorizationPort;
|
|
65
|
+
/** The approval chain, in order (AZ-4). */
|
|
66
|
+
readonly policies?: readonly ApprovalPolicy[];
|
|
67
|
+
/** The host's risk function (GT-5). Required if any policy declares a threshold. */
|
|
68
|
+
readonly riskScorer?: RiskScorer;
|
|
69
|
+
/** Deterministic resolvers (PV-2). */
|
|
70
|
+
readonly interceptors?: readonly FieldInterceptor[];
|
|
71
|
+
/** Where every instant on the record comes from. */
|
|
72
|
+
readonly clock?: Clock;
|
|
73
|
+
/** Where the TL-1 events go. */
|
|
74
|
+
readonly telemetry?: TelemetryPort;
|
|
75
|
+
/**
|
|
76
|
+
* The deadline applied when neither the verdict nor the policy names one (GT-4).
|
|
77
|
+
* **Required**: `expiresAt` is not nullable, so every filed entry carries a
|
|
78
|
+
* deadline and there is no wiring in which one is missing.
|
|
79
|
+
*/
|
|
80
|
+
readonly defaultTtlMs: number;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* A capture the host has already assembled — Sequence C's way in.
|
|
84
|
+
*
|
|
85
|
+
* Supply `fields` when the provenance is settled (a relay's capture, a form
|
|
86
|
+
* submission, a replay): the pipeline skips the interceptors and the inference and
|
|
87
|
+
* starts at projection. Supply `schema` instead to run the whole pipeline against the
|
|
88
|
+
* turn without a {@link ToolDefinition}. Supplying neither is a wire-up error — there
|
|
89
|
+
* would be nothing to swear to and no way to find out.
|
|
90
|
+
*/
|
|
91
|
+
export interface WriteProposal {
|
|
92
|
+
/** The write being proposed. */
|
|
93
|
+
readonly operation: Operation;
|
|
94
|
+
/** The tool or capture source's name — the key a coverage declaration matches (CV-4). */
|
|
95
|
+
readonly toolName: string;
|
|
96
|
+
/** Host-tagged fields. Present ⇒ interceptors and inference are skipped. */
|
|
97
|
+
readonly fields?: readonly PreparedField[];
|
|
98
|
+
/** The field schema, for a proposal that should run inference. */
|
|
99
|
+
readonly schema?: FieldSchema;
|
|
100
|
+
/**
|
|
101
|
+
* The arguments this capture came from, part of the entry id's derivation.
|
|
102
|
+
*
|
|
103
|
+
* A {@link JsonValue}, because that is what tool arguments are: the id derivation
|
|
104
|
+
* canonicalises them, and a value with no canonical form is a caller bug the type
|
|
105
|
+
* says so about rather than a `TypeError` at the first filing.
|
|
106
|
+
*/
|
|
107
|
+
readonly args?: JsonValue;
|
|
108
|
+
/** The host's own verb for the operation, carried onto the card. */
|
|
109
|
+
readonly operationLabel?: string;
|
|
110
|
+
}
|
|
111
|
+
/** The gate a host builds once and calls from every seam (CV-2). */
|
|
112
|
+
export interface Gate {
|
|
113
|
+
/**
|
|
114
|
+
* Put the gate in front of `tool` for the turn `ctx` describes (GT-2, GT-6, CV-4).
|
|
115
|
+
*
|
|
116
|
+
* @throws AffiantError `"coverage-refused"` or `"wireup-invalid"` at wire-up.
|
|
117
|
+
*/
|
|
118
|
+
wrap<TArgs, TResult>(tool: ToolDefinition<TArgs, TResult>, ctx: TurnContext): GatedTool<TArgs, TResult>;
|
|
119
|
+
/**
|
|
120
|
+
* File a host-assembled proposal — Sequence C's entry point.
|
|
121
|
+
*
|
|
122
|
+
* @throws AffiantError `"substance-refused"` when the capture swears to nothing
|
|
123
|
+
* (GT-3), or `"wireup-invalid"` when the proposal carries neither prepared
|
|
124
|
+
* fields nor a schema.
|
|
125
|
+
*/
|
|
126
|
+
file(proposal: WriteProposal, ctx: TurnContext): Promise<FiledEntry>;
|
|
127
|
+
/**
|
|
128
|
+
* Record that the gate cannot intercept `tool`, so every later proposal from it is
|
|
129
|
+
* filed `blocked` rather than refused at wire-up (CV-4). It never allows the tool.
|
|
130
|
+
*/
|
|
131
|
+
declareUncovered(tool: Pick<ToolDefinition, "name">, category: UncoveredCategory): void;
|
|
132
|
+
/**
|
|
133
|
+
* Approve, amend or reject an entry, as `ctx.principal` (DK-1, AZ-1, AZ-2, AZ-3).
|
|
134
|
+
*
|
|
135
|
+
* @throws AffiantError `"decision-unauthorized"`, `"entry-not-found"`,
|
|
136
|
+
* `"decision-expired"`, `"decision-not-pending"` or `"decision-lost-race"`.
|
|
137
|
+
*/
|
|
138
|
+
decide(entryId: string, decision: Decision, ctx: TurnContext): Promise<DocketEntry>;
|
|
139
|
+
/**
|
|
140
|
+
* Record what the host's executor did with an approved write (DK-1, AZ-5, AZ-7).
|
|
141
|
+
*
|
|
142
|
+
* The only public path to `execution: "executed"`. The gate never calls an executor
|
|
143
|
+
* to get there — a host reads its approved-and-unexecuted rows, writes, and reports.
|
|
144
|
+
*
|
|
145
|
+
* @throws AffiantError `"decision-unauthorized"`, `"entry-not-found"`, or
|
|
146
|
+
* `"decision-not-pending"` when the row is not approved.
|
|
147
|
+
*/
|
|
148
|
+
markExecuted(entryId: string, outcome: ExecutionReport, detail: string | null, ctx: TurnContext): Promise<DocketEntry>;
|
|
149
|
+
/**
|
|
150
|
+
* File an expired entry again as a new entry whose lineage names it (DK-1).
|
|
151
|
+
*
|
|
152
|
+
* @throws AffiantError `"decision-unauthorized"`, `"entry-not-found"`, or
|
|
153
|
+
* `"decision-not-pending"` when the entry does not read `expired`.
|
|
154
|
+
*/
|
|
155
|
+
resubmit(entryId: string, ctx: TurnContext): Promise<FiledEntry>;
|
|
156
|
+
/**
|
|
157
|
+
* The entry as it reads now, within `ctx`'s tenant, or `null` (DK-1, expiry as
|
|
158
|
+
* state).
|
|
159
|
+
*
|
|
160
|
+
* **Tenant scope, not conversation scope, and that widening is deliberate.** A
|
|
161
|
+
* reviewer surface is not the conversation that proposed the write: a person opens
|
|
162
|
+
* a queue, or follows a link, and reads an entry filed in some other conversation
|
|
163
|
+
* of the same tenant. AZ-2's boundary is the tenant, and GT-2's "two conversations
|
|
164
|
+
* never observe each other" is about the turn's *own* state — its fields, its
|
|
165
|
+
* pending inference, its proposals — not about a Docket a tenant's reviewers
|
|
166
|
+
* share. Narrowing this to `{ tenantId, conversationId }` would break every
|
|
167
|
+
* reviewer surface; `gate-scope.test.ts` pins the widening so it cannot be
|
|
168
|
+
* "tightened" with a green suite.
|
|
169
|
+
*/
|
|
170
|
+
get(entryId: string, ctx: TurnContext): Promise<DocketEntry | null>;
|
|
171
|
+
/**
|
|
172
|
+
* One page of what a reconnecting client needs: everything that reads `pending`,
|
|
173
|
+
* then everything `approved` and `unexecuted`, each in filing order (DK-5).
|
|
174
|
+
*
|
|
175
|
+
* @throws AffiantError `"wireup-invalid"` when the host supplied no
|
|
176
|
+
* {@link GateOptions.sessions}. It is the one wiring check that cannot
|
|
177
|
+
* happen at `createGate`: a host with no reconnecting client needs no
|
|
178
|
+
* session store, and refusing to build a gate without one would be the
|
|
179
|
+
* framework insisting on a surface the host does not have.
|
|
180
|
+
*/
|
|
181
|
+
rehydrate(scope: Scope, page: Page): Promise<PageResult<DocketEntry>>;
|
|
182
|
+
/**
|
|
183
|
+
* Expire the pending entries in `scope` that are past their deadline, at most
|
|
184
|
+
* `limit` of them (DK-3). The host schedules this; the core owns no timer.
|
|
185
|
+
*/
|
|
186
|
+
expireDue(now: string, scope: Scope, limit: number): Promise<{
|
|
187
|
+
readonly expired: readonly string[];
|
|
188
|
+
readonly more: boolean;
|
|
189
|
+
}>;
|
|
190
|
+
/** The uncovered declarations this gate holds (CV-4). */
|
|
191
|
+
readonly coverage: CoverageRegistry;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Build the gate, refusing a wiring it can tell is wrong (CV-1).
|
|
195
|
+
*
|
|
196
|
+
* Every refusal names the missing piece, because a wire-up error a host has to bisect
|
|
197
|
+
* is a wire-up error a host works around. The checks:
|
|
198
|
+
*
|
|
199
|
+
* - the four ports — `store`, `inference`, `projection`, `authorization` — are present;
|
|
200
|
+
* - `defaultTtlMs` is a positive, finite integer of milliseconds (GT-4);
|
|
201
|
+
* - every policy carrying its own {@link ApprovalPolicy.defaultTtlMs} states it the
|
|
202
|
+
* same way (GT-4), so a policy that would file an entry nobody can decide is
|
|
203
|
+
* refused here rather than on the request that first falls through to it;
|
|
204
|
+
* - every policy that says {@link ApprovalPolicy.declaresThreshold} has a
|
|
205
|
+
* `riskScorer` to compare against (GT-5). This is checked from the **static**
|
|
206
|
+
* declaration, before any evaluation, because a check that only fires when a policy
|
|
207
|
+
* happens to return a threshold is exactly the "silent non-fire" GT-5 forbids.
|
|
208
|
+
*
|
|
209
|
+
* @throws AffiantError `"wireup-invalid"`, naming what is missing.
|
|
210
|
+
*/
|
|
211
|
+
export declare function createGate(options: GateOptions): Gate;
|
|
212
|
+
//# sourceMappingURL=gate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.d.ts","sourceRoot":"","sources":["../../src/gate/gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `createGate` — the object a host builds once, and the wire-up checks it refuses at.
|
|
3
|
+
*
|
|
4
|
+
* **Rules served: CV-1** (a misconfiguration the framework can detect fails at
|
|
5
|
+
* wire-up with a stated error; no option turns the gate off), **GT-2** (every entry
|
|
6
|
+
* point takes the turn context as a parameter), **GT-5** (a policy that can declare a
|
|
7
|
+
* risk threshold needs a host-supplied scorer, and its absence is caught here rather
|
|
8
|
+
* than on the unlucky request that first reaches the threshold branch), **GT-4**
|
|
9
|
+
* (`defaultTtlMs` is required and so is every policy's own default: `expiresAt` is
|
|
10
|
+
* not nullable, so every filed entry carries a deadline and there is no wiring in
|
|
11
|
+
* which one is missing), **CV-4** (`declareUncovered`), **DK-3** (`expireDue` is
|
|
12
|
+
* host-scheduled — this package owns no timer).
|
|
13
|
+
*
|
|
14
|
+
* ## What is deliberately not on this object
|
|
15
|
+
*
|
|
16
|
+
* There is no `execute`, and no executor port in {@link GateOptions} for one to be
|
|
17
|
+
* built from. AZ-7 says no package in an implementation writes to a host's store, so
|
|
18
|
+
* the gate has nothing to call: the only path to `execution: "executed"` is
|
|
19
|
+
* {@link Gate.markExecuted}, the host's own executor reporting what it did.
|
|
20
|
+
*
|
|
21
|
+
* ## Two ways in
|
|
22
|
+
*
|
|
23
|
+
* {@link Gate.wrap} is Sequence A: a chat turn, a tool the model calls, the pipeline
|
|
24
|
+
* from the top. {@link Gate.file} is Sequence C: a capture that arrived over a trusted
|
|
25
|
+
* relay's MCP surface with its provenance already settled, entering at the projection
|
|
26
|
+
* step. They are the same pipeline; the second skips the two steps that have nothing
|
|
27
|
+
* to do.
|
|
28
|
+
*
|
|
29
|
+
* @packageDocumentation
|
|
30
|
+
*/
|
|
31
|
+
import { AffiantError } from "../errors.js";
|
|
32
|
+
import { defaultClock } from "../ports.js";
|
|
33
|
+
import { noopTelemetry } from "../telemetry.js";
|
|
34
|
+
import { createCoverageRegistry, declareUncovered } from "./coverage.js";
|
|
35
|
+
import { decide, markExecuted, resubmit } from "./decide.js";
|
|
36
|
+
import { runPipeline } from "./pipeline.js";
|
|
37
|
+
import { isUsableTtlMs, unusableTtlMessage } from "./policy.js";
|
|
38
|
+
import { wrapTool } from "./wrap.js";
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Wire-up
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
/**
|
|
43
|
+
* Build the gate, refusing a wiring it can tell is wrong (CV-1).
|
|
44
|
+
*
|
|
45
|
+
* Every refusal names the missing piece, because a wire-up error a host has to bisect
|
|
46
|
+
* is a wire-up error a host works around. The checks:
|
|
47
|
+
*
|
|
48
|
+
* - the four ports — `store`, `inference`, `projection`, `authorization` — are present;
|
|
49
|
+
* - `defaultTtlMs` is a positive, finite integer of milliseconds (GT-4);
|
|
50
|
+
* - every policy carrying its own {@link ApprovalPolicy.defaultTtlMs} states it the
|
|
51
|
+
* same way (GT-4), so a policy that would file an entry nobody can decide is
|
|
52
|
+
* refused here rather than on the request that first falls through to it;
|
|
53
|
+
* - every policy that says {@link ApprovalPolicy.declaresThreshold} has a
|
|
54
|
+
* `riskScorer` to compare against (GT-5). This is checked from the **static**
|
|
55
|
+
* declaration, before any evaluation, because a check that only fires when a policy
|
|
56
|
+
* happens to return a threshold is exactly the "silent non-fire" GT-5 forbids.
|
|
57
|
+
*
|
|
58
|
+
* @throws AffiantError `"wireup-invalid"`, naming what is missing.
|
|
59
|
+
*/
|
|
60
|
+
export function createGate(options) {
|
|
61
|
+
requirePort(options.store, "store", "the Docket every entry is filed in (DK-1)");
|
|
62
|
+
requirePort(options.inference, "inference", "the host's structured inference (GT-1 step 3)");
|
|
63
|
+
requirePort(options.projection, "projection", "the host's previous-value lookup (AF-3)");
|
|
64
|
+
requirePort(options.authorization, "authorization", "who may decide an entry (AZ-2)");
|
|
65
|
+
const defaultTtlMs = options.defaultTtlMs;
|
|
66
|
+
if (!Number.isInteger(defaultTtlMs) || defaultTtlMs <= 0) {
|
|
67
|
+
throw new AffiantError("wireup-invalid", `CV-1: GateOptions.defaultTtlMs must be a positive whole number of milliseconds; ` +
|
|
68
|
+
`received ${JSON.stringify(defaultTtlMs)}. Every filed entry carries a deadline (GT-4), ` +
|
|
69
|
+
`so there is no wiring in which this is absent.`, { option: "defaultTtlMs" });
|
|
70
|
+
}
|
|
71
|
+
const policies = options.policies ?? [];
|
|
72
|
+
for (const policy of policies) {
|
|
73
|
+
// The same rule as `GateOptions.defaultTtlMs`, applied to the other place the
|
|
74
|
+
// same value comes from. A verdict's own `ttlMs` cannot be seen from here — it
|
|
75
|
+
// exists only once a policy has spoken — so `evaluatePolicies` holds that one to
|
|
76
|
+
// this definition at the moment it reads it.
|
|
77
|
+
if (policy.defaultTtlMs !== undefined && !isUsableTtlMs(policy.defaultTtlMs)) {
|
|
78
|
+
throw new AffiantError("wireup-invalid", unusableTtlMessage(policy.id, "defaultTtlMs", policy.defaultTtlMs), { option: "defaultTtlMs", policyId: policy.id, ttlMs: String(policy.defaultTtlMs) });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (options.riskScorer === undefined) {
|
|
82
|
+
const needsScorer = policies.filter((policy) => policy.declaresThreshold === true);
|
|
83
|
+
if (needsScorer.length > 0) {
|
|
84
|
+
throw new AffiantError("wireup-invalid", `CV-1: policy ${needsScorer.map((policy) => JSON.stringify(policy.id)).join(", ")} ` +
|
|
85
|
+
`declares a risk threshold and no GateOptions.riskScorer was supplied. This package ` +
|
|
86
|
+
`ships no scoring formula and no floor (GT-5): the host owns the risk function, and ` +
|
|
87
|
+
`a declared threshold with nothing to compare against is a configuration error, never ` +
|
|
88
|
+
`a silent non-fire.`, { option: "riskScorer", policyIds: needsScorer.map((policy) => policy.id) });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const coverage = createCoverageRegistry();
|
|
92
|
+
const clock = options.clock ?? defaultClock;
|
|
93
|
+
const telemetry = options.telemetry ?? noopTelemetry;
|
|
94
|
+
const store = options.store;
|
|
95
|
+
const deps = {
|
|
96
|
+
store,
|
|
97
|
+
inference: options.inference,
|
|
98
|
+
projection: options.projection,
|
|
99
|
+
policies,
|
|
100
|
+
interceptors: options.interceptors ?? [],
|
|
101
|
+
riskScorer: options.riskScorer,
|
|
102
|
+
clock,
|
|
103
|
+
telemetry,
|
|
104
|
+
defaultTtlMs,
|
|
105
|
+
coverage,
|
|
106
|
+
};
|
|
107
|
+
const sessions = options.sessions ?? null;
|
|
108
|
+
const decideDeps = { ...deps, authorization: options.authorization, sessions };
|
|
109
|
+
return {
|
|
110
|
+
coverage,
|
|
111
|
+
wrap(tool, ctx) {
|
|
112
|
+
return wrapTool(tool, ctx, deps);
|
|
113
|
+
},
|
|
114
|
+
async file(proposal, ctx) {
|
|
115
|
+
const fields = proposal.fields ?? null;
|
|
116
|
+
const schema = proposal.schema ?? null;
|
|
117
|
+
if (fields === null && schema === null) {
|
|
118
|
+
throw new AffiantError("wireup-invalid", `CV-1: a proposal for ${JSON.stringify(proposal.toolName)} carries neither prepared ` +
|
|
119
|
+
`fields nor a field schema. Supply \`fields\` when the capture's provenance is ` +
|
|
120
|
+
`already settled (Sequence C), or \`schema\` to run the inference step against the ` +
|
|
121
|
+
`turn. With neither there is nothing to swear to.`, { toolName: proposal.toolName });
|
|
122
|
+
}
|
|
123
|
+
return runPipeline({
|
|
124
|
+
operation: proposal.operation,
|
|
125
|
+
toolName: proposal.toolName,
|
|
126
|
+
schema,
|
|
127
|
+
args: proposal.args ?? null,
|
|
128
|
+
preparedFields: fields,
|
|
129
|
+
operationLabel: proposal.operationLabel ?? null,
|
|
130
|
+
supersedes: null,
|
|
131
|
+
priorAmendments: null,
|
|
132
|
+
}, ctx, deps);
|
|
133
|
+
},
|
|
134
|
+
declareUncovered(tool, category) {
|
|
135
|
+
declareUncovered(coverage, tool, category);
|
|
136
|
+
},
|
|
137
|
+
async decide(entryId, decision, ctx) {
|
|
138
|
+
return decide(entryId, decision, ctx, decideDeps);
|
|
139
|
+
},
|
|
140
|
+
async markExecuted(entryId, outcome, detail, ctx) {
|
|
141
|
+
return markExecuted(entryId, outcome, detail, ctx, decideDeps);
|
|
142
|
+
},
|
|
143
|
+
async resubmit(entryId, ctx) {
|
|
144
|
+
return resubmit(entryId, ctx, decideDeps);
|
|
145
|
+
},
|
|
146
|
+
async rehydrate(scope, page) {
|
|
147
|
+
if (sessions === null) {
|
|
148
|
+
throw new AffiantError("wireup-invalid", `DK-5: GateOptions.sessions is required to rehydrate — it is the surface that ` +
|
|
149
|
+
`returns pending entries and then approved, unexecuted ones, in that order. ` +
|
|
150
|
+
`Supply a SessionStore, or do not call this.`, { option: "sessions" });
|
|
151
|
+
}
|
|
152
|
+
return sessions.rehydrate(scope, page);
|
|
153
|
+
},
|
|
154
|
+
async get(entryId, ctx) {
|
|
155
|
+
// Tenant scope, not conversation scope: a reviewer surface reads an entry filed
|
|
156
|
+
// in another conversation of the same tenant, and AZ-2's boundary is the tenant.
|
|
157
|
+
return store.get(entryId, { tenantId: ctx.tenantId });
|
|
158
|
+
},
|
|
159
|
+
async expireDue(now, scope, limit) {
|
|
160
|
+
const result = await store.expireDue(now, scope, limit);
|
|
161
|
+
for (const entryId of result.expired) {
|
|
162
|
+
telemetry.emit({ key: "docket.expired", at: now, attributes: { "entry.id": entryId } });
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
/** Refuse a missing port by name, so a host is told what to supply rather than what broke. */
|
|
169
|
+
function requirePort(value, option, what) {
|
|
170
|
+
if (value === null || value === undefined) {
|
|
171
|
+
throw new AffiantError("wireup-invalid", `CV-1: GateOptions.${option} is required — ${what}. A misconfiguration the gate can ` +
|
|
172
|
+
`detect fails here, at wire-up, and there is no option that turns the gate off.`, { option });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gate.js","sourceRoot":"","sources":["../../src/gate/gate.ts"],"names":[],"mappings":"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"}
|