@cotal-ai/core 0.12.0 → 0.13.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 +31 -7
- package/dist/acls.d.ts.map +1 -1
- package/dist/acls.js +105 -17
- package/dist/acls.js.map +1 -1
- package/dist/agent-file.js +1 -1
- package/dist/agent-file.js.map +1 -1
- package/dist/auth-provider.d.ts +8 -0
- package/dist/auth-provider.d.ts.map +1 -1
- package/dist/auth-provider.js.map +1 -1
- package/dist/backup.d.ts.map +1 -1
- package/dist/backup.js +6 -4
- package/dist/backup.js.map +1 -1
- package/dist/broker-floor.d.ts +34 -0
- package/dist/broker-floor.d.ts.map +1 -0
- package/dist/broker-floor.js +39 -0
- package/dist/broker-floor.js.map +1 -0
- package/dist/canonical.d.ts +24 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +159 -0
- package/dist/canonical.js.map +1 -0
- package/dist/connector.d.ts +4 -0
- package/dist/connector.d.ts.map +1 -1
- package/dist/endpoint-action.d.ts +424 -0
- package/dist/endpoint-action.d.ts.map +1 -0
- package/dist/endpoint-action.js +910 -0
- package/dist/endpoint-action.js.map +1 -0
- package/dist/endpoint-binding.d.ts +344 -0
- package/dist/endpoint-binding.d.ts.map +1 -0
- package/dist/endpoint-binding.js +753 -0
- package/dist/endpoint-binding.js.map +1 -0
- package/dist/endpoint-checkpoint.d.ts +292 -0
- package/dist/endpoint-checkpoint.d.ts.map +1 -0
- package/dist/endpoint-checkpoint.js +818 -0
- package/dist/endpoint-checkpoint.js.map +1 -0
- package/dist/endpoint-cluster.d.ts +95 -0
- package/dist/endpoint-cluster.d.ts.map +1 -0
- package/dist/endpoint-cluster.js +194 -0
- package/dist/endpoint-cluster.js.map +1 -0
- package/dist/endpoint-contract-store.d.ts +90 -0
- package/dist/endpoint-contract-store.d.ts.map +1 -0
- package/dist/endpoint-contract-store.js +348 -0
- package/dist/endpoint-contract-store.js.map +1 -0
- package/dist/endpoint-envelope.d.ts +165 -0
- package/dist/endpoint-envelope.d.ts.map +1 -0
- package/dist/endpoint-envelope.js +346 -0
- package/dist/endpoint-envelope.js.map +1 -0
- package/dist/endpoint-grants.d.ts +123 -0
- package/dist/endpoint-grants.d.ts.map +1 -0
- package/dist/endpoint-grants.js +215 -0
- package/dist/endpoint-grants.js.map +1 -0
- package/dist/endpoint-guard.d.ts +222 -0
- package/dist/endpoint-guard.d.ts.map +1 -0
- package/dist/endpoint-guard.js +468 -0
- package/dist/endpoint-guard.js.map +1 -0
- package/dist/endpoint-handle.d.ts +176 -0
- package/dist/endpoint-handle.d.ts.map +1 -0
- package/dist/endpoint-handle.js +608 -0
- package/dist/endpoint-handle.js.map +1 -0
- package/dist/endpoint-journal.d.ts +225 -0
- package/dist/endpoint-journal.d.ts.map +1 -0
- package/dist/endpoint-journal.js +431 -0
- package/dist/endpoint-journal.js.map +1 -0
- package/dist/endpoint-receipt.d.ts +225 -0
- package/dist/endpoint-receipt.d.ts.map +1 -0
- package/dist/endpoint-receipt.js +417 -0
- package/dist/endpoint-receipt.js.map +1 -0
- package/dist/endpoint-records.d.ts +243 -0
- package/dist/endpoint-records.d.ts.map +1 -0
- package/dist/endpoint-records.js +591 -0
- package/dist/endpoint-records.js.map +1 -0
- package/dist/endpoint-serve.d.ts +176 -0
- package/dist/endpoint-serve.d.ts.map +1 -0
- package/dist/endpoint-serve.js +446 -0
- package/dist/endpoint-serve.js.map +1 -0
- package/dist/endpoint-service.d.ts +518 -0
- package/dist/endpoint-service.d.ts.map +1 -0
- package/dist/endpoint-service.js +973 -0
- package/dist/endpoint-service.js.map +1 -0
- package/dist/endpoint-session.d.ts +398 -0
- package/dist/endpoint-session.d.ts.map +1 -0
- package/dist/endpoint-session.js +834 -0
- package/dist/endpoint-session.js.map +1 -0
- package/dist/endpoint-signing.d.ts +105 -0
- package/dist/endpoint-signing.d.ts.map +1 -0
- package/dist/endpoint-signing.js +190 -0
- package/dist/endpoint-signing.js.map +1 -0
- package/dist/endpoint-subjects.d.ts +222 -0
- package/dist/endpoint-subjects.d.ts.map +1 -0
- package/dist/endpoint-subjects.js +381 -0
- package/dist/endpoint-subjects.js.map +1 -0
- package/dist/endpoint-supervisor.d.ts +19 -0
- package/dist/endpoint-supervisor.d.ts.map +1 -0
- package/dist/endpoint-supervisor.js +12 -0
- package/dist/endpoint-supervisor.js.map +1 -0
- package/dist/endpoint-traits.d.ts +225 -0
- package/dist/endpoint-traits.d.ts.map +1 -0
- package/dist/endpoint-traits.js +469 -0
- package/dist/endpoint-traits.js.map +1 -0
- package/dist/endpoint-verbs.d.ts +277 -0
- package/dist/endpoint-verbs.d.ts.map +1 -0
- package/dist/endpoint-verbs.js +576 -0
- package/dist/endpoint-verbs.js.map +1 -0
- package/dist/endpoint-virtual.d.ts +308 -0
- package/dist/endpoint-virtual.d.ts.map +1 -0
- package/dist/endpoint-virtual.js +440 -0
- package/dist/endpoint-virtual.js.map +1 -0
- package/dist/endpoint-work.d.ts +304 -0
- package/dist/endpoint-work.d.ts.map +1 -0
- package/dist/endpoint-work.js +728 -0
- package/dist/endpoint-work.js.map +1 -0
- package/dist/endpoint.d.ts +66 -22
- package/dist/endpoint.d.ts.map +1 -1
- package/dist/endpoint.js +289 -89
- package/dist/endpoint.js.map +1 -1
- package/dist/evict.d.ts +95 -32
- package/dist/evict.d.ts.map +1 -1
- package/dist/evict.js +193 -3
- package/dist/evict.js.map +1 -1
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/lease.d.ts +4 -0
- package/dist/lease.d.ts.map +1 -1
- package/dist/lease.js.map +1 -1
- package/dist/members.d.ts +4 -4
- package/dist/members.d.ts.map +1 -1
- package/dist/members.js +12 -12
- package/dist/members.js.map +1 -1
- package/dist/provision.d.ts +70 -18
- package/dist/provision.d.ts.map +1 -1
- package/dist/provision.js +194 -33
- package/dist/provision.js.map +1 -1
- package/dist/safe-pattern.d.ts +33 -0
- package/dist/safe-pattern.d.ts.map +1 -0
- package/dist/safe-pattern.js +486 -0
- package/dist/safe-pattern.js.map +1 -0
- package/dist/schema-profile.d.ts +93 -0
- package/dist/schema-profile.d.ts.map +1 -0
- package/dist/schema-profile.js +284 -0
- package/dist/schema-profile.js.map +1 -0
- package/dist/streams.d.ts +13 -8
- package/dist/streams.d.ts.map +1 -1
- package/dist/streams.js +35 -18
- package/dist/streams.js.map +1 -1
- package/dist/subjects.d.ts +100 -40
- package/dist/subjects.d.ts.map +1 -1
- package/dist/subjects.js +136 -60
- package/dist/subjects.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Virtual endpoints (SPEC §13.6): a registered endpoint (`spec.activation = on-demand`) with no
|
|
3
|
+
* live instance. Submissions buffer on the ordinary journal plane; the CANONICALIZER (running
|
|
4
|
+
* wherever the endpoint's activator/owning authority runs) checks pool admission BEFORE deciding,
|
|
5
|
+
* and an ACTIVATOR watches the pool and starts an instance. This module owns the transport-thin
|
|
6
|
+
* core of that loop; everything durable composes the existing work-pool, service-record, and
|
|
7
|
+
* timer-plane primitives (never reinvented):
|
|
8
|
+
*
|
|
9
|
+
* - ADMISSION ({@link admitVirtualWork}): occupancy is the pool consumer's
|
|
10
|
+
* `num_pending + num_ack_pending`, read FRESH from the exact per-pool Consumer INFO
|
|
11
|
+
* ({@link readPoolOccupancy}) — and only after RECONCILING the canonicalizer's own
|
|
12
|
+
* outstanding acceptances against the §13.6 predicate (reconcile-orphans-before-admit: an
|
|
13
|
+
* accepted-but-lost item is repaired INTO the pool first, so the count it competes under is
|
|
14
|
+
* honest). The read FAILS CLOSED against EVERY editable consumer knob: a missing/unreadable
|
|
15
|
+
* consumer is `unavailable` (never a fabricated zero); a reported `max_deliver` other than
|
|
16
|
+
* unlimited is `failed-precondition` (a finite ceiling strands exhausted items outside BOTH
|
|
17
|
+
* counters); a `filter_subject` that is not EXACTLY the pool's derived filter (or any
|
|
18
|
+
* multi-filter shape) is `failed-precondition` (a narrowed/foreign filter undercounts while
|
|
19
|
+
* stored work remains). Admission itself RE-PROVES the serial pin live: the canonicalizer
|
|
20
|
+
* durable's `max_ack_pending` must read 1 at every admit (MaxAckPending is editable, so
|
|
21
|
+
* creation intent proves nothing later). Capacity comes from the endpoint's REGISTERED
|
|
22
|
+
* {@link VirtualActivationPolicy} (closed schema, capacity required), never a free-floating
|
|
23
|
+
* knob. An over-capacity verdict is the caller's durable `resource-exhausted` decision fact,
|
|
24
|
+
* never an accepted-and-stranded submission.
|
|
25
|
+
* - SERIAL admission ({@link virtualAdmissionConsumerConfig}): the virtual endpoint's
|
|
26
|
+
* canonicalizer durable pins `max_ack_pending: 1` BY CONSTRUCTION, so count → decide →
|
|
27
|
+
* enqueue cannot interleave across submissions. The pin is on the ADMISSION durable only:
|
|
28
|
+
* pool-worker execution concurrency is an independent knob, and occupancy already counts
|
|
29
|
+
* every worker's `num_ack_pending`.
|
|
30
|
+
* - ACTIVATION ({@link startVirtualActivator} over an {@link activatorContext}): exact
|
|
31
|
+
* Consumer INFO is a request/reply SNAPSHOT — there is no broker wakeup — so watching is
|
|
32
|
+
* BOUNDED POLLING with backoff to a FINITE maximum interval, and an INFO failure is LOUD
|
|
33
|
+
* (the required `onError` seam) while polling continues. The activator runs over its own
|
|
34
|
+
* NARROW branded context (a JetStream manager bound with `checkAPI: false`; no KV, no
|
|
35
|
+
* publisher — an exact-INFO-only credential can construct it), its grant profile is exactly
|
|
36
|
+
* {@link activatorGrants} (the one `$JS.API.CONSUMER.INFO.EPW_<space>.pool_<e>_<pool>` row),
|
|
37
|
+
* and the start is a TARGET-BOUND mediated seam (`startInstance()`, fully bound at
|
|
38
|
+
* construction). `stop()` is re-checked after EVERY await: a not-yet-started activation
|
|
39
|
+
* never begins after stop (an already-running start completes on its own).
|
|
40
|
+
* - RESTART-INTENSITY supervision ({@link noteInstanceRestart}): the restart history is
|
|
41
|
+
* DURABLE and SUPERVISOR-OWNED — it rides the instance's `svc….status` record, and
|
|
42
|
+
* `writeServiceStatus` carries it forward through every ordinary (unpinned) instance write,
|
|
43
|
+
* so a successor's `ready` convergence can neither reset nor forge it. Every note is a
|
|
44
|
+
* revision-pinned CAS (two concurrent notes can never merge-lose a restart), each history
|
|
45
|
+
* entry is BOUND TO THE DYING PROCESS EPOCH (a real restart advances the epoch, so a
|
|
46
|
+
* retried/duplicated note for the same restart is an idempotent no-op, never a double
|
|
47
|
+
* count), and a CLOCK REGRESSION (`now` before the newest recorded restart) REFUSES rather
|
|
48
|
+
* than silently amnestying history. More than `maxRestarts` (default
|
|
49
|
+
* {@link RESTART_MAX_DEFAULT}) within `restartWindowMs` (default
|
|
50
|
+
* {@link RESTART_WINDOW_MS_DEFAULT}) escalates: the status records
|
|
51
|
+
* {@link SERVICE_ESCALATED} — IRREVERSIBLE at the status writer, excluded from scatter's
|
|
52
|
+
* live expected set — and the caller's D13 retire seam (`retireLifecycle`, the §13.1
|
|
53
|
+
* terminal barrier, MUST be idempotent) runs after. A retire failure surfaces `unavailable`
|
|
54
|
+
* with the escalation standing, and {@link reconcileEscalation} is the RETRY: it acts on
|
|
55
|
+
* already-escalated rows, re-invokes the idempotent retire seam until it succeeds, and
|
|
56
|
+
* marks completion durably (the pinned retirement mark is the ONE touch an escalated row
|
|
57
|
+
* admits, written directly by the reconciler).
|
|
58
|
+
*
|
|
59
|
+
* Passivation is composition, not new machinery: drain, `writeServiceStatus` to
|
|
60
|
+
* `SERVICE_EXITED`, exit; durable reminders ride the timer plane (`emitScheduleRequest`).
|
|
61
|
+
*/
|
|
62
|
+
import type { KV } from "@nats-io/kv";
|
|
63
|
+
import type { NatsConnection } from "@nats-io/transport-node";
|
|
64
|
+
import { type ConsumerConfig, type JetStreamManager } from "@nats-io/jetstream";
|
|
65
|
+
import { type WorkPoolContext, type WorkItemRef } from "./endpoint-work.js";
|
|
66
|
+
/** The activator's NARROW broker context: a JetStream manager and the space, nothing else — no
|
|
67
|
+
* KV, no publisher, so a credential holding only the exact Consumer INFO row can construct it
|
|
68
|
+
* (`checkAPI: false`: binding does not require `$JS.API.INFO`). Branded like WorkPoolContext:
|
|
69
|
+
* a hand-assembled look-alike is rejected at every consuming seam. */
|
|
70
|
+
export interface ActivatorContext {
|
|
71
|
+
jsm: JetStreamManager;
|
|
72
|
+
space: string;
|
|
73
|
+
}
|
|
74
|
+
export declare function activatorContext(nc: NatsConnection, space: string): Promise<ActivatorContext>;
|
|
75
|
+
/** The activator principal's COMPLETE broker authority (§13.6/§13.9): the exact per-pool
|
|
76
|
+
* Consumer INFO PUBLISH row plus — since Consumer INFO is a request/reply call — the
|
|
77
|
+
* CONNECTION-SCOPED reply inbox SUBSCRIBE row `_INBOX_<connId>.>` (never account-wide
|
|
78
|
+
* `_INBOX.>`, which is cross-connection reply-read authority). The start is a mediated,
|
|
79
|
+
* target-bound seam (off-broker or its own ep rail), so it contributes no row here; NOTHING
|
|
80
|
+
* else — no MSG.NEXT/ACK, no EPW STREAM.MSG.GET, no consumer create/update/delete, no EPW
|
|
81
|
+
* publish. The credential's OWN lifetime/renewal/lifecycle-UID binding rides the production
|
|
82
|
+
* activator provisioning (the named manager-wiring slice); this is the confined subject set.
|
|
83
|
+
* `connId` is the connection's validated inbox nonce (the same `_INBOX_<connId>` prefix the
|
|
84
|
+
* connection sets); omit it to get the publish half alone. */
|
|
85
|
+
export declare function activatorGrants(space: string, endpoint: string, pool: string, connId?: string): {
|
|
86
|
+
publish: string[];
|
|
87
|
+
subscribe: string[];
|
|
88
|
+
};
|
|
89
|
+
/** The pool's admission occupancy (§13.6): stored-and-uncounted states do not exist while the
|
|
90
|
+
* reader's invariants hold (WorkQueue retention + unlimited delivery + the exact pool filter +
|
|
91
|
+
* explicit ack). */
|
|
92
|
+
export interface PoolOccupancy {
|
|
93
|
+
/** Not yet delivered to the pool consumer. */
|
|
94
|
+
pending: number;
|
|
95
|
+
/** Delivered, awaiting ack (a worker is on it, or redelivery is due). */
|
|
96
|
+
ackPending: number;
|
|
97
|
+
/** `pending + ackPending` — the §13.6 admission count. */
|
|
98
|
+
occupancy: number;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Read the pool's occupancy FRESH from the exact per-pool Consumer INFO (request/reply
|
|
102
|
+
* snapshot; leader-routed like every JS API call). FAIL CLOSED, never fabricated — and every
|
|
103
|
+
* EDITABLE knob the count depends on is re-proved at EVERY read, because a post-create
|
|
104
|
+
* consumer edit must not silently falsify the fence:
|
|
105
|
+
* - a missing or unreadable consumer is `unavailable` (an admission fence cannot treat
|
|
106
|
+
* ignorance as an empty pool);
|
|
107
|
+
* - a reported `max_deliver` other than -1 (unlimited) is `failed-precondition`
|
|
108
|
+
* ({@link poolConsumerConfig} pins -1 at create; MaxDeliver is editable after);
|
|
109
|
+
* - a `filter_subject` that is not EXACTLY the pool's derived filter — or any multi-filter
|
|
110
|
+
* (`filter_subjects`) shape — is `failed-precondition`: FilterSubject is editable, and a
|
|
111
|
+
* narrowed/foreign filter reads 0 while stored work remains;
|
|
112
|
+
* - a non-explicit ack policy is `failed-precondition` (without an ack barrier,
|
|
113
|
+
* `num_ack_pending` does not mean "work still owned").
|
|
114
|
+
* Accepts the branded {@link WorkPoolContext} (admission path) or the narrow branded
|
|
115
|
+
* {@link ActivatorContext} (the watch loop); a hand-assembled context is refused.
|
|
116
|
+
*/
|
|
117
|
+
export declare function readPoolOccupancy(ctx: WorkPoolContext | ActivatorContext, endpoint: string, pool: string): Promise<PoolOccupancy>;
|
|
118
|
+
/**
|
|
119
|
+
* The VIRTUAL endpoint's canonicalizer durable: {@link canonConsumerConfig} with
|
|
120
|
+
* `max_ack_pending` PINNED to 1 (not an option — the pin is the point). One submission is in
|
|
121
|
+
* the admission path at a time, so the count → decide → enqueue sequence is SERIAL and two
|
|
122
|
+
* concurrent submissions cannot both observe the same free slot. Pool-worker execution
|
|
123
|
+
* concurrency is untouched: occupancy already counts every worker's `num_ack_pending`, and the
|
|
124
|
+
* worker durable keeps its own knobs. Because MaxAckPending is EDITABLE post-create,
|
|
125
|
+
* {@link admitVirtualWork} re-proves the live pin at every admission — creation intent alone
|
|
126
|
+
* is not the invariant.
|
|
127
|
+
*/
|
|
128
|
+
export declare function virtualAdmissionConsumerConfig(space: string, endpoint: string, opts?: {
|
|
129
|
+
ackWaitMs?: number;
|
|
130
|
+
}): Partial<ConsumerConfig>;
|
|
131
|
+
/** One outstanding acceptance the canonicalizer must reconcile before it counts (§13.6: the
|
|
132
|
+
* acceptance→enqueue bridge is repaired by the decidable predicate, never guessed). */
|
|
133
|
+
export interface OutstandingAcceptance {
|
|
134
|
+
ref: WorkItemRef;
|
|
135
|
+
itemBytes: Uint8Array;
|
|
136
|
+
workExpiry: number;
|
|
137
|
+
}
|
|
138
|
+
export interface VirtualAdmissionVerdict {
|
|
139
|
+
/** True iff the pool has a free slot under the policy's capacity AFTER repair. A false
|
|
140
|
+
* verdict is the caller's durable `resource-exhausted` decision fact (§13.6), not an error. */
|
|
141
|
+
admitted: boolean;
|
|
142
|
+
occupancy: PoolOccupancy;
|
|
143
|
+
capacity: number;
|
|
144
|
+
/** How many outstanding acceptances the pre-admission reconciliation re-enqueued. */
|
|
145
|
+
repaired: number;
|
|
146
|
+
/** The RE-PROVEN registration revision the decision bound to (§13.6): the caller carries it
|
|
147
|
+
* into the acceptance commit so the accept CAS fences on the same policy coordinate. */
|
|
148
|
+
policyRevision: number;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* The §13.6 admission fence, in the canonicalizer's decide path (admission BEFORE decision):
|
|
152
|
+
* 1. RE-PROVE the serial pin LIVE: the canonicalizer durable must report
|
|
153
|
+
* `max_ack_pending === 1` and its exact EPJ filter (both editable post-create); a drifted
|
|
154
|
+
* admission durable means the serial invariant is GONE — refuse, never decide;
|
|
155
|
+
* 2. RECONCILE the caller's outstanding acceptances (`reconcileWorkItem` per item, the §13.6
|
|
156
|
+
* predicate): an accepted item with no terminal, no settled lease, and no live pool entry
|
|
157
|
+
* is re-enqueued NOW, so repaired work is inside the count new work competes under;
|
|
158
|
+
* 3. read occupancy FRESH ({@link readPoolOccupancy}, fail-closed against every editable knob);
|
|
159
|
+
* 4. verdict: `occupancy < policy.capacity` (the REGISTERED activation policy, closed schema).
|
|
160
|
+
* Infrastructure failures THROW (`unavailable`/`failed-precondition`); only a genuine
|
|
161
|
+
* over-capacity state returns `admitted: false`.
|
|
162
|
+
*/
|
|
163
|
+
export declare function admitVirtualWork(ctx: WorkPoolContext, args: {
|
|
164
|
+
endpoint: string;
|
|
165
|
+
pool: string;
|
|
166
|
+
/** The registered instance whose `svc` spec carries the activation policy (§13.6): the
|
|
167
|
+
* capacity is READ from that registration, LEADER-SERVED, never taken from the caller. */
|
|
168
|
+
instanceId: string;
|
|
169
|
+
/** The canonicalizer's own accepted-but-unsettled items (its journal redeliveries). */
|
|
170
|
+
outstanding?: OutstandingAcceptance[];
|
|
171
|
+
now: number;
|
|
172
|
+
}): Promise<VirtualAdmissionVerdict>;
|
|
173
|
+
export interface VirtualActivatorOpts {
|
|
174
|
+
/** The NARROW branded activator context ({@link activatorContext}) — the watch loop's whole
|
|
175
|
+
* broker surface is the exact Consumer INFO its {@link activatorGrants} row permits. */
|
|
176
|
+
ctx: ActivatorContext;
|
|
177
|
+
endpoint: string;
|
|
178
|
+
pool: string;
|
|
179
|
+
/** The TARGET-BOUND mediated start seam: fully bound at construction (no arguments, so a
|
|
180
|
+
* compromised activator cannot redirect it), resolved by the supervisor/manager that holds
|
|
181
|
+
* the actual start authority. Idempotence against a concurrent start is the registration
|
|
182
|
+
* barrier's job, not this seam's. It MUST refuse an escalated identity — production wires
|
|
183
|
+
* it through the supervisor, whose start path consults the status record
|
|
184
|
+
* ({@link SERVICE_ESCALATED} is irreversible and excluded from liveness). */
|
|
185
|
+
startInstance(): Promise<void>;
|
|
186
|
+
/** Mediated liveness: is a live instance already serving? Answered by the caller's authority
|
|
187
|
+
* (a `svc` record read, or the supervisor), so the activator itself stays INFO-only. */
|
|
188
|
+
isLive(): Promise<boolean> | boolean;
|
|
189
|
+
/** REQUIRED loud-failure seam: an unobserved activator failure is not allowed (`kind` is
|
|
190
|
+
* `info` for an occupancy-read failure, `start` for a start/liveness failure). Polling
|
|
191
|
+
* continues with backoff after either. */
|
|
192
|
+
onError(kind: "info" | "start", err: unknown): void;
|
|
193
|
+
/** Base poll interval (ms), default 500. Exact Consumer INFO is a snapshot; polling IS the
|
|
194
|
+
* watch — there is no broker wakeup to wait for. */
|
|
195
|
+
pollMs?: number;
|
|
196
|
+
/** FINITE backoff ceiling (ms), default 5000: quiet polls back off toward it, work resets to
|
|
197
|
+
* `pollMs`. Refused unless a safe integer >= pollMs (an unbounded interval is a liveness
|
|
198
|
+
* hole dressed as economy). */
|
|
199
|
+
maxPollMs?: number;
|
|
200
|
+
/** Injectable timer/clock (testability); defaults to Node setTimeout/clearTimeout. */
|
|
201
|
+
setTimeoutFn?: (fn: () => void, ms: number) => {
|
|
202
|
+
unref?: () => void;
|
|
203
|
+
};
|
|
204
|
+
clearTimeoutFn?: (h: unknown) => void;
|
|
205
|
+
}
|
|
206
|
+
export interface VirtualActivator {
|
|
207
|
+
/** Stop polling. Idempotent. Re-checked after EVERY await: a start not yet begun never
|
|
208
|
+
* begins after stop; a start already running completes on its own. */
|
|
209
|
+
stop(): void;
|
|
210
|
+
/** Loop observability (smoke assertions + operator introspection). */
|
|
211
|
+
stats(): {
|
|
212
|
+
polls: number;
|
|
213
|
+
starts: number;
|
|
214
|
+
infoErrors: number;
|
|
215
|
+
startErrors: number;
|
|
216
|
+
lastOccupancy: number;
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Watch one pool by BOUNDED POLLING of its exact Consumer INFO and start the instance through
|
|
221
|
+
* the bound seam when there is work and no live instance. See the module header for the
|
|
222
|
+
* authority profile this loop is confined to. One start is in flight at a time (the guard is
|
|
223
|
+
* local dedupe, not the correctness fence — registration owns that); polls stay serial with the
|
|
224
|
+
* tick chain, so a slow INFO read never stacks requests.
|
|
225
|
+
*/
|
|
226
|
+
export declare function startVirtualActivator(opts: VirtualActivatorOpts): VirtualActivator;
|
|
227
|
+
/** §13.6 defaults: more than 3 restarts within 60s escalates. */
|
|
228
|
+
export declare const RESTART_MAX_DEFAULT = 3;
|
|
229
|
+
export declare const RESTART_WINDOW_MS_DEFAULT = 60000;
|
|
230
|
+
/** The SUPERVISOR-OWNED status field carrying the durable restart history: entries are
|
|
231
|
+
* `{ t, epoch }`, one per DYING PROCESS EPOCH (a real restart advances the epoch, so a
|
|
232
|
+
* replayed note is an idempotent no-op). The field is defined by the service module because
|
|
233
|
+
* {@link writeServiceStatus} carries it forward through instance-side writes. */
|
|
234
|
+
export declare const RESTART_HISTORY_FIELD = "restarts";
|
|
235
|
+
/** The reconciler's durable retirement-complete mark (see {@link reconcileEscalation}). */
|
|
236
|
+
export declare const RETIRED_MARK_FIELD = "retiredAt";
|
|
237
|
+
/** One durable restart-history entry: when, and WHICH process epoch died. */
|
|
238
|
+
export interface RestartHistoryEntry {
|
|
239
|
+
t: number;
|
|
240
|
+
epoch: number;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Note one restart of a virtual instance, DURABLY and CAS-fenced (§13.6 supervision):
|
|
244
|
+
* - the restart history rides the instance's `svc….status` record and is SUPERVISOR-OWNED
|
|
245
|
+
* ({@link writeServiceStatus} carries it forward through every unpinned instance write, so
|
|
246
|
+
* a successor's ordinary `ready` convergence cannot reset or forge it);
|
|
247
|
+
* - the write is pinned to the revision THIS call read (`expectedStatusRevision`), so two
|
|
248
|
+
* concurrent notes can never merge-lose a restart (one loses `conflict` and retries);
|
|
249
|
+
* - each entry is BOUND to the dying process epoch: a note whose epoch is already recorded is
|
|
250
|
+
* an idempotent NO-OP (`duplicate: true`) — one physical restart counts once, however many
|
|
251
|
+
* times its notification is retried or duplicated;
|
|
252
|
+
* - a CLOCK REGRESSION (`now` before the newest recorded restart) REFUSES
|
|
253
|
+
* (`failed-precondition`): a rolled-back supervisor clock must not amnesty durable history;
|
|
254
|
+
* - a stored {@link SERVICE_ESCALATED} state REFUSES (`failed-precondition`): the instance
|
|
255
|
+
* has stopped restarting, terminally — {@link reconcileEscalation} is the retirement retry;
|
|
256
|
+
* - more than `maxRestarts` entries within `restartWindowMs` (the pruned history plus this
|
|
257
|
+
* note) ESCALATES: the status commits {@link SERVICE_ESCALATED} first (irreversible at the
|
|
258
|
+
* writer), then the caller's D13 retire seam runs (`retireLifecycle`, the §13.1 terminal
|
|
259
|
+
* barrier, MUST be idempotent). A retire failure is `unavailable` with the escalated status
|
|
260
|
+
* already durable — honest halves; {@link reconcileEscalation} retries until it completes.
|
|
261
|
+
* A non-escalating note records {@link SERVICE_EXITED} (the instance just died; its successor
|
|
262
|
+
* writes `ready` itself when it registers) with the pruned history plus this note.
|
|
263
|
+
*/
|
|
264
|
+
export declare function noteInstanceRestart(kv: KV, args: {
|
|
265
|
+
endpoint: string;
|
|
266
|
+
instanceId: string;
|
|
267
|
+
/** The DYING instance's epoch (still the mapping's current one until a successor activates). */
|
|
268
|
+
epoch: number;
|
|
269
|
+
now: number;
|
|
270
|
+
/** The trusted lifecycle-mapping reader (same seam as {@link writeServiceStatus}). */
|
|
271
|
+
readProcessEpoch: () => Promise<number> | number;
|
|
272
|
+
/** LEADER-SERVED reader of the endpoint's `svc.<endpoint>.<instanceId>` spec (value +
|
|
273
|
+
* revision). The restart-intensity thresholds are FENCING by use (they gate escalation and
|
|
274
|
+
* retirement), so the policy MUST NOT be read through a follower-capable KV get — a stale
|
|
275
|
+
* wider window would suppress an escalation. Production wires the records-KV leader-served
|
|
276
|
+
* `STREAM.MSG.GET` reader here (the same one the admission fence uses). */
|
|
277
|
+
readSpecLeader: () => Promise<{
|
|
278
|
+
value: unknown;
|
|
279
|
+
revision: number;
|
|
280
|
+
} | undefined>;
|
|
281
|
+
/** The D13/§13.1 terminal retire seam, invoked ONLY on escalation. MUST be idempotent
|
|
282
|
+
* ({@link reconcileEscalation} re-invokes it on retry). */
|
|
283
|
+
retireLifecycle: () => Promise<void>;
|
|
284
|
+
}): Promise<{
|
|
285
|
+
escalated: boolean;
|
|
286
|
+
restartsInWindow: number;
|
|
287
|
+
duplicate: boolean;
|
|
288
|
+
}>;
|
|
289
|
+
/**
|
|
290
|
+
* The escalation RETIREMENT reconciler (§13.6: "the lifecycle retires terminally" must survive
|
|
291
|
+
* a crash or a failed retire between the escalation CAS and the barrier): acts on an
|
|
292
|
+
* already-escalated status row, re-invokes the caller's IDEMPOTENT retire seam until it
|
|
293
|
+
* succeeds, and then durably marks completion (a revision-pinned direct update — the one touch
|
|
294
|
+
* an escalated row admits; {@link writeServiceStatus} refuses everything else). Run it on
|
|
295
|
+
* supervisor startup and whenever {@link noteInstanceRestart} refuses on an escalated row.
|
|
296
|
+
* Returns what it found and whether THIS pass did the retirement.
|
|
297
|
+
*/
|
|
298
|
+
export declare function reconcileEscalation(kv: KV, args: {
|
|
299
|
+
endpoint: string;
|
|
300
|
+
instanceId: string;
|
|
301
|
+
now: number;
|
|
302
|
+
retireLifecycle: () => Promise<void>;
|
|
303
|
+
}): Promise<{
|
|
304
|
+
escalated: boolean;
|
|
305
|
+
retired: boolean;
|
|
306
|
+
acted: boolean;
|
|
307
|
+
}>;
|
|
308
|
+
//# sourceMappingURL=endpoint-virtual.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint-virtual.d.ts","sourceRoot":"","sources":["../src/endpoint-virtual.ts"],"names":[],"mappings":"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"}
|