@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
package/dist/errors.js ADDED
@@ -0,0 +1,164 @@
1
+ /**
2
+ * The error the gate throws, and the closed set of codes it throws with.
3
+ *
4
+ * **Rules served: CV-1** (hard-fail at wire-up; there is no disable switch),
5
+ * **AZ-4** (a requirement the implementation does not run is refused, never
6
+ * silently degraded).
7
+ *
8
+ * CV-1 in one sentence: *a misconfiguration the framework can detect fails at
9
+ * wire-up with a stated error, and no option turns the gate off for a tool it
10
+ * covers.* Every such failure is an {@link AffiantError} carrying one
11
+ * {@link ErrorCode} — a machine-readable reason a host can branch on and a
12
+ * conformance fixture can assert, rather than a message string that drifts.
13
+ *
14
+ * The codes are a closed union on purpose. A refusal that cannot be named here is
15
+ * a refusal no fixture can pin, and a host that cannot distinguish "you wired this
16
+ * wrong" from "the reviewer rejected it" will paper over the first.
17
+ *
18
+ * @packageDocumentation
19
+ */
20
+ /**
21
+ * Every reason the gate refuses, keyed by itself.
22
+ *
23
+ * The key and the value are the same string because the string *is* the API: it is
24
+ * what a fixture asserts and what a host branches on, so there is exactly one
25
+ * spelling to remember. Read a code as `ErrorCode["substance-refused"]`, or write
26
+ * the literal — both type-check.
27
+ *
28
+ * Three codes are marked **provisional**: they are named by the v0.1 design but the
29
+ * protocol rulebook does not yet carry an `ErrorCode` registry. When it does, those
30
+ * three are the ones that may be renamed to match it; the other seven describe
31
+ * behaviour the rulebook already fixes.
32
+ */
33
+ export const ErrorCode = {
34
+ /**
35
+ * A requirement this implementation recognises but does not run — a `MultiParty`
36
+ * approval, a `ReferralRequired` referral — reached the pipeline. The entry is
37
+ * filed `pending` and marked blocked; every decision on it is refused. Never
38
+ * degraded to a weaker requirement (AZ-4).
39
+ *
40
+ * **Provisional** until the protocol's `ErrorCode` registry lands.
41
+ */
42
+ "requirement-not-implemented": "requirement-not-implemented",
43
+ /**
44
+ * A tool the gate must cover cannot be intercepted — it is write-capable with no
45
+ * `execute` to replace, it is executed by the model provider, or it is a hosted
46
+ * MCP tool. Raised at wire-up (CV-4, CV-1), or carried on a proposal from a tool
47
+ * the host explicitly declared uncovered.
48
+ *
49
+ * **Provisional** until the protocol's `ErrorCode` registry lands.
50
+ */
51
+ "coverage-refused": "coverage-refused",
52
+ /**
53
+ * A proposal reached the substance gate with nothing to swear to: no field
54
+ * carrying provenance other than `Empty`, or a non-empty value sitting under
55
+ * `Empty` provenance. Refused before anything is filed (GT-3).
56
+ */
57
+ "substance-refused": "substance-refused",
58
+ /**
59
+ * A decision was refused on identity grounds: the context carried no resolved
60
+ * principal, the entry belongs to another tenant, or the host's authorization
61
+ * port said no. Refused before the store is touched (AZ-2).
62
+ */
63
+ "decision-unauthorized": "decision-unauthorized",
64
+ /** A decision was made on an entry that is no longer `pending` (DK-1). */
65
+ "decision-not-pending": "decision-not-pending",
66
+ /**
67
+ * A decision was made on an entry that has passed its expiry. The entry reads
68
+ * `expired` whether or not the host's sweep has run; the decision's amendments
69
+ * are preserved on the row for a resubmission (DK-1).
70
+ */
71
+ "decision-expired": "decision-expired",
72
+ /**
73
+ * Two decisions raced for the same entry and this one lost the compare-and-set.
74
+ * A transition is applied once or not at all, never twice (DK-1).
75
+ */
76
+ "decision-lost-race": "decision-lost-race",
77
+ /**
78
+ * The gate was built wrong in a way it can detect: no store, no authorization
79
+ * port, a policy declaring a risk threshold with no scorer to compare against.
80
+ * Thrown from `createGate`, not on the first request (CV-1).
81
+ */
82
+ "wireup-invalid": "wireup-invalid",
83
+ /** No entry with that id is visible in the given scope (DK-1). */
84
+ "entry-not-found": "entry-not-found",
85
+ /**
86
+ * An execution outcome was reported against a row that already carries one. The
87
+ * first report stands and the row is untouched: a decision, once recorded, is
88
+ * never edited in place, and an approved-but-failed write must stay
89
+ * distinguishable from an approved-and-committed one (DK-4, DK-1).
90
+ *
91
+ * A host that retries a write reports **once**, when it knows the outcome (AZ-5:
92
+ * an outbox is a retry of an already-attested write, not a second authorization
93
+ * path, and not a second fact about what happened).
94
+ *
95
+ * **Provisional** until the protocol's `ErrorCode` registry lands.
96
+ */
97
+ "execution-already-recorded": "execution-already-recorded",
98
+ };
99
+ /**
100
+ * Every {@link ErrorCode} value, in registry order. Pinned as data so a runtime
101
+ * check and a fixture can use the same list the type does.
102
+ *
103
+ * **The order only ever grows at the end.** A code is added by appending it, never
104
+ * by inserting one among the codes that already shipped: the list is what a host's
105
+ * exhaustiveness check and a parity manifest read, and a reordering would look like
106
+ * a rename to both.
107
+ */
108
+ export const ERROR_CODES = [
109
+ "requirement-not-implemented",
110
+ "coverage-refused",
111
+ "substance-refused",
112
+ "decision-unauthorized",
113
+ "decision-not-pending",
114
+ "decision-expired",
115
+ "decision-lost-race",
116
+ "wireup-invalid",
117
+ "entry-not-found",
118
+ "execution-already-recorded",
119
+ ];
120
+ /** Whether `value` is one of the codes in {@link ErrorCode}. */
121
+ export function isErrorCode(value) {
122
+ return typeof value === "string" && ERROR_CODES.includes(value);
123
+ }
124
+ /**
125
+ * The error every refusal in this package throws.
126
+ *
127
+ * The `code` is the contract; the `message` is for a human reading a log. A host
128
+ * that branches on the message is doing it wrong, and a fixture that asserts on
129
+ * the message is asserting on prose.
130
+ */
131
+ export class AffiantError extends Error {
132
+ /** Why the gate refused. */
133
+ code;
134
+ /** Structured context for the refusal. `{}` when the throwing site supplied none. */
135
+ details;
136
+ /**
137
+ * @param code Why the gate refused.
138
+ * @param message A human-readable explanation. Defaults to the code itself.
139
+ * @param details Structured context for the refusal.
140
+ */
141
+ constructor(code, message, details) {
142
+ super(message ?? code);
143
+ this.name = "AffiantError";
144
+ this.code = code;
145
+ this.details = details ?? {};
146
+ }
147
+ }
148
+ /**
149
+ * Whether `value` is an {@link AffiantError}.
150
+ *
151
+ * `instanceof` first, then a structural check: a host can end up with two copies of
152
+ * this package in one process (a bundler, two versions in a dependency tree), and a
153
+ * `catch` that spans that boundary still has to give a true answer. The structural
154
+ * arm is deliberately narrow — an `Error` named `AffiantError` carrying a `code`
155
+ * from {@link ERROR_CODES}.
156
+ */
157
+ export function isAffiantError(value) {
158
+ if (value instanceof AffiantError)
159
+ return true;
160
+ return (value instanceof Error &&
161
+ value.name === "AffiantError" &&
162
+ isErrorCode(value.code));
163
+ }
164
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB;;;;;;;OAOG;IACH,6BAA6B,EAAE,6BAA6B;IAC5D;;;;;;;OAOG;IACH,kBAAkB,EAAE,kBAAkB;IACtC;;;;OAIG;IACH,mBAAmB,EAAE,mBAAmB;IACxC;;;;OAIG;IACH,uBAAuB,EAAE,uBAAuB;IAChD,0EAA0E;IAC1E,sBAAsB,EAAE,sBAAsB;IAC9C;;;;OAIG;IACH,kBAAkB,EAAE,kBAAkB;IACtC;;;OAGG;IACH,oBAAoB,EAAE,oBAAoB;IAC1C;;;;OAIG;IACH,gBAAgB,EAAE,gBAAgB;IAClC,kEAAkE;IAClE,iBAAiB,EAAE,iBAAiB;IACpC;;;;;;;;;;;OAWG;IACH,4BAA4B,EAAE,4BAA4B;CAClD,CAAC;AAKX;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,6BAA6B;IAC7B,kBAAkB;IAClB,mBAAmB;IACnB,uBAAuB;IACvB,sBAAsB;IACtB,kBAAkB;IAClB,oBAAoB;IACpB,gBAAgB;IAChB,iBAAiB;IACjB,4BAA4B;CACW,CAAC;AAE1C,gEAAgE;AAChE,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,WAAiC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzF,CAAC;AAcD;;;;;;GAMG;AACH,MAAM,OAAO,YAAa,SAAQ,KAAK;IACrC,4BAA4B;IACnB,IAAI,CAAY;IACzB,qFAAqF;IAC5E,OAAO,CAAsB;IAEtC;;;;OAIG;IACH,YAAY,IAAe,EAAE,OAAgB,EAAE,OAA6B;QAC1E,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,EAAE,CAAC;IAC/B,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,KAAK,YAAY,YAAY;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,CACL,KAAK,YAAY,KAAK;QACtB,KAAK,CAAC,IAAI,KAAK,cAAc;QAC7B,WAAW,CAAE,KAAqC,CAAC,IAAI,CAAC,CACzD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Coverage: which tools the gate can actually intercept, and what happens to the
3
+ * ones it cannot.
4
+ *
5
+ * **Rules served: CV-4** (a write-capable tool in an uncovered category is refused at
6
+ * wire-up, or — where wire-up cannot see it — marked `blocked` with code
7
+ * `coverage-refused` on the Docket; it is never silently allowed to write),
8
+ * **CV-1** (the refusal is at wire-up and there is no option that turns the gate off
9
+ * for a tool it covers), **AZ-4** (the blocked marker and its codes).
10
+ *
11
+ * ## The three categories
12
+ *
13
+ * A tool is *uncovered* when there is nothing for the gate to replace:
14
+ *
15
+ * - `"no-execute"` — the tool declares no `execute`. There is no function to stand in
16
+ * front of; whatever writes, writes somewhere this package cannot see.
17
+ * - `"provider-executed"` — the model provider runs the tool on its own side. The
18
+ * call never reaches this process.
19
+ * - `"hosted-mcp"` — the tool is a hosted MCP server's, and the write happens
20
+ * server-side, past the boundary an adapter can bind at.
21
+ *
22
+ * The first one that matches is the category reported; a tool with no `execute` that
23
+ * is *also* provider-executed reads as `"no-execute"`, because that is the fact a
24
+ * host can check without knowing anything about the provider.
25
+ *
26
+ * ## Why a declaration, and why it does not make the tool safe
27
+ *
28
+ * A host that knows it cannot cover a tool may declare it. The declaration does not
29
+ * grant the tool anything: it converts a **wire-up refusal** into a **Docket record**
30
+ * — every proposal from that tool is filed `pending` with `blocked: { code:
31
+ * "coverage-refused", category, toolName }`, which AZ-4 says can never be decided and
32
+ * never executes. So the choice a host makes is not "refuse or allow"; it is "refuse
33
+ * at start-up, or refuse per proposal with the proposal on the record". The second is
34
+ * the more useful of the two when the host wants a person to see what an uncovered
35
+ * tool tried to do.
36
+ *
37
+ * What no declaration can do is cover a tool that opens its own connection and writes
38
+ * inside its body. GT-6 states that boundary as an honest limit rather than a rule an
39
+ * implementation can enforce.
40
+ *
41
+ * @packageDocumentation
42
+ */
43
+ import type { TurnContext } from "../context.js";
44
+ import type { BlockedMarker } from "../docket/entry.js";
45
+ import type { FieldSchema, Operation } from "../ports.js";
46
+ /**
47
+ * A tool as the host declares it, in the shape the gate needs to decide two things:
48
+ * whether it can be intercepted, and how its arguments become a proposal.
49
+ *
50
+ * The type parameters default to `never` and `unknown`, which makes the bare
51
+ * `ToolDefinition` a supertype of every concrete one — so
52
+ * {@link assessCoverage} and {@link declareUncovered} take any tool without a cast.
53
+ *
54
+ * `operation` is what a **write-capable** tool must supply: the function that turns a
55
+ * call's arguments into the {@link Operation} the Affidavit is sworn over. It is the
56
+ * host's declaration of what the tool is about to write, and it is required at
57
+ * wire-up rather than inferred, because nothing else in this package can know that
58
+ * `{ id, status }` is an update of a `Ticket` and not a search over one.
59
+ *
60
+ * `execute` takes the turn context as its second argument. A read tool is called
61
+ * with the same explicit context the gate was given (GT-2); nothing is ambient, at
62
+ * any depth of the call path. A write tool's `execute` is **never called by the
63
+ * gate** (GT-6) — see `wrap.ts`.
64
+ */
65
+ export interface ToolDefinition<TArgs = never, TResult = unknown> {
66
+ /** The tool's name, as the model sees it and as a Docket row records it. */
67
+ readonly name: string;
68
+ /** What the tool does, in one line. */
69
+ readonly description: string;
70
+ /** The fields a proposal from this tool can carry, for the inference step. */
71
+ readonly inputSchema: FieldSchema;
72
+ /** The host's implementation. Called for a read tool; never for a write tool (GT-6). */
73
+ readonly execute?: (args: TArgs, ctx: TurnContext) => Promise<TResult> | TResult;
74
+ /** Whether a call to this tool would write. */
75
+ readonly writeCapable: boolean;
76
+ /** Who runs it. `"provider"` means the call never reaches this process. */
77
+ readonly executedBy?: "host" | "provider";
78
+ /** Whether the tool is a hosted MCP server's, writing server-side. */
79
+ readonly hostedMcp?: boolean;
80
+ /** How a call's arguments declare the write being proposed. Required for a write tool. */
81
+ readonly operation?: (args: TArgs) => Operation;
82
+ /** The host's own verb for the operation, e.g. `"WriteUpdate"`, carried onto the card. */
83
+ readonly operationLabel?: string;
84
+ }
85
+ /** Why a tool cannot be intercepted (CV-4). */
86
+ export type UncoveredCategory = "no-execute" | "provider-executed" | "hosted-mcp";
87
+ /** Every {@link UncoveredCategory}, in the order {@link assessCoverage} checks them. */
88
+ export declare const UNCOVERED_CATEGORIES: readonly ["no-execute", "provider-executed", "hosted-mcp"];
89
+ /** Whether `value` is one of the categories in {@link UNCOVERED_CATEGORIES}. */
90
+ export declare function isUncoveredCategory(value: unknown): value is UncoveredCategory;
91
+ /** What {@link assessCoverage} found. */
92
+ export type CoverageAssessment = {
93
+ readonly covered: true;
94
+ } | {
95
+ readonly covered: false;
96
+ readonly category: UncoveredCategory;
97
+ };
98
+ /**
99
+ * Whether the gate can intercept `tool`, and if not, which category it falls in.
100
+ *
101
+ * This asks only about **interception**, not about whether the tool matters: a read
102
+ * tool with no `execute` is reported uncovered too, because it is. What turns an
103
+ * uncovered assessment into a refusal is CV-4's other half —
104
+ * {@link ToolDefinition.writeCapable} — and that check lives in `wrap.ts`, where the
105
+ * refusal is raised.
106
+ */
107
+ export declare function assessCoverage(tool: ToolDefinition): CoverageAssessment;
108
+ /** One tool a host has declared it cannot cover. */
109
+ export interface UncoveredDeclaration {
110
+ /** The tool's name — the key a later proposal is matched by. */
111
+ readonly toolName: string;
112
+ /** Why it cannot be covered. */
113
+ readonly category: UncoveredCategory;
114
+ }
115
+ /**
116
+ * The set of uncovered declarations a gate holds.
117
+ *
118
+ * One registry per gate, created by `createGate` and closed over by the pipeline —
119
+ * never a module-level map. Two gates in one process (two tenants' wirings, a test
120
+ * and the thing it tests) share nothing, which is the same reason GT-2 gives for the
121
+ * turn context: state that is reachable without being passed is state two callers
122
+ * can collide in.
123
+ */
124
+ export interface CoverageRegistry {
125
+ /**
126
+ * Record that `toolName` cannot be covered.
127
+ *
128
+ * @throws RangeError if the tool was already declared under a different category —
129
+ * a host contradicting itself about what a tool is, which is a programming
130
+ * error rather than a refusal.
131
+ */
132
+ declare(toolName: string, category: UncoveredCategory): void;
133
+ /** The category `toolName` was declared under, or `null` if it was not declared. */
134
+ lookup(toolName: string): UncoveredCategory | null;
135
+ /** Every declaration, in the order they were made. */
136
+ declarations(): readonly UncoveredDeclaration[];
137
+ }
138
+ /** A fresh, empty {@link CoverageRegistry}. */
139
+ export declare function createCoverageRegistry(): CoverageRegistry;
140
+ /**
141
+ * Declare `tool` uncovered in `registry`, so that a later proposal from it is filed
142
+ * `blocked` rather than refused at wire-up (CV-4).
143
+ *
144
+ * The first parameter is the registry rather than the gate: `gate.ts` builds the
145
+ * registry and hands it to both `wrap` and the pipeline, and a function that took the
146
+ * gate would make this module import the module that imports it. `Gate.declareUncovered`
147
+ * is the surface a host calls; this is what it calls.
148
+ */
149
+ export declare function declareUncovered(registry: CoverageRegistry, tool: Pick<ToolDefinition, "name">, category: UncoveredCategory): void;
150
+ /** The AZ-4 marker a proposal from a declared-uncovered tool is filed with (CV-4). */
151
+ export declare function coverageRefusedMarker(toolName: string, category: UncoveredCategory): BlockedMarker;
152
+ //# sourceMappingURL=coverage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/gate/coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAM1D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,cAAc,CAAC,KAAK,GAAG,KAAK,EAAE,OAAO,GAAG,OAAO;IAC9D,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uCAAuC;IACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,wFAAwF;IACxF,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACjF,+CAA+C;IAC/C,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;IAC1C,sEAAsE;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,0FAA0F;IAC1F,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,SAAS,CAAC;IAChD,0FAA0F;IAC1F,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAMD,+CAA+C;AAC/C,MAAM,MAAM,iBAAiB,GAAG,YAAY,GAAG,mBAAmB,GAAG,YAAY,CAAC;AAElF,wFAAwF;AACxF,eAAO,MAAM,oBAAoB,4DAIgB,CAAC;AAElD,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAE9E;AAED,yCAAyC;AACzC,MAAM,MAAM,kBAAkB,GAC5B;IAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAA;CAAE,CAAC;AAEjG;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,cAAc,GAAG,kBAAkB,CAKvE;AAMD,oDAAoD;AACpD,MAAM,WAAW,oBAAoB;IACnC,gEAAgE;IAChE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,gCAAgC;IAChC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;CACtC;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC7D,oFAAoF;IACpF,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAAC;IACnD,sDAAsD;IACtD,YAAY,IAAI,SAAS,oBAAoB,EAAE,CAAC;CACjD;AAED,+CAA+C;AAC/C,wBAAgB,sBAAsB,IAAI,gBAAgB,CA6BzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,MAAM,CAAC,EAClC,QAAQ,EAAE,iBAAiB,GAC1B,IAAI,CAEN;AAED,sFAAsF;AACtF,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,iBAAiB,GAC1B,aAAa,CAEf"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Coverage: which tools the gate can actually intercept, and what happens to the
3
+ * ones it cannot.
4
+ *
5
+ * **Rules served: CV-4** (a write-capable tool in an uncovered category is refused at
6
+ * wire-up, or — where wire-up cannot see it — marked `blocked` with code
7
+ * `coverage-refused` on the Docket; it is never silently allowed to write),
8
+ * **CV-1** (the refusal is at wire-up and there is no option that turns the gate off
9
+ * for a tool it covers), **AZ-4** (the blocked marker and its codes).
10
+ *
11
+ * ## The three categories
12
+ *
13
+ * A tool is *uncovered* when there is nothing for the gate to replace:
14
+ *
15
+ * - `"no-execute"` — the tool declares no `execute`. There is no function to stand in
16
+ * front of; whatever writes, writes somewhere this package cannot see.
17
+ * - `"provider-executed"` — the model provider runs the tool on its own side. The
18
+ * call never reaches this process.
19
+ * - `"hosted-mcp"` — the tool is a hosted MCP server's, and the write happens
20
+ * server-side, past the boundary an adapter can bind at.
21
+ *
22
+ * The first one that matches is the category reported; a tool with no `execute` that
23
+ * is *also* provider-executed reads as `"no-execute"`, because that is the fact a
24
+ * host can check without knowing anything about the provider.
25
+ *
26
+ * ## Why a declaration, and why it does not make the tool safe
27
+ *
28
+ * A host that knows it cannot cover a tool may declare it. The declaration does not
29
+ * grant the tool anything: it converts a **wire-up refusal** into a **Docket record**
30
+ * — every proposal from that tool is filed `pending` with `blocked: { code:
31
+ * "coverage-refused", category, toolName }`, which AZ-4 says can never be decided and
32
+ * never executes. So the choice a host makes is not "refuse or allow"; it is "refuse
33
+ * at start-up, or refuse per proposal with the proposal on the record". The second is
34
+ * the more useful of the two when the host wants a person to see what an uncovered
35
+ * tool tried to do.
36
+ *
37
+ * What no declaration can do is cover a tool that opens its own connection and writes
38
+ * inside its body. GT-6 states that boundary as an honest limit rather than a rule an
39
+ * implementation can enforce.
40
+ *
41
+ * @packageDocumentation
42
+ */
43
+ /** Every {@link UncoveredCategory}, in the order {@link assessCoverage} checks them. */
44
+ export const UNCOVERED_CATEGORIES = [
45
+ "no-execute",
46
+ "provider-executed",
47
+ "hosted-mcp",
48
+ ];
49
+ /** Whether `value` is one of the categories in {@link UNCOVERED_CATEGORIES}. */
50
+ export function isUncoveredCategory(value) {
51
+ return typeof value === "string" && UNCOVERED_CATEGORIES.includes(value);
52
+ }
53
+ /**
54
+ * Whether the gate can intercept `tool`, and if not, which category it falls in.
55
+ *
56
+ * This asks only about **interception**, not about whether the tool matters: a read
57
+ * tool with no `execute` is reported uncovered too, because it is. What turns an
58
+ * uncovered assessment into a refusal is CV-4's other half —
59
+ * {@link ToolDefinition.writeCapable} — and that check lives in `wrap.ts`, where the
60
+ * refusal is raised.
61
+ */
62
+ export function assessCoverage(tool) {
63
+ if (typeof tool.execute !== "function")
64
+ return { covered: false, category: "no-execute" };
65
+ if (tool.executedBy === "provider")
66
+ return { covered: false, category: "provider-executed" };
67
+ if (tool.hostedMcp === true)
68
+ return { covered: false, category: "hosted-mcp" };
69
+ return { covered: true };
70
+ }
71
+ /** A fresh, empty {@link CoverageRegistry}. */
72
+ export function createCoverageRegistry() {
73
+ const declared = new Map();
74
+ return {
75
+ declare(toolName, category) {
76
+ if (toolName.trim() === "") {
77
+ throw new RangeError("CV-4: an uncovered declaration names a tool; the name was blank");
78
+ }
79
+ if (!isUncoveredCategory(category)) {
80
+ throw new RangeError(`CV-4: ${JSON.stringify(category)} is not an uncovered category; the three are ` +
81
+ `${UNCOVERED_CATEGORIES.join(", ")}`);
82
+ }
83
+ const existing = declared.get(toolName);
84
+ if (existing !== undefined && existing !== category) {
85
+ throw new RangeError(`CV-4: tool ${JSON.stringify(toolName)} is already declared uncovered as ` +
86
+ `${JSON.stringify(existing)}; it cannot also be ${JSON.stringify(category)}`);
87
+ }
88
+ declared.set(toolName, category);
89
+ },
90
+ lookup(toolName) {
91
+ return declared.get(toolName) ?? null;
92
+ },
93
+ declarations() {
94
+ return [...declared].map(([toolName, category]) => ({ toolName, category }));
95
+ },
96
+ };
97
+ }
98
+ /**
99
+ * Declare `tool` uncovered in `registry`, so that a later proposal from it is filed
100
+ * `blocked` rather than refused at wire-up (CV-4).
101
+ *
102
+ * The first parameter is the registry rather than the gate: `gate.ts` builds the
103
+ * registry and hands it to both `wrap` and the pipeline, and a function that took the
104
+ * gate would make this module import the module that imports it. `Gate.declareUncovered`
105
+ * is the surface a host calls; this is what it calls.
106
+ */
107
+ export function declareUncovered(registry, tool, category) {
108
+ registry.declare(tool.name, category);
109
+ }
110
+ /** The AZ-4 marker a proposal from a declared-uncovered tool is filed with (CV-4). */
111
+ export function coverageRefusedMarker(toolName, category) {
112
+ return { code: "coverage-refused", category, toolName };
113
+ }
114
+ //# sourceMappingURL=coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/gate/coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAyDH,wFAAwF;AACxF,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,YAAY;IACZ,mBAAmB;IACnB,YAAY;CACmC,CAAC;AAElD,gFAAgF;AAChF,MAAM,UAAU,mBAAmB,CAAC,KAAc;IAChD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,oBAA0C,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAClG,CAAC;AAMD;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,IAAoB;IACjD,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,UAAU;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAC1F,IAAI,IAAI,CAAC,UAAU,KAAK,UAAU;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAC7F,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;IAC/E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC;AAsCD,+CAA+C;AAC/C,MAAM,UAAU,sBAAsB;IACpC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAC;IACtD,OAAO;QACL,OAAO,CAAC,QAAgB,EAAE,QAA2B;YACnD,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;gBAC3B,MAAM,IAAI,UAAU,CAAC,iEAAiE,CAAC,CAAC;YAC1F,CAAC;YACD,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACnC,MAAM,IAAI,UAAU,CAClB,SAAS,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,+CAA+C;oBAC9E,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACvC,CAAC;YACJ,CAAC;YACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxC,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACpD,MAAM,IAAI,UAAU,CAClB,cAAc,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,oCAAoC;oBACxE,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,uBAAuB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAC/E,CAAC;YACJ,CAAC;YACD,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACnC,CAAC;QACD,MAAM,CAAC,QAAgB;YACrB,OAAO,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC;QACxC,CAAC;QACD,YAAY;YACV,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC/E,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAA0B,EAC1B,IAAkC,EAClC,QAA2B;IAE3B,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,qBAAqB,CACnC,QAAgB,EAChB,QAA2B;IAE3B,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,207 @@
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 type { Principal, TurnContext } from "../context.js";
59
+ import type { Attestor, DocketEntry, ExecutionOutcome } from "../docket/entry.js";
60
+ import type { SessionStore } from "../docket/store.js";
61
+ import type { AmendmentMap } from "../model/amendments.js";
62
+ import type { AuthorizationPort } from "../ports.js";
63
+ import type { FiledEntry, PipelineDeps } from "./pipeline.js";
64
+ /**
65
+ * What a reviewer decided.
66
+ *
67
+ * Amending is not a third kind: it is an approval carrying an
68
+ * {@link AmendmentMap} (DK-2). Modelling it as a separate verb would let an
69
+ * implementation record an amendment that approved nothing, and a reviewer who
70
+ * corrects a field has, by correcting it, said what they are prepared to approve.
71
+ *
72
+ * A rejection requires a reason and an approval does not, for the asymmetric reason
73
+ * that a person who declines a machine's proposal is the only one who knows why,
74
+ * whereas an approval's reason is the Affidavit.
75
+ */
76
+ export type Decision = {
77
+ /** Approve the write, as proposed or as amended. */
78
+ readonly kind: "approve";
79
+ /** The reviewer's corrections. `null` under a key clears the field; an absent key leaves it untouched (DK-2). */
80
+ readonly amendments?: AmendmentMap;
81
+ /** Why, for the record. Optional: the Affidavit is the reason. */
82
+ readonly reason?: string;
83
+ } | {
84
+ /** Refuse the write. */
85
+ readonly kind: "reject";
86
+ /** Why. Required — a refusal nobody explained teaches the host nothing. */
87
+ readonly reason: string;
88
+ };
89
+ /**
90
+ * What a host's executor reports back: the write happened, or it did not.
91
+ *
92
+ * `"unexecuted"` is excluded because it is the state a row is *filed* in, never a
93
+ * report — an executor that has nothing to say says nothing.
94
+ */
95
+ export type ExecutionReport = Exclude<ExecutionOutcome, "unexecuted">;
96
+ /** Everything the decision path needs from the host, assembled once by `createGate`. */
97
+ export interface DecideDeps extends PipelineDeps {
98
+ /** Who may decide an entry (AZ-2). The gate has already refused the cases this port must not be asked about. */
99
+ readonly authorization: AuthorizationPort;
100
+ /** The rehydration surface (DK-5), or `null` when the host supplied none. */
101
+ readonly sessions: SessionStore | null;
102
+ }
103
+ /**
104
+ * Approve, amend or reject the entry `entryId` names, as `ctx.principal` (DK-1,
105
+ * AZ-1, AZ-2, AZ-3).
106
+ *
107
+ * @returns The row as it stands after the transition.
108
+ * @throws AffiantError `"decision-unauthorized"` when the context carries no
109
+ * resolved principal, when the host's authorization port says no, or when a
110
+ * machine caller with nothing to relay tries to attest (AZ-2, AZ-3);
111
+ * `"entry-not-found"` when no entry with that id is visible in the caller's
112
+ * tenant; `"decision-expired"` when the entry has passed its deadline — the
113
+ * decision's amendments are preserved on the row first (DK-1);
114
+ * `"decision-not-pending"` when it has already been decided or is blocked
115
+ * (AZ-4); `"decision-lost-race"` when a competing decision won the guarded
116
+ * compare-and-set.
117
+ * @throws RangeError when an amendment map holds `undefined` under a key, or names a
118
+ * field the Affidavit does not propose. Neither is a refusal the gate hands
119
+ * back to a caller: they are caller programming errors, and an `AffiantError`
120
+ * code would invite a host to catch and continue.
121
+ */
122
+ export declare function decide(entryId: string, decision: Decision, ctx: TurnContext, deps: DecideDeps): Promise<DocketEntry>;
123
+ /**
124
+ * Record what the host's executor did with an approved write (DK-1, AZ-5, AZ-7).
125
+ *
126
+ * `status` stays `approved` — the approval happened and is not undone by a failed
127
+ * write; only `execution` and `executionDetail` move. This is the **only** public
128
+ * path to `execution: "executed"`, and the gate never calls an executor to reach it:
129
+ * a host reads its approved-and-unexecuted rows (DK-5), does the write itself, and
130
+ * says what happened.
131
+ *
132
+ * A `service` principal is admitted here and refused as a decider (AZ-3). The
133
+ * asymmetry is the point: reporting an outcome is a statement of fact about work the
134
+ * host performed, which a machine is the right party to make, while a decision is an
135
+ * act of authority that a machine may never make in a person's name. The tenant check
136
+ * and the host's authorization port still apply, so "which service may report on this
137
+ * entry" is still the host's answer and not an open door.
138
+ *
139
+ * **Reported once.** The execution transition is a guarded compare-and-set out of
140
+ * `"unexecuted"`, like every other transition on a row (DK-1): a second report is
141
+ * refused and the first stands. Overwriting would let an approved-and-committed row
142
+ * later read `failed` — an edit in place of a recorded fact (DK-4), and the loss of
143
+ * exactly the distinction DK-1 requires the row to keep. So a host that retries a
144
+ * write reports **once**, when it knows the outcome; the retries are the host's
145
+ * business (AZ-5), the outcome is the Docket's.
146
+ *
147
+ * @throws AffiantError `"decision-unauthorized"`, `"entry-not-found"`,
148
+ * `"decision-not-pending"` when the row is not `approved`, or
149
+ * `"execution-already-recorded"` when it already carries an outcome.
150
+ */
151
+ export declare function markExecuted(entryId: string, outcome: ExecutionReport, detail: string | null, ctx: TurnContext, deps: DecideDeps): Promise<DocketEntry>;
152
+ /**
153
+ * File the expired entry `entryId` names again, as a **new** entry whose lineage
154
+ * points back at it (DK-1).
155
+ *
156
+ * A resubmission is never a reopening. The superseded entry keeps its terminal state
157
+ * and gains a successor link, so the history reads forward (DK-4) and nothing that
158
+ * was once decided is quietly edited. The new proposal carries the same operation and
159
+ * the same sworn fields, with the amendments the refused late decision left on the
160
+ * row prefilled as values — each prefilled field tagged `UserStated` with a
161
+ * `reviewer-act` binding naming the superseded entry (PV-2), so a reader of the new
162
+ * card can see which values came from a person's earlier correction rather than from
163
+ * the machine.
164
+ *
165
+ * The whole pipeline runs again: the policy chain gets another say, the deadline is
166
+ * stamped afresh from that verdict (GT-4), and the substance gate applies (GT-3). A
167
+ * resubmission is a new proposal, not a replay of an old approval.
168
+ *
169
+ * @throws AffiantError `"decision-unauthorized"`, `"entry-not-found"`, or
170
+ * `"decision-not-pending"` when the entry does not read `expired`.
171
+ * @throws RangeError when the preserved amendment map names a field the Affidavit
172
+ * does not propose.
173
+ */
174
+ export declare function resubmit(entryId: string, ctx: TurnContext, deps: DecideDeps): Promise<FiledEntry>;
175
+ /** A human-verified session's attestation. The only kind a `member` principal makes. */
176
+ export type MemberAttestation = Extract<Attestor, {
177
+ kind: "member";
178
+ }>;
179
+ /** A person's decision carried by a relay. The strongest kind a `service` principal can make. */
180
+ export type RelayAttestation = Extract<Attestor, {
181
+ kind: "member-via-relay";
182
+ }>;
183
+ /**
184
+ * The strongest attestation `principal` can honestly make, or `null` when it can
185
+ * make none (AZ-1, AZ-3).
186
+ *
187
+ * A `member` principal attests `member`. A `service` principal carrying both a relay
188
+ * assertion and the person it speaks for attests `member-via-relay`, naming both — and
189
+ * that is the *only* thing it can attest. A `service` principal with nothing to relay
190
+ * attests nothing: it is a machine acting on its own behalf, and a machine cannot
191
+ * agree to a write in a person's name.
192
+ *
193
+ * **AZ-3 is in the overloads, not only in the body.** The signature for a `service`
194
+ * principal cannot return a `member` attestation — a compiler rejects the shortcut
195
+ * before a reviewer has to notice it — and this is the only function in the package
196
+ * that builds an attestation for a decision, so there is no second path to check.
197
+ * `standing-order` is not reachable from here at all: a policy verdict writes that
198
+ * one, in the same operation as the filing (AZ-1, GT-1 step 9).
199
+ */
200
+ export declare function attestorOf(principal: Extract<Principal, {
201
+ kind: "member";
202
+ }>): MemberAttestation;
203
+ export declare function attestorOf(principal: Extract<Principal, {
204
+ kind: "service";
205
+ }>): RelayAttestation | null;
206
+ export declare function attestorOf(principal: Principal): Attestor | null;
207
+ //# sourceMappingURL=decide.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decide.d.ts","sourceRoot":"","sources":["../../src/gate/decide.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,KAAK,EAAe,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE/F,OAAO,KAAK,EAAS,YAAY,EAAmB,MAAM,oBAAoB,CAAC;AAG/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAI3D,OAAO,KAAK,EAAE,iBAAiB,EAAa,MAAM,aAAa,CAAC;AAEhE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAmC,MAAM,eAAe,CAAC;AAO/F;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,QAAQ,GAChB;IACE,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,iHAAiH;IACjH,QAAQ,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC;IACnC,kEAAkE;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,GACD;IACE,wBAAwB;IACxB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEN;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,gBAAgB,EAAE,YAAY,CAAC,CAAC;AAEtE,wFAAwF;AACxF,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,gHAAgH;IAChH,QAAQ,CAAC,aAAa,EAAE,iBAAiB,CAAC;IAC1C,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;CACxC;AASD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,MAAM,CAC1B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,WAAW,CAAC,CAuItB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAsB,YAAY,CAChC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,eAAe,EACxB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,WAAW,CAAC,CAgDtB;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,UAAU,CAAC,CA0BrB;AA6MD,wFAAwF;AACxF,MAAM,MAAM,iBAAiB,GAAG,OAAO,CAAC,QAAQ,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,CAAC;AAEtE,iGAAiG;AACjG,MAAM,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,EAAE;IAAE,IAAI,EAAE,kBAAkB,CAAA;CAAE,CAAC,CAAC;AAE/E;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,GAAG,iBAAiB,CAAC;AACjG,wBAAgB,UAAU,CACxB,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC,GACjD,gBAAgB,GAAG,IAAI,CAAC;AAC3B,wBAAgB,UAAU,CAAC,SAAS,EAAE,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAC"}