@cotal-ai/core 0.18.0 → 0.19.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/dist/acls.d.ts +0 -7
- package/dist/acls.d.ts.map +1 -1
- package/dist/acls.js +10 -7
- package/dist/acls.js.map +1 -1
- package/dist/agui-kind.d.ts +71 -0
- package/dist/agui-kind.d.ts.map +1 -0
- package/dist/agui-kind.js +95 -0
- package/dist/agui-kind.js.map +1 -0
- package/dist/endpoint-action.d.ts +3 -3
- package/dist/endpoint-action.js +4 -4
- package/dist/endpoint-action.js.map +1 -1
- package/dist/endpoint-binding.d.ts +48 -5
- package/dist/endpoint-binding.d.ts.map +1 -1
- package/dist/endpoint-binding.js +82 -6
- package/dist/endpoint-binding.js.map +1 -1
- package/dist/endpoint-cluster.d.ts +20 -0
- package/dist/endpoint-cluster.d.ts.map +1 -1
- package/dist/endpoint-cluster.js +47 -0
- package/dist/endpoint-cluster.js.map +1 -1
- package/dist/endpoint-effects.d.ts +73 -0
- package/dist/endpoint-effects.d.ts.map +1 -0
- package/dist/endpoint-effects.js +46 -0
- package/dist/endpoint-effects.js.map +1 -0
- package/dist/endpoint-envelope.d.ts +32 -1
- package/dist/endpoint-envelope.d.ts.map +1 -1
- package/dist/endpoint-envelope.js +56 -2
- package/dist/endpoint-envelope.js.map +1 -1
- package/dist/endpoint-epname.d.ts +62 -0
- package/dist/endpoint-epname.d.ts.map +1 -0
- package/dist/endpoint-epname.js +273 -0
- package/dist/endpoint-epname.js.map +1 -0
- package/dist/endpoint-error.d.ts +155 -1
- package/dist/endpoint-error.d.ts.map +1 -1
- package/dist/endpoint-error.js +114 -2
- package/dist/endpoint-error.js.map +1 -1
- package/dist/endpoint-goaleff.d.ts +56 -0
- package/dist/endpoint-goaleff.d.ts.map +1 -0
- package/dist/endpoint-goaleff.js +212 -0
- package/dist/endpoint-goaleff.js.map +1 -0
- package/dist/endpoint-grants.d.ts +31 -0
- package/dist/endpoint-grants.d.ts.map +1 -1
- package/dist/endpoint-grants.js +47 -0
- package/dist/endpoint-grants.js.map +1 -1
- package/dist/endpoint-invoke.d.ts +1 -1
- package/dist/endpoint-invoke.d.ts.map +1 -1
- package/dist/endpoint-invoke.js +89 -7
- package/dist/endpoint-invoke.js.map +1 -1
- package/dist/endpoint-journal.d.ts +103 -0
- package/dist/endpoint-journal.d.ts.map +1 -1
- package/dist/endpoint-journal.js +290 -0
- package/dist/endpoint-journal.js.map +1 -1
- package/dist/endpoint-records.d.ts.map +1 -1
- package/dist/endpoint-records.js +37 -0
- package/dist/endpoint-records.js.map +1 -1
- package/dist/endpoint-serve.d.ts.map +1 -1
- package/dist/endpoint-serve.js +45 -1
- package/dist/endpoint-serve.js.map +1 -1
- package/dist/endpoint-verbs.d.ts +12 -3
- package/dist/endpoint-verbs.d.ts.map +1 -1
- package/dist/endpoint-verbs.js +113 -19
- package/dist/endpoint-verbs.js.map +1 -1
- package/dist/endpoint.d.ts +149 -6
- package/dist/endpoint.d.ts.map +1 -1
- package/dist/endpoint.js +330 -14
- package/dist/endpoint.js.map +1 -1
- package/dist/event-channel.d.ts +107 -0
- package/dist/event-channel.d.ts.map +1 -0
- package/dist/event-channel.js +139 -0
- package/dist/event-channel.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/membership-feed.d.ts.map +1 -1
- package/dist/membership-feed.js +35 -12
- package/dist/membership-feed.js.map +1 -1
- package/dist/parts.d.ts +29 -5
- package/dist/parts.d.ts.map +1 -1
- package/dist/parts.js +46 -3
- package/dist/parts.js.map +1 -1
- package/dist/provision.d.ts +1 -1
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +38 -0
- package/dist/resolve.js.map +1 -1
- package/dist/streams.d.ts +27 -3
- package/dist/streams.d.ts.map +1 -1
- package/dist/streams.js +28 -4
- package/dist/streams.js.map +1 -1
- package/dist/subjects.d.ts +42 -0
- package/dist/subjects.d.ts.map +1 -1
- package/dist/subjects.js +117 -0
- package/dist/subjects.js.map +1 -1
- package/package.json +5 -2
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `epname` — the durable name claim (SPEC §13.4; the closed machine).
|
|
3
|
+
*
|
|
4
|
+
* A name is an identity that outlives the process holding it. The row answers three questions that
|
|
5
|
+
* a live process cannot answer about itself: who holds this name, which lifecycle it names, and
|
|
6
|
+
* WHICH INCARNATION owns the handle table for it. The third is the one that keeps being got wrong,
|
|
7
|
+
* because it is the only one whose answer is invisible from the row's own subject.
|
|
8
|
+
*
|
|
9
|
+
* TWO RULES THAT COST MORE THAN THEY LOOK.
|
|
10
|
+
*
|
|
11
|
+
* `runtimeOwner` IS MOVED, NOT DERIVED. It is written at `launching → live` from the executor that
|
|
12
|
+
* made the spawn call — recorded at the moment it becomes true rather than reconstructed later —
|
|
13
|
+
* and every subsequent edge CARRIES it. It is deliberately never re-derived from a slot row,
|
|
14
|
+
* because user mode has no slot row at all, so a derivation is unevaluable on a supported path,
|
|
15
|
+
* and an unevaluable predicate is one that either refuses forever or falls back to absence.
|
|
16
|
+
* `instanceId` alone will not do: an identity is not an incarnation, and a restarted process with
|
|
17
|
+
* the same id has an empty handle table, which is the absence of knowledge rather than knowledge
|
|
18
|
+
* of absence.
|
|
19
|
+
*
|
|
20
|
+
* `draining` HAS EXACTLY ONE EXIT, AND IT IS THE OPERATOR. The ordinary edge required its actor to
|
|
21
|
+
* be the row's `runtimeOwner` attesting that the runtime is gone. That actor cannot exist: an owner
|
|
22
|
+
* still alive has no queryable per-attempt handle to attest about, and a restarted one is a
|
|
23
|
+
* different incarnation. The edge was satisfiable only by the party least entitled to satisfy it,
|
|
24
|
+
* so it is removed rather than weakened — and `draining` is a state an operator clears by hand
|
|
25
|
+
* until a durable runtime-attempt token exists. That cost is real and is recorded rather than
|
|
26
|
+
* hidden inside a predicate that reads as satisfiable.
|
|
27
|
+
*/
|
|
28
|
+
import { EpEnvelopeError } from "./endpoint-error.js";
|
|
29
|
+
function fail(message) {
|
|
30
|
+
throw new EpEnvelopeError("bad-request", `epname: ${message}`);
|
|
31
|
+
}
|
|
32
|
+
const BASE = ["v", "ts", "state", "claimant"];
|
|
33
|
+
/** The COMPLETE legal field set per state. § S2's variants are per-state for the reason § S1's are:
|
|
34
|
+
* a single broad object with everything optional cannot say that `executor` is present IFF a launch
|
|
35
|
+
* is in flight, and "present iff" is the only form in which that field is useful. */
|
|
36
|
+
const STATE_FIELDS = {
|
|
37
|
+
claimed: BASE,
|
|
38
|
+
launching: [...BASE, "lifecycleUid", "launchAttemptId", "executor"],
|
|
39
|
+
live: [...BASE, "lifecycleUid", "runtimeOwner"],
|
|
40
|
+
preserved: [...BASE, "lifecycleUid", "runtimeOwner"],
|
|
41
|
+
relaunching: [...BASE, "lifecycleUid", "launchAttemptId", "executor"],
|
|
42
|
+
draining: [...BASE, "lifecycleUid", "runtimeOwner", "enteredAt"],
|
|
43
|
+
released: BASE,
|
|
44
|
+
};
|
|
45
|
+
function parseIncarnation(v, what) {
|
|
46
|
+
if (typeof v !== "object" || v === null || Array.isArray(v))
|
|
47
|
+
fail(`\`${what}\` must be an object`);
|
|
48
|
+
const o = v;
|
|
49
|
+
const extra = Object.keys(o).filter((k) => k !== "instanceId" && k !== "processEpoch");
|
|
50
|
+
if (extra.length > 0)
|
|
51
|
+
fail(`unknown field(s) on \`${what}\`: ${extra.join(", ")}`);
|
|
52
|
+
if (typeof o.instanceId !== "string" || o.instanceId.length === 0)
|
|
53
|
+
fail(`\`${what}.instanceId\` must be a non-empty string`);
|
|
54
|
+
if (typeof o.processEpoch !== "number" || !Number.isSafeInteger(o.processEpoch) || o.processEpoch < 0)
|
|
55
|
+
fail(`\`${what}.processEpoch\` must be a non-negative safe integer — an incarnation, not an identity`);
|
|
56
|
+
return { instanceId: o.instanceId, processEpoch: o.processEpoch };
|
|
57
|
+
}
|
|
58
|
+
function parseClaimant(v) {
|
|
59
|
+
if (typeof v !== "object" || v === null || Array.isArray(v))
|
|
60
|
+
fail("`claimant` must be an object");
|
|
61
|
+
const o = v;
|
|
62
|
+
const legal = {
|
|
63
|
+
action: ["kind", "goalId", "gen"],
|
|
64
|
+
direct: ["kind", "instanceId", "processEpoch", "opId"],
|
|
65
|
+
incumbent: ["kind", "backfillId"],
|
|
66
|
+
};
|
|
67
|
+
const kind = o.kind;
|
|
68
|
+
// `Object.hasOwn`, not `in` — see the state check below.
|
|
69
|
+
if (typeof kind !== "string" || !Object.hasOwn(legal, kind))
|
|
70
|
+
fail(`unknown claimant kind ${JSON.stringify(kind)} — the legal set is action|direct|incumbent`);
|
|
71
|
+
const extra = Object.keys(o).filter((k) => !legal[kind].includes(k));
|
|
72
|
+
if (extra.length > 0)
|
|
73
|
+
fail(`unknown field(s) on a ${kind} claimant: ${extra.join(", ")}`);
|
|
74
|
+
const missing = legal[kind].filter((k) => !(k in o));
|
|
75
|
+
if (missing.length > 0)
|
|
76
|
+
fail(`a ${kind} claimant is missing: ${missing.join(", ")}`);
|
|
77
|
+
if (kind === "action") {
|
|
78
|
+
if (typeof o.goalId !== "string" || o.goalId.length === 0)
|
|
79
|
+
fail("`claimant.goalId` must be a non-empty string");
|
|
80
|
+
if (typeof o.gen !== "number" || !Number.isSafeInteger(o.gen))
|
|
81
|
+
fail("`claimant.gen` must be a safe integer");
|
|
82
|
+
return { kind: "action", goalId: o.goalId, gen: o.gen };
|
|
83
|
+
}
|
|
84
|
+
if (kind === "direct") {
|
|
85
|
+
if (typeof o.opId !== "string" || o.opId.length === 0)
|
|
86
|
+
fail("`claimant.opId` must be a non-empty string");
|
|
87
|
+
const inc = parseIncarnation({ instanceId: o.instanceId, processEpoch: o.processEpoch }, "claimant");
|
|
88
|
+
return { kind: "direct", instanceId: inc.instanceId, processEpoch: inc.processEpoch, opId: o.opId };
|
|
89
|
+
}
|
|
90
|
+
if (typeof o.backfillId !== "string" || o.backfillId.length === 0)
|
|
91
|
+
fail("`claimant.backfillId` must be a non-empty string");
|
|
92
|
+
return { kind: "incumbent", backfillId: o.backfillId };
|
|
93
|
+
}
|
|
94
|
+
/** Parse a row from CURRENT BYTES with no knowledge of history — which is the property that makes a
|
|
95
|
+
* sweeper able to act on a row it did not write. */
|
|
96
|
+
export function parseEpName(value) {
|
|
97
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
98
|
+
fail("row must be a JSON object");
|
|
99
|
+
const o = value;
|
|
100
|
+
const state = o.state;
|
|
101
|
+
// `Object.hasOwn`, NOT `in`: the `in` operator walks the PROTOTYPE CHAIN, so a row whose
|
|
102
|
+
// discriminant is `toString`, `constructor` or `hasOwnProperty` passed this test and then
|
|
103
|
+
// crashed with an uncontrolled TypeError instead of the declared bad-request refusal. An
|
|
104
|
+
// attacker-supplied string reaching a plain-object lookup is exactly where that matters.
|
|
105
|
+
if (typeof state !== "string" || !Object.hasOwn(STATE_FIELDS, state))
|
|
106
|
+
fail(`unknown state ${JSON.stringify(state)} — the legal set is ${Object.keys(STATE_FIELDS).join("|")}`);
|
|
107
|
+
const s = state;
|
|
108
|
+
const legal = STATE_FIELDS[s];
|
|
109
|
+
const unknown = Object.keys(o).filter((k) => !legal.includes(k));
|
|
110
|
+
if (unknown.length > 0)
|
|
111
|
+
fail(`unknown field(s) for state ${s}: ${unknown.join(", ")} — each state names the COMPLETE legal set`);
|
|
112
|
+
const missing = legal.filter((k) => !(k in o));
|
|
113
|
+
if (missing.length > 0)
|
|
114
|
+
fail(`state ${s} is missing required field(s): ${missing.join(", ")}`);
|
|
115
|
+
if (o.v !== 1)
|
|
116
|
+
fail("`v` must be exactly 1");
|
|
117
|
+
if (typeof o.ts !== "number" || !Number.isSafeInteger(o.ts))
|
|
118
|
+
fail("`ts` must be a safe integer");
|
|
119
|
+
// `claimant` is NON-NULL in every state but `released`. A `live` row with a null claimant cannot
|
|
120
|
+
// support the identity checks every release depends on, so admitting one moves the failure to
|
|
121
|
+
// whichever release reads it next — far from the write that caused it.
|
|
122
|
+
const row = { v: 1, ts: o.ts, state: s, claimant: null };
|
|
123
|
+
if (s === "released") {
|
|
124
|
+
if (o.claimant !== null)
|
|
125
|
+
fail("`released` REQUIRES a null `claimant` — the name is unheld");
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
if (o.claimant === null)
|
|
129
|
+
fail(`state ${s} REQUIRES a non-null \`claimant\`: a held name with no holder cannot answer the identity check every release makes`);
|
|
130
|
+
row.claimant = parseClaimant(o.claimant);
|
|
131
|
+
}
|
|
132
|
+
if (legal.includes("lifecycleUid")) {
|
|
133
|
+
if (typeof o.lifecycleUid !== "string" || o.lifecycleUid.length === 0)
|
|
134
|
+
fail("`lifecycleUid` must be a non-empty string");
|
|
135
|
+
row.lifecycleUid = o.lifecycleUid;
|
|
136
|
+
}
|
|
137
|
+
if (legal.includes("launchAttemptId")) {
|
|
138
|
+
if (typeof o.launchAttemptId !== "string" || o.launchAttemptId.length === 0)
|
|
139
|
+
fail("`launchAttemptId` must be a non-empty string");
|
|
140
|
+
row.launchAttemptId = o.launchAttemptId;
|
|
141
|
+
}
|
|
142
|
+
if (legal.includes("executor"))
|
|
143
|
+
row.executor = parseIncarnation(o.executor, "executor");
|
|
144
|
+
if (legal.includes("runtimeOwner"))
|
|
145
|
+
row.runtimeOwner = parseIncarnation(o.runtimeOwner, "runtimeOwner");
|
|
146
|
+
if (legal.includes("enteredAt")) {
|
|
147
|
+
if (typeof o.enteredAt !== "number" || !Number.isSafeInteger(o.enteredAt))
|
|
148
|
+
fail("`enteredAt` must be a safe integer");
|
|
149
|
+
row.enteredAt = o.enteredAt;
|
|
150
|
+
}
|
|
151
|
+
return row;
|
|
152
|
+
}
|
|
153
|
+
/** The § S2 edge table. Every legal transition, and nothing else.
|
|
154
|
+
*
|
|
155
|
+
* `live → relaunching` IS ABSENT ON PURPOSE. Round 11 had it, and it reused ONE state for both a
|
|
156
|
+
* running agent and a stopped one: the holder could rotate the nonce and spawn a second process,
|
|
157
|
+
* and a crash after the spawn call was byte-identical to the state before it. Both are exactly
|
|
158
|
+
* what `launching` exists to prevent, reintroduced one level down. Ordinary `live` authorizes NO
|
|
159
|
+
* relaunch; only `preserved` does.
|
|
160
|
+
*
|
|
161
|
+
* `draining → released` carries EXACTLY ONE actor, the operator. See the module header. */
|
|
162
|
+
const EDGES = [
|
|
163
|
+
{ from: "—", to: "claimed", actors: ["allocator"] },
|
|
164
|
+
{ from: "released", to: "claimed", actors: ["allocator"] },
|
|
165
|
+
{ from: "claimed", to: "launching", actors: ["claimant"] },
|
|
166
|
+
{ from: "launching", to: "live", actors: ["claimant"] },
|
|
167
|
+
{ from: "live", to: "preserved", actors: ["holder"] },
|
|
168
|
+
{ from: "preserved", to: "relaunching", actors: ["holder"] },
|
|
169
|
+
{ from: "relaunching", to: "live", actors: ["holder"] },
|
|
170
|
+
{ from: "claimed", to: "released", actors: ["claimant", "sweeper"] },
|
|
171
|
+
{ from: "launching", to: "draining", actors: ["sweeper"] },
|
|
172
|
+
{ from: "live", to: "draining", actors: ["sweeper"] },
|
|
173
|
+
{ from: "preserved", to: "draining", actors: ["sweeper"] },
|
|
174
|
+
{ from: "relaunching", to: "draining", actors: ["sweeper"] },
|
|
175
|
+
{ from: "draining", to: "released", actors: ["operator"] },
|
|
176
|
+
{ from: "—", to: "live", actors: ["cutover"] },
|
|
177
|
+
];
|
|
178
|
+
function sameInc(a, b) {
|
|
179
|
+
if (a === undefined && b === undefined)
|
|
180
|
+
return true;
|
|
181
|
+
if (a === undefined || b === undefined)
|
|
182
|
+
return false;
|
|
183
|
+
return a.instanceId === b.instanceId && a.processEpoch === b.processEpoch;
|
|
184
|
+
}
|
|
185
|
+
function sameClaimant(a, b) {
|
|
186
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Validate a transition against § S2. `prev` is `null` for the two creation edges.
|
|
190
|
+
*
|
|
191
|
+
* `gateSatisfied` is the caller's attestation that the edge's external precondition holds — the
|
|
192
|
+
* `goaleff` election won, the process authoritatively quiesced, the executor dead by the gate
|
|
193
|
+
* predicate, the operator's host-level attestation. It is a REQUIRED argument for the same reason
|
|
194
|
+
* `terminalExists` is in § S1: a precondition the caller can satisfy by not mentioning it is not a
|
|
195
|
+
* precondition.
|
|
196
|
+
*/
|
|
197
|
+
export function assertEpNameEdge(prev, next, actor, opts) {
|
|
198
|
+
const from = prev === null ? "—" : prev.state;
|
|
199
|
+
const to = next.state;
|
|
200
|
+
const edge = EDGES.find((e) => e.from === from && e.to === to);
|
|
201
|
+
if (edge === undefined) {
|
|
202
|
+
const legal = EDGES.filter((e) => e.from === from).map((e) => e.to);
|
|
203
|
+
fail(legal.length === 0
|
|
204
|
+
? `\`${from}\` has no outgoing edge at all (attempted ${from} → ${to})`
|
|
205
|
+
: `${from} → ${to} is not a legal edge; from \`${from}\` the legal set is ${legal.join(", ")}`);
|
|
206
|
+
}
|
|
207
|
+
// CLOSED AT RUNTIME for the same reason as `goaleff`: an unknown role must be refused, not
|
|
208
|
+
// silently measured against a list it cannot be in. Here it happens to fail closed via
|
|
209
|
+
// `includes`, but relying on that is relying on an accident of the check's shape.
|
|
210
|
+
const ROLES = ["claimant", "holder", "sweeper", "operator", "allocator", "cutover"];
|
|
211
|
+
if (!ROLES.includes(actor.role))
|
|
212
|
+
fail(`unknown actor role ${JSON.stringify(actor.role)} — the legal set is ${ROLES.join("|")}`);
|
|
213
|
+
if (!edge.actors.includes(actor.role))
|
|
214
|
+
fail(`a ${actor.role} may not take ${from} → ${to}; that edge belongs to: ${edge.actors.join(", ")}`);
|
|
215
|
+
if (!opts.gateSatisfied)
|
|
216
|
+
fail(`${from} → ${to} requires its gate to hold FIRST, and the caller did not attest it`);
|
|
217
|
+
if (actor.role === "holder" && prev !== null && actor.lifecycleUid !== prev.lifecycleUid)
|
|
218
|
+
fail(`this edge is for the EXACT \`lifecycleUid\` holder only: row ${JSON.stringify(prev.lifecycleUid)}, `
|
|
219
|
+
+ `actor ${JSON.stringify(actor.lifecycleUid)}`);
|
|
220
|
+
// ---- creation edges ------------------------------------------------------------------------
|
|
221
|
+
if (prev === null) {
|
|
222
|
+
if (to === "live") {
|
|
223
|
+
// The cutover backfill. `runtimeOwner` comes from the incumbent's LIVE gate row, and if no
|
|
224
|
+
// such row names an incarnation the key is NOT backfilled — it is recorded as a casualty. A
|
|
225
|
+
// `live` row whose owner is unknown is the row § R15-A exists to forbid, and inventing one
|
|
226
|
+
// here puts the unevaluable value in the durable record where every later release reads it.
|
|
227
|
+
if (next.runtimeOwner === undefined)
|
|
228
|
+
fail("the cutover may not backfill a `live` row without a `runtimeOwner` read from the incumbent's "
|
|
229
|
+
+ "live gate row — record a cutover CASUALTY instead of inventing an owner");
|
|
230
|
+
if (next.claimant?.kind !== "incumbent")
|
|
231
|
+
fail("a cutover backfill claims as `incumbent`; any other claimant kind is a different edge");
|
|
232
|
+
}
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
// ---- claimant / lifecycle immutability -----------------------------------------------------
|
|
236
|
+
const reclaim = from === "released" && to === "claimed";
|
|
237
|
+
const releasing = to === "released";
|
|
238
|
+
if (!reclaim && !releasing && !sameClaimant(prev.claimant, next.claimant))
|
|
239
|
+
fail(`\`claimant\` is immutable while a claim is held: ${JSON.stringify(prev.claimant)} → ${JSON.stringify(next.claimant)}`);
|
|
240
|
+
if (releasing && next.claimant !== null)
|
|
241
|
+
fail("a release CLEARS `claimant`");
|
|
242
|
+
if (prev.lifecycleUid !== undefined && next.lifecycleUid !== undefined
|
|
243
|
+
&& prev.lifecycleUid !== next.lifecycleUid)
|
|
244
|
+
fail(`\`lifecycleUid\` is immutable while a claim is held: ${prev.lifecycleUid} → ${next.lifecycleUid}`);
|
|
245
|
+
// ---- runtimeOwner: MOVED on the launch-completing edges, CARRIED everywhere else ------------
|
|
246
|
+
const completesLaunch = (from === "launching" || from === "relaunching") && to === "live";
|
|
247
|
+
const drainsFromLaunch = (from === "launching" || from === "relaunching") && to === "draining";
|
|
248
|
+
if (completesLaunch || drainsFromLaunch) {
|
|
249
|
+
// The FULL incarnation moves, both fields. `instanceId` alone is an identity, and the row would
|
|
250
|
+
// then name a process rather than the run of it that holds the handle table.
|
|
251
|
+
if (!sameInc(next.runtimeOwner, prev.executor))
|
|
252
|
+
fail(`${from} → ${to} MOVES the full \`executor\` into \`runtimeOwner\`: expected `
|
|
253
|
+
+ `${JSON.stringify(prev.executor)}, got ${JSON.stringify(next.runtimeOwner)} — `
|
|
254
|
+
+ `an \`instanceId\` without its \`processEpoch\` is an identity, not the incarnation that holds the handle`);
|
|
255
|
+
if (next.launchAttemptId !== undefined)
|
|
256
|
+
fail(`${from} → ${to} CLEARS \`launchAttemptId\``);
|
|
257
|
+
}
|
|
258
|
+
else if (to === "draining" || to === "preserved" || to === "live") {
|
|
259
|
+
// CARRIED, never re-derived. The derivation a reader reaches for is the slot row's
|
|
260
|
+
// ownerInstanceId, and user mode has no slot row at all — so it is unevaluable on a supported
|
|
261
|
+
// path, which is the same failure as a predicate whose actor cannot exist.
|
|
262
|
+
if (!sameInc(prev.runtimeOwner, next.runtimeOwner))
|
|
263
|
+
fail(`${from} → ${to} CARRIES \`runtimeOwner\` unchanged (${JSON.stringify(prev.runtimeOwner)} → `
|
|
264
|
+
+ `${JSON.stringify(next.runtimeOwner)}) — it is installed once, when the spawn call returns, and never re-derived`);
|
|
265
|
+
}
|
|
266
|
+
if (to === "draining" && next.enteredAt === undefined)
|
|
267
|
+
fail("`draining` SETS `enteredAt`");
|
|
268
|
+
if (from === "draining" && to === "released") {
|
|
269
|
+
if (next.lifecycleUid !== undefined || next.runtimeOwner !== undefined || next.enteredAt !== undefined)
|
|
270
|
+
fail("the operator edge CLEARS `lifecycleUid`, `runtimeOwner` and `enteredAt`");
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=endpoint-epname.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint-epname.js","sourceRoot":"","sources":["../src/endpoint-epname.ts"],"names":[],"mappings":"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"}
|
package/dist/endpoint-error.d.ts
CHANGED
|
@@ -15,11 +15,164 @@ export interface EpErrorDetail {
|
|
|
15
15
|
kind: string;
|
|
16
16
|
[key: string]: unknown;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* `details[].kind` for a refusal raised because a responder ANSWERED but was not the incarnation
|
|
20
|
+
* this handle resolved against (§13.2): `failed-precondition` for a DIFFERENT instance, `expired`
|
|
21
|
+
* for the SAME instance at another EPOCH. It marks what the code alone cannot say — **the request
|
|
22
|
+
* drew an attributed reply from a live responder** — which rules out the reading "the incarnation
|
|
23
|
+
* is gone, resolve again". The reply may be a refusal or a result and the marker does not say
|
|
24
|
+
* which, so a retry here is a SECOND ATTEMPT that may duplicate an effect, never a repair.
|
|
25
|
+
*/
|
|
26
|
+
export declare const EP_UNBOUND_RESPONDER = "ai.cotal.ep.unbound-responder";
|
|
27
|
+
/** The {@link EP_UNBOUND_RESPONDER} payload. Two producers: the describe-bound currency check (a
|
|
28
|
+
* DIFFERENT instance) sets `answeredBy`/`boundTo`; the stale-epoch refusal (the SAME instance at
|
|
29
|
+
* another epoch) sets `answeredEpoch`/`heldEpoch` and says in `reference` which epoch `heldEpoch`
|
|
30
|
+
* is — `bind`, this caller's own resolve (so the handle is the stale side), or `registry`, the
|
|
31
|
+
* responder's current registered epoch (so a responder behind it is superseded and still
|
|
32
|
+
* answering). `boundTo` is set only where a bind exists. */
|
|
33
|
+
export interface EpUnboundResponderDetail extends EpErrorDetail {
|
|
34
|
+
kind: typeof EP_UNBOUND_RESPONDER;
|
|
35
|
+
endpoint: string;
|
|
36
|
+
command: string;
|
|
37
|
+
/** The instance whose attributed reply was refused. */
|
|
38
|
+
answeredBy: string;
|
|
39
|
+
/** The instance this handle resolved against; absent when the caller holds no bind. */
|
|
40
|
+
boundTo?: string;
|
|
41
|
+
answeredEpoch?: number;
|
|
42
|
+
heldEpoch?: number;
|
|
43
|
+
reference?: "bind" | "registry";
|
|
44
|
+
/** Whether the call addressed one instance (`inst` rail) rather than the class queue. */
|
|
45
|
+
pinned: boolean;
|
|
46
|
+
}
|
|
47
|
+
/** True iff `e` carries the {@link EP_UNBOUND_RESPONDER} marker: a responder ANSWERED the request
|
|
48
|
+
* (an attributed reply, which may be a refusal or a result), so retrying it is a second attempt
|
|
49
|
+
* that may duplicate an effect, not a repair. */
|
|
50
|
+
export declare function respondedButUnbound(e: unknown): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* `details[].kind` for a refusal raised because NO VALID REPLY REACHED THE CALLER: no responder on
|
|
53
|
+
* the subject, or the deadline elapsed with nothing attributed to the request's nonce. A frame that
|
|
54
|
+
* fails the request binding is dropped and is not an answer, so the marker means nothing
|
|
55
|
+
* ATTRIBUTABLE arrived, not that no bytes did. `unavailable`/`deadline-exceeded` alone is not
|
|
56
|
+
* evidence of silence — the same codes are raised where something did answer, or where a
|
|
57
|
+
* caller-side read failed after the describe — so a consumer stating a reachability verdict keys on
|
|
58
|
+
* this marker, never on the code.
|
|
59
|
+
*/
|
|
60
|
+
export declare const EP_UNANSWERED = "ai.cotal.ep.unanswered";
|
|
61
|
+
/** The {@link EP_UNANSWERED} payload: the call that drew no reply. */
|
|
62
|
+
export interface EpUnansweredDetail extends EpErrorDetail {
|
|
63
|
+
kind: typeof EP_UNANSWERED;
|
|
64
|
+
endpoint: string;
|
|
65
|
+
command: string;
|
|
66
|
+
}
|
|
67
|
+
/** True iff `e` carries the {@link EP_UNANSWERED} marker: no valid reply reached the caller (no
|
|
68
|
+
* responder, or the deadline elapsed with nothing attributed to the request). */
|
|
69
|
+
export declare function unansweredRequest(e: unknown): boolean;
|
|
70
|
+
/**
|
|
71
|
+
* `details[].kind` for a refusal raised because a caller-side read of the SERVICE REGISTRY failed
|
|
72
|
+
* or did not settle: the scatter's freeze (§13.5) or its mandatory reconcile. It marks the failure
|
|
73
|
+
* as the caller's own, establishing NOTHING about the responders — the freeze fails before any
|
|
74
|
+
* request goes out, and the reconcile fails after the gather, where members may all have answered
|
|
75
|
+
* and their replies simply could not be classified. A consumer must not read it as their silence.
|
|
76
|
+
*/
|
|
77
|
+
export declare const EP_REGISTRY_READ_FAILED = "ai.cotal.ep.registry-read-failed";
|
|
78
|
+
/** The {@link EP_REGISTRY_READ_FAILED} payload: the call whose registry read failed. */
|
|
79
|
+
export interface EpRegistryReadFailedDetail extends EpErrorDetail {
|
|
80
|
+
kind: typeof EP_REGISTRY_READ_FAILED;
|
|
81
|
+
endpoint: string;
|
|
82
|
+
command: string;
|
|
83
|
+
}
|
|
84
|
+
/** True iff `e` carries the {@link EP_REGISTRY_READ_FAILED} marker: a caller-side registry read
|
|
85
|
+
* failed; the responders were not the failure. */
|
|
86
|
+
export declare function registryReadFailed(e: unknown): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* `details[].kind` for a refusal raised by the RESPONDER because the request declared a bound
|
|
89
|
+
* incarnation (`bind`, §13.3) that is not this instance: `failed-precondition` for a different
|
|
90
|
+
* instance, `expired` for the same instance at another epoch. It marks what no caller-side check
|
|
91
|
+
* can establish: **the command did not run, and no effect of it exists.**
|
|
92
|
+
*
|
|
93
|
+
* Set before the handler, before args validation, and before any seam that can consume a one-use
|
|
94
|
+
* proof, by the only party that knows which incarnation it is. {@link EP_UNBOUND_RESPONDER} is
|
|
95
|
+
* raised by the CALLER on the reply, after the responder has already acted — a report, not a
|
|
96
|
+
* guard. So a caller holding THIS marker may re-resolve and re-issue without risking a duplicate,
|
|
97
|
+
* which is exactly what a caller holding that one must not do.
|
|
98
|
+
*/
|
|
99
|
+
export declare const EP_BIND_REFUSED = "ai.cotal.ep.bind-refused";
|
|
100
|
+
/** The {@link EP_BIND_REFUSED} payload: the incarnation the caller bound, and the one that
|
|
101
|
+
* refused. Both ids are stated because either field alone can be the mismatching one — a
|
|
102
|
+
* different instance, or the same instance at any other epoch — and the reader needs to see
|
|
103
|
+
* which. */
|
|
104
|
+
export interface EpBindRefusedDetail extends EpErrorDetail {
|
|
105
|
+
kind: typeof EP_BIND_REFUSED;
|
|
106
|
+
endpoint: string;
|
|
107
|
+
command: string;
|
|
108
|
+
/** What the request's `bind` block declared. */
|
|
109
|
+
boundTo: {
|
|
110
|
+
instanceId: string;
|
|
111
|
+
epoch: number;
|
|
112
|
+
};
|
|
113
|
+
/** The refusing instance's own identity. */
|
|
114
|
+
servedBy: {
|
|
115
|
+
instanceId: string;
|
|
116
|
+
epoch: number;
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/** True iff an `EpError` CARRIES the {@link EP_BIND_REFUSED} marker, saying nothing about whether
|
|
120
|
+
* the marker is believable. It is the claim's presence, not its acceptance.
|
|
121
|
+
*
|
|
122
|
+
* The two questions come apart, and conflating them is what this pair exists to prevent. Whether a
|
|
123
|
+
* caller may ACT on a bind refusal — re-issue a command it would otherwise never repeat — needs
|
|
124
|
+
* the marker AND an explicit `not-executed`, which is {@link replyRefusedBeforeEffect}. Whether a
|
|
125
|
+
* reply is CHECKED for self-consistency needs only the claim, because the contradiction being
|
|
126
|
+
* checked is between the reply's BODY and the subject the broker pinned, and that is a
|
|
127
|
+
* contradiction whatever the outcome field says — or does not say.
|
|
128
|
+
*
|
|
129
|
+
* Gating the checks on the stronger predicate meant a reply could skip them by OMITTING a field,
|
|
130
|
+
* so the least credible shape drew the least scrutiny. */
|
|
131
|
+
export declare function bindRefusalMarked(e: EpError | undefined): boolean;
|
|
132
|
+
/** True iff an `EpError` carries the {@link EP_BIND_REFUSED} marker: a responder refused BEFORE
|
|
133
|
+
* executing, because it is not the incarnation the caller bound — the command did not run.
|
|
134
|
+
*
|
|
135
|
+
* It takes an `EpError` and not a thrown value, unlike its sibling predicates, because this
|
|
136
|
+
* refusal never arrives as a throw: it is the responder's own application-level failure and
|
|
137
|
+
* those ride the reply (§13.5). A consumer reads it off `reply.error`.
|
|
138
|
+
*
|
|
139
|
+
* A REPLY THAT CONTRADICTS ITSELF IS NOT A REFUSAL. The marker IS the assertion that the command
|
|
140
|
+
* did not run, and {@link EpError.outcome} says a responder refusing before dispatch MUST carry
|
|
141
|
+
* `not-executed` — but {@link EpBindRefusedDetail} carries no outcome of its own, so nothing in the
|
|
142
|
+
* type stops a reply pairing the marker with `executed`. That combination is not merely odd: the
|
|
143
|
+
* only consumer of this predicate re-issues a command **without** the {@link isRepeatSafeCommand}
|
|
144
|
+
* gate, on the strength of the marker, so resolving the contradiction toward "refused" re-sends a
|
|
145
|
+
* command the reply just said had ALREADY RUN. A present outcome that disagrees therefore wins, and
|
|
146
|
+
* the reply is not read as a refusal.
|
|
147
|
+
*
|
|
148
|
+
* AN ABSENT OUTCOME IS NOT A REFUSAL EITHER, and it is the same answer as `unknown` because the
|
|
149
|
+
* spec says they are the same value: SPEC 1510, "an error reply that omits `outcome` MUST be read
|
|
150
|
+
* as `unknown`". An earlier revision accepted absence, on the argument that a responder too old to
|
|
151
|
+
* know the field emits exactly that and refusing it would stop core repairing splits for a third
|
|
152
|
+
* party that is otherwise behaving. That argument does not survive SPEC 2271: a client MUST NOT
|
|
153
|
+
* automatically re-issue a command declared `write` after any outcome that does not prove
|
|
154
|
+
* non-execution, whatever `id` the re-issue carries, and `unknown` proves nothing. Since this
|
|
155
|
+
* predicate is what licenses a re-issue that SKIPS {@link isRepeatSafeCommand}, accepting absence
|
|
156
|
+
* made core re-issue writes on an outcome the spec says is `unknown`.
|
|
157
|
+
*
|
|
158
|
+
* The cost is real and it is bounded: a responder that omits the field no longer has its splits
|
|
159
|
+
* repaired. That responder is already non-conforming, because §13.3 requires a refusal raised
|
|
160
|
+
* before dispatch to carry `not-executed`, so what it loses is a repair it was never owed. This
|
|
161
|
+
* endpoint's own responder sets the field, so conforming deployments are unaffected. */
|
|
162
|
+
export declare function replyRefusedBeforeEffect(e: EpError | undefined): boolean;
|
|
163
|
+
/** §13.3 **Effect outcome**: whether the command's effect occurred. Emitted by the RESPONDER,
|
|
164
|
+
* which is the only party that knows. An omitted `outcome` MUST be read as `unknown`, so absence
|
|
165
|
+
* is never evidence of non-execution. */
|
|
166
|
+
export type EpEffectOutcome = "executed" | "not-executed" | "unknown";
|
|
18
167
|
/** The `EndpointReply.error` shape. */
|
|
19
168
|
export interface EpError {
|
|
20
169
|
code: string;
|
|
21
170
|
message: string;
|
|
22
171
|
details?: EpErrorDetail[];
|
|
172
|
+
/** §13.3. A responder refusing BEFORE dispatching to the handler MUST carry `not-executed`;
|
|
173
|
+
* one refusing AFTER the handler ran MUST carry `executed`; one that cannot tell MUST carry
|
|
174
|
+
* `unknown` rather than guess. Absent on a caller-raised refusal, which is not a reply. */
|
|
175
|
+
outcome?: EpEffectOutcome;
|
|
23
176
|
}
|
|
24
177
|
/** A consuming-boundary rejection: the catalog code plus a human message. Boundaries convert it
|
|
25
178
|
* to an `EndpointReply` error via {@link EpEnvelopeError.toEpError} (or, on reply-less planes,
|
|
@@ -27,7 +180,8 @@ export interface EpError {
|
|
|
27
180
|
export declare class EpEnvelopeError extends Error {
|
|
28
181
|
readonly code: EpErrorCode;
|
|
29
182
|
readonly details?: EpErrorDetail[] | undefined;
|
|
30
|
-
|
|
183
|
+
readonly outcome?: EpEffectOutcome | undefined;
|
|
184
|
+
constructor(code: EpErrorCode, message: string, details?: EpErrorDetail[] | undefined, outcome?: EpEffectOutcome | undefined);
|
|
31
185
|
toEpError(): EpError;
|
|
32
186
|
}
|
|
33
187
|
//# sourceMappingURL=endpoint-error.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"endpoint-error.d.ts","sourceRoot":"","sources":["../src/endpoint-error.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;mDACmD;AACnD,eAAO,MAAM,cAAc,0XAMhB,CAAC;AACZ,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,yFAAyF;AACzF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,uCAAuC;AACvC,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED;;qEAEqE;AACrE,qBAAa,eAAgB,SAAQ,KAAK;IAC5B,QAAQ,CAAC,IAAI,EAAE,WAAW;IAAmB,QAAQ,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE;
|
|
1
|
+
{"version":3,"file":"endpoint-error.d.ts","sourceRoot":"","sources":["../src/endpoint-error.ts"],"names":[],"mappings":"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"}
|
package/dist/endpoint-error.js
CHANGED
|
@@ -15,20 +15,132 @@ export const EP_ERROR_CODES = Object.freeze([
|
|
|
15
15
|
"deadline-exceeded", "cancelled", "expired", "unavailable", "unimplemented",
|
|
16
16
|
"resource-exhausted", "internal",
|
|
17
17
|
]);
|
|
18
|
+
/**
|
|
19
|
+
* `details[].kind` for a refusal raised because a responder ANSWERED but was not the incarnation
|
|
20
|
+
* this handle resolved against (§13.2): `failed-precondition` for a DIFFERENT instance, `expired`
|
|
21
|
+
* for the SAME instance at another EPOCH. It marks what the code alone cannot say — **the request
|
|
22
|
+
* drew an attributed reply from a live responder** — which rules out the reading "the incarnation
|
|
23
|
+
* is gone, resolve again". The reply may be a refusal or a result and the marker does not say
|
|
24
|
+
* which, so a retry here is a SECOND ATTEMPT that may duplicate an effect, never a repair.
|
|
25
|
+
*/
|
|
26
|
+
export const EP_UNBOUND_RESPONDER = "ai.cotal.ep.unbound-responder";
|
|
27
|
+
/** True iff `e` carries the {@link EP_UNBOUND_RESPONDER} marker: a responder ANSWERED the request
|
|
28
|
+
* (an attributed reply, which may be a refusal or a result), so retrying it is a second attempt
|
|
29
|
+
* that may duplicate an effect, not a repair. */
|
|
30
|
+
export function respondedButUnbound(e) {
|
|
31
|
+
return e instanceof EpEnvelopeError && (e.details ?? []).some((d) => d.kind === EP_UNBOUND_RESPONDER);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* `details[].kind` for a refusal raised because NO VALID REPLY REACHED THE CALLER: no responder on
|
|
35
|
+
* the subject, or the deadline elapsed with nothing attributed to the request's nonce. A frame that
|
|
36
|
+
* fails the request binding is dropped and is not an answer, so the marker means nothing
|
|
37
|
+
* ATTRIBUTABLE arrived, not that no bytes did. `unavailable`/`deadline-exceeded` alone is not
|
|
38
|
+
* evidence of silence — the same codes are raised where something did answer, or where a
|
|
39
|
+
* caller-side read failed after the describe — so a consumer stating a reachability verdict keys on
|
|
40
|
+
* this marker, never on the code.
|
|
41
|
+
*/
|
|
42
|
+
export const EP_UNANSWERED = "ai.cotal.ep.unanswered";
|
|
43
|
+
/** True iff `e` carries the {@link EP_UNANSWERED} marker: no valid reply reached the caller (no
|
|
44
|
+
* responder, or the deadline elapsed with nothing attributed to the request). */
|
|
45
|
+
export function unansweredRequest(e) {
|
|
46
|
+
return e instanceof EpEnvelopeError && (e.details ?? []).some((d) => d.kind === EP_UNANSWERED);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* `details[].kind` for a refusal raised because a caller-side read of the SERVICE REGISTRY failed
|
|
50
|
+
* or did not settle: the scatter's freeze (§13.5) or its mandatory reconcile. It marks the failure
|
|
51
|
+
* as the caller's own, establishing NOTHING about the responders — the freeze fails before any
|
|
52
|
+
* request goes out, and the reconcile fails after the gather, where members may all have answered
|
|
53
|
+
* and their replies simply could not be classified. A consumer must not read it as their silence.
|
|
54
|
+
*/
|
|
55
|
+
export const EP_REGISTRY_READ_FAILED = "ai.cotal.ep.registry-read-failed";
|
|
56
|
+
/** True iff `e` carries the {@link EP_REGISTRY_READ_FAILED} marker: a caller-side registry read
|
|
57
|
+
* failed; the responders were not the failure. */
|
|
58
|
+
export function registryReadFailed(e) {
|
|
59
|
+
return e instanceof EpEnvelopeError && (e.details ?? []).some((d) => d.kind === EP_REGISTRY_READ_FAILED);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* `details[].kind` for a refusal raised by the RESPONDER because the request declared a bound
|
|
63
|
+
* incarnation (`bind`, §13.3) that is not this instance: `failed-precondition` for a different
|
|
64
|
+
* instance, `expired` for the same instance at another epoch. It marks what no caller-side check
|
|
65
|
+
* can establish: **the command did not run, and no effect of it exists.**
|
|
66
|
+
*
|
|
67
|
+
* Set before the handler, before args validation, and before any seam that can consume a one-use
|
|
68
|
+
* proof, by the only party that knows which incarnation it is. {@link EP_UNBOUND_RESPONDER} is
|
|
69
|
+
* raised by the CALLER on the reply, after the responder has already acted — a report, not a
|
|
70
|
+
* guard. So a caller holding THIS marker may re-resolve and re-issue without risking a duplicate,
|
|
71
|
+
* which is exactly what a caller holding that one must not do.
|
|
72
|
+
*/
|
|
73
|
+
export const EP_BIND_REFUSED = "ai.cotal.ep.bind-refused";
|
|
74
|
+
/** True iff an `EpError` CARRIES the {@link EP_BIND_REFUSED} marker, saying nothing about whether
|
|
75
|
+
* the marker is believable. It is the claim's presence, not its acceptance.
|
|
76
|
+
*
|
|
77
|
+
* The two questions come apart, and conflating them is what this pair exists to prevent. Whether a
|
|
78
|
+
* caller may ACT on a bind refusal — re-issue a command it would otherwise never repeat — needs
|
|
79
|
+
* the marker AND an explicit `not-executed`, which is {@link replyRefusedBeforeEffect}. Whether a
|
|
80
|
+
* reply is CHECKED for self-consistency needs only the claim, because the contradiction being
|
|
81
|
+
* checked is between the reply's BODY and the subject the broker pinned, and that is a
|
|
82
|
+
* contradiction whatever the outcome field says — or does not say.
|
|
83
|
+
*
|
|
84
|
+
* Gating the checks on the stronger predicate meant a reply could skip them by OMITTING a field,
|
|
85
|
+
* so the least credible shape drew the least scrutiny. */
|
|
86
|
+
export function bindRefusalMarked(e) {
|
|
87
|
+
return (e?.details ?? []).some((d) => d.kind === EP_BIND_REFUSED);
|
|
88
|
+
}
|
|
89
|
+
/** True iff an `EpError` carries the {@link EP_BIND_REFUSED} marker: a responder refused BEFORE
|
|
90
|
+
* executing, because it is not the incarnation the caller bound — the command did not run.
|
|
91
|
+
*
|
|
92
|
+
* It takes an `EpError` and not a thrown value, unlike its sibling predicates, because this
|
|
93
|
+
* refusal never arrives as a throw: it is the responder's own application-level failure and
|
|
94
|
+
* those ride the reply (§13.5). A consumer reads it off `reply.error`.
|
|
95
|
+
*
|
|
96
|
+
* A REPLY THAT CONTRADICTS ITSELF IS NOT A REFUSAL. The marker IS the assertion that the command
|
|
97
|
+
* did not run, and {@link EpError.outcome} says a responder refusing before dispatch MUST carry
|
|
98
|
+
* `not-executed` — but {@link EpBindRefusedDetail} carries no outcome of its own, so nothing in the
|
|
99
|
+
* type stops a reply pairing the marker with `executed`. That combination is not merely odd: the
|
|
100
|
+
* only consumer of this predicate re-issues a command **without** the {@link isRepeatSafeCommand}
|
|
101
|
+
* gate, on the strength of the marker, so resolving the contradiction toward "refused" re-sends a
|
|
102
|
+
* command the reply just said had ALREADY RUN. A present outcome that disagrees therefore wins, and
|
|
103
|
+
* the reply is not read as a refusal.
|
|
104
|
+
*
|
|
105
|
+
* AN ABSENT OUTCOME IS NOT A REFUSAL EITHER, and it is the same answer as `unknown` because the
|
|
106
|
+
* spec says they are the same value: SPEC 1510, "an error reply that omits `outcome` MUST be read
|
|
107
|
+
* as `unknown`". An earlier revision accepted absence, on the argument that a responder too old to
|
|
108
|
+
* know the field emits exactly that and refusing it would stop core repairing splits for a third
|
|
109
|
+
* party that is otherwise behaving. That argument does not survive SPEC 2271: a client MUST NOT
|
|
110
|
+
* automatically re-issue a command declared `write` after any outcome that does not prove
|
|
111
|
+
* non-execution, whatever `id` the re-issue carries, and `unknown` proves nothing. Since this
|
|
112
|
+
* predicate is what licenses a re-issue that SKIPS {@link isRepeatSafeCommand}, accepting absence
|
|
113
|
+
* made core re-issue writes on an outcome the spec says is `unknown`.
|
|
114
|
+
*
|
|
115
|
+
* The cost is real and it is bounded: a responder that omits the field no longer has its splits
|
|
116
|
+
* repaired. That responder is already non-conforming, because §13.3 requires a refusal raised
|
|
117
|
+
* before dispatch to carry `not-executed`, so what it loses is a repair it was never owed. This
|
|
118
|
+
* endpoint's own responder sets the field, so conforming deployments are unaffected. */
|
|
119
|
+
export function replyRefusedBeforeEffect(e) {
|
|
120
|
+
if (!bindRefusalMarked(e))
|
|
121
|
+
return false;
|
|
122
|
+
return e?.outcome === "not-executed";
|
|
123
|
+
}
|
|
18
124
|
/** A consuming-boundary rejection: the catalog code plus a human message. Boundaries convert it
|
|
19
125
|
* to an `EndpointReply` error via {@link EpEnvelopeError.toEpError} (or, on reply-less planes,
|
|
20
126
|
* to the §13.4 decision/quarantine fact carrying the same code). */
|
|
21
127
|
export class EpEnvelopeError extends Error {
|
|
22
128
|
code;
|
|
23
129
|
details;
|
|
24
|
-
|
|
130
|
+
outcome;
|
|
131
|
+
constructor(code, message, details, outcome) {
|
|
25
132
|
super(message);
|
|
26
133
|
this.code = code;
|
|
27
134
|
this.details = details;
|
|
135
|
+
this.outcome = outcome;
|
|
28
136
|
this.name = "EpEnvelopeError";
|
|
29
137
|
}
|
|
30
138
|
toEpError() {
|
|
31
|
-
return {
|
|
139
|
+
return {
|
|
140
|
+
code: this.code, message: this.message,
|
|
141
|
+
...(this.details ? { details: this.details } : {}),
|
|
142
|
+
...(this.outcome ? { outcome: this.outcome } : {}),
|
|
143
|
+
};
|
|
32
144
|
}
|
|
33
145
|
}
|
|
34
146
|
//# sourceMappingURL=endpoint-error.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"endpoint-error.js","sourceRoot":"","sources":["../src/endpoint-error.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;mDACmD;AACnD,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC;IAC1C,aAAa,EAAE,qBAAqB,EAAE,aAAa,EAAE,gBAAgB,EAAE,iBAAiB;IACxF,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,WAAW,EAAE,gBAAgB;IACxF,UAAU,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,qBAAqB;IAC1E,mBAAmB,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe;IAC3E,oBAAoB,EAAE,UAAU;CACxB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"endpoint-error.js","sourceRoot":"","sources":["../src/endpoint-error.ts"],"names":[],"mappings":"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"}
|