@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.
Files changed (152) hide show
  1. package/dist/acls.d.ts +31 -7
  2. package/dist/acls.d.ts.map +1 -1
  3. package/dist/acls.js +105 -17
  4. package/dist/acls.js.map +1 -1
  5. package/dist/agent-file.js +1 -1
  6. package/dist/agent-file.js.map +1 -1
  7. package/dist/auth-provider.d.ts +8 -0
  8. package/dist/auth-provider.d.ts.map +1 -1
  9. package/dist/auth-provider.js.map +1 -1
  10. package/dist/backup.d.ts.map +1 -1
  11. package/dist/backup.js +6 -4
  12. package/dist/backup.js.map +1 -1
  13. package/dist/broker-floor.d.ts +34 -0
  14. package/dist/broker-floor.d.ts.map +1 -0
  15. package/dist/broker-floor.js +39 -0
  16. package/dist/broker-floor.js.map +1 -0
  17. package/dist/canonical.d.ts +24 -0
  18. package/dist/canonical.d.ts.map +1 -0
  19. package/dist/canonical.js +159 -0
  20. package/dist/canonical.js.map +1 -0
  21. package/dist/connector.d.ts +4 -0
  22. package/dist/connector.d.ts.map +1 -1
  23. package/dist/endpoint-action.d.ts +424 -0
  24. package/dist/endpoint-action.d.ts.map +1 -0
  25. package/dist/endpoint-action.js +910 -0
  26. package/dist/endpoint-action.js.map +1 -0
  27. package/dist/endpoint-binding.d.ts +344 -0
  28. package/dist/endpoint-binding.d.ts.map +1 -0
  29. package/dist/endpoint-binding.js +753 -0
  30. package/dist/endpoint-binding.js.map +1 -0
  31. package/dist/endpoint-checkpoint.d.ts +292 -0
  32. package/dist/endpoint-checkpoint.d.ts.map +1 -0
  33. package/dist/endpoint-checkpoint.js +818 -0
  34. package/dist/endpoint-checkpoint.js.map +1 -0
  35. package/dist/endpoint-cluster.d.ts +95 -0
  36. package/dist/endpoint-cluster.d.ts.map +1 -0
  37. package/dist/endpoint-cluster.js +194 -0
  38. package/dist/endpoint-cluster.js.map +1 -0
  39. package/dist/endpoint-contract-store.d.ts +90 -0
  40. package/dist/endpoint-contract-store.d.ts.map +1 -0
  41. package/dist/endpoint-contract-store.js +348 -0
  42. package/dist/endpoint-contract-store.js.map +1 -0
  43. package/dist/endpoint-envelope.d.ts +165 -0
  44. package/dist/endpoint-envelope.d.ts.map +1 -0
  45. package/dist/endpoint-envelope.js +346 -0
  46. package/dist/endpoint-envelope.js.map +1 -0
  47. package/dist/endpoint-grants.d.ts +123 -0
  48. package/dist/endpoint-grants.d.ts.map +1 -0
  49. package/dist/endpoint-grants.js +215 -0
  50. package/dist/endpoint-grants.js.map +1 -0
  51. package/dist/endpoint-guard.d.ts +222 -0
  52. package/dist/endpoint-guard.d.ts.map +1 -0
  53. package/dist/endpoint-guard.js +468 -0
  54. package/dist/endpoint-guard.js.map +1 -0
  55. package/dist/endpoint-handle.d.ts +176 -0
  56. package/dist/endpoint-handle.d.ts.map +1 -0
  57. package/dist/endpoint-handle.js +608 -0
  58. package/dist/endpoint-handle.js.map +1 -0
  59. package/dist/endpoint-journal.d.ts +225 -0
  60. package/dist/endpoint-journal.d.ts.map +1 -0
  61. package/dist/endpoint-journal.js +431 -0
  62. package/dist/endpoint-journal.js.map +1 -0
  63. package/dist/endpoint-receipt.d.ts +225 -0
  64. package/dist/endpoint-receipt.d.ts.map +1 -0
  65. package/dist/endpoint-receipt.js +417 -0
  66. package/dist/endpoint-receipt.js.map +1 -0
  67. package/dist/endpoint-records.d.ts +243 -0
  68. package/dist/endpoint-records.d.ts.map +1 -0
  69. package/dist/endpoint-records.js +591 -0
  70. package/dist/endpoint-records.js.map +1 -0
  71. package/dist/endpoint-serve.d.ts +176 -0
  72. package/dist/endpoint-serve.d.ts.map +1 -0
  73. package/dist/endpoint-serve.js +446 -0
  74. package/dist/endpoint-serve.js.map +1 -0
  75. package/dist/endpoint-service.d.ts +518 -0
  76. package/dist/endpoint-service.d.ts.map +1 -0
  77. package/dist/endpoint-service.js +973 -0
  78. package/dist/endpoint-service.js.map +1 -0
  79. package/dist/endpoint-session.d.ts +398 -0
  80. package/dist/endpoint-session.d.ts.map +1 -0
  81. package/dist/endpoint-session.js +834 -0
  82. package/dist/endpoint-session.js.map +1 -0
  83. package/dist/endpoint-signing.d.ts +105 -0
  84. package/dist/endpoint-signing.d.ts.map +1 -0
  85. package/dist/endpoint-signing.js +190 -0
  86. package/dist/endpoint-signing.js.map +1 -0
  87. package/dist/endpoint-subjects.d.ts +222 -0
  88. package/dist/endpoint-subjects.d.ts.map +1 -0
  89. package/dist/endpoint-subjects.js +381 -0
  90. package/dist/endpoint-subjects.js.map +1 -0
  91. package/dist/endpoint-supervisor.d.ts +19 -0
  92. package/dist/endpoint-supervisor.d.ts.map +1 -0
  93. package/dist/endpoint-supervisor.js +12 -0
  94. package/dist/endpoint-supervisor.js.map +1 -0
  95. package/dist/endpoint-traits.d.ts +225 -0
  96. package/dist/endpoint-traits.d.ts.map +1 -0
  97. package/dist/endpoint-traits.js +469 -0
  98. package/dist/endpoint-traits.js.map +1 -0
  99. package/dist/endpoint-verbs.d.ts +277 -0
  100. package/dist/endpoint-verbs.d.ts.map +1 -0
  101. package/dist/endpoint-verbs.js +576 -0
  102. package/dist/endpoint-verbs.js.map +1 -0
  103. package/dist/endpoint-virtual.d.ts +308 -0
  104. package/dist/endpoint-virtual.d.ts.map +1 -0
  105. package/dist/endpoint-virtual.js +440 -0
  106. package/dist/endpoint-virtual.js.map +1 -0
  107. package/dist/endpoint-work.d.ts +304 -0
  108. package/dist/endpoint-work.d.ts.map +1 -0
  109. package/dist/endpoint-work.js +728 -0
  110. package/dist/endpoint-work.js.map +1 -0
  111. package/dist/endpoint.d.ts +66 -22
  112. package/dist/endpoint.d.ts.map +1 -1
  113. package/dist/endpoint.js +289 -89
  114. package/dist/endpoint.js.map +1 -1
  115. package/dist/evict.d.ts +95 -32
  116. package/dist/evict.d.ts.map +1 -1
  117. package/dist/evict.js +193 -3
  118. package/dist/evict.js.map +1 -1
  119. package/dist/index.d.ts +25 -0
  120. package/dist/index.d.ts.map +1 -1
  121. package/dist/index.js +25 -0
  122. package/dist/index.js.map +1 -1
  123. package/dist/lease.d.ts +4 -0
  124. package/dist/lease.d.ts.map +1 -1
  125. package/dist/lease.js.map +1 -1
  126. package/dist/members.d.ts +4 -4
  127. package/dist/members.d.ts.map +1 -1
  128. package/dist/members.js +12 -12
  129. package/dist/members.js.map +1 -1
  130. package/dist/provision.d.ts +70 -18
  131. package/dist/provision.d.ts.map +1 -1
  132. package/dist/provision.js +194 -33
  133. package/dist/provision.js.map +1 -1
  134. package/dist/safe-pattern.d.ts +33 -0
  135. package/dist/safe-pattern.d.ts.map +1 -0
  136. package/dist/safe-pattern.js +486 -0
  137. package/dist/safe-pattern.js.map +1 -0
  138. package/dist/schema-profile.d.ts +93 -0
  139. package/dist/schema-profile.d.ts.map +1 -0
  140. package/dist/schema-profile.js +284 -0
  141. package/dist/schema-profile.js.map +1 -0
  142. package/dist/streams.d.ts +13 -8
  143. package/dist/streams.d.ts.map +1 -1
  144. package/dist/streams.js +35 -18
  145. package/dist/streams.js.map +1 -1
  146. package/dist/subjects.d.ts +100 -40
  147. package/dist/subjects.d.ts.map +1 -1
  148. package/dist/subjects.js +136 -60
  149. package/dist/subjects.js.map +1 -1
  150. package/dist/types.d.ts +9 -0
  151. package/dist/types.d.ts.map +1 -1
  152. 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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"}