@eir-labs/coltrane 0.11.0 → 0.12.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.
@@ -0,0 +1,105 @@
1
+ /** The lease a claimed gig carries — a continuing renewed fact (monotonic `renewed_at`), not a boot
2
+ * assertion. */
3
+ export interface LeaseState {
4
+ holder: string;
5
+ renewed_at: number;
6
+ expires_at: number;
7
+ }
8
+ /** A claimed local gig — the sibling of worker.ts ClaimedGig, plus the local lease and, on a
9
+ * re-claim, the human seat's role-keyed verdicts. */
10
+ export interface ClaimedLocalGig {
11
+ gig_id: string;
12
+ standard_slug: string;
13
+ standard_version: number | null;
14
+ mode: string;
15
+ input: Record<string, unknown>;
16
+ acting_for: string;
17
+ venue?: string | null;
18
+ worker: string;
19
+ lease: LeaseState;
20
+ approvals?: Record<string, {
21
+ verdict: Record<string, unknown>;
22
+ approved_by?: string;
23
+ }> | null;
24
+ }
25
+ /** One row's observable state — how a reader tells a live claim from an abandoned one. */
26
+ export interface LocalGigView {
27
+ gig_id: string;
28
+ state: "queued" | "claimed" | "awaiting_approval" | "complete" | "failed" | "cancelled";
29
+ holder?: string;
30
+ lease?: LeaseState;
31
+ }
32
+ export interface LocalQueueOptions {
33
+ leaseMs?: number;
34
+ /** Injected clock for deterministic lease/reap laws. Defaults to Date.now(). */
35
+ clock?: () => number;
36
+ }
37
+ /** The local queue port — every verb is offline and needs no credential. */
38
+ export interface LocalQueue {
39
+ enqueue(args: Record<string, unknown>): Promise<{
40
+ gig_id: string;
41
+ status: "queued";
42
+ }>;
43
+ claim(worker: string): Promise<ClaimedLocalGig | null>;
44
+ heartbeat(worker: string, gig_id: string): Promise<boolean>;
45
+ reap(): {
46
+ requeued: string[];
47
+ kept: number;
48
+ errors: string[];
49
+ };
50
+ park(worker: string, gig_id: string): Promise<boolean>;
51
+ approve(gig_id: string, role: string, verdict: Record<string, unknown>, approved_by?: string): Promise<boolean>;
52
+ cancel(args: Record<string, unknown>): Promise<{
53
+ gig_id: string;
54
+ status: "cancelled";
55
+ }>;
56
+ complete(worker: string, gig_id: string, output: Record<string, unknown>): Promise<{
57
+ content_sha: string;
58
+ duplicated: boolean;
59
+ }>;
60
+ list(): LocalGigView[];
61
+ readonly leaseMs: number;
62
+ }
63
+ /** Which backing owns the queue, decided by which environment is present. */
64
+ export type QueueBackingChoice = {
65
+ backing: "file";
66
+ root: string;
67
+ } | {
68
+ backing: "hosted";
69
+ } | {
70
+ backing: "none";
71
+ why: string;
72
+ } | {
73
+ backing: "conflict";
74
+ why: string;
75
+ };
76
+ export interface LocalQueueModule {
77
+ openLocalQueue(root: string, opts?: LocalQueueOptions): LocalQueue;
78
+ fileQueueGig(root: string): (args: Record<string, unknown>) => Promise<Record<string, unknown>>;
79
+ fileCancelGig(root: string): (args: Record<string, unknown>) => Promise<Record<string, unknown>>;
80
+ selectQueueBacking(env: Record<string, string | undefined>): QueueBackingChoice;
81
+ LOCAL_QUEUE_DIR_VAR: string;
82
+ DRAIN_VARS: readonly string[];
83
+ }
84
+ /** The env var whose presence selects the local backing. */
85
+ export declare const LOCAL_QUEUE_DIR_VAR = "COLTRANE_QUEUE_DIR";
86
+ /** The drain's five-variable contract (drain_preflight.ts:55-61), kept SORTED. The local path must
87
+ * never read a VALUE of any of these; selectQueueBacking only ever inspects key PRESENCE. */
88
+ export declare const DRAIN_VARS: readonly string[];
89
+ /**
90
+ * The single backing selector — file when the local dir is present, hosted for the drain env,
91
+ * conflict when both, none otherwise. It reads the VALUE of exactly one variable, LOCAL_QUEUE_DIR_VAR
92
+ * (not a drain var), and detects hosted presence by KEY PRESENCE via Object.keys — never by reading a
93
+ * drain variable's value. That distinction is load-bearing for F8: the test passes an env Proxy whose
94
+ * `get` trap throws on any drain-var read, so hosted detection must go through `ownKeys` (Object.keys
95
+ * does not trip the `get` trap), letting a local-present env resolve to `file` without touching one of
96
+ * the five. Values of the drain vars are never needed — their mere presence is the whole signal.
97
+ */
98
+ export declare function selectQueueBacking(env: Record<string, string | undefined>): QueueBackingChoice;
99
+ export declare function openLocalQueue(root: string, opts?: LocalQueueOptions): LocalQueue;
100
+ /** The deps.queueGig-shaped enqueue seam — byte-compatible with postgrestQueueGig / rpcQueueGig
101
+ * ({gig_id, status:'queued'}), so a caller cannot tell which backing answered (I1). */
102
+ export declare function fileQueueGig(root: string): (args: Record<string, unknown>) => Promise<Record<string, unknown>>;
103
+ /** The deps.cancelGig-shaped seam — sibling of postgrestCancelGig ({gig_id, status:'cancelled'})
104
+ * (I18). */
105
+ export declare function fileCancelGig(root: string): (args: Record<string, unknown>) => Promise<Record<string, unknown>>;
@@ -0,0 +1,380 @@
1
+ // The local, file-backed gig queue — the third gig backing, the offline sibling of the two HTTP
2
+ // seams (postgrestQueueGig / rpcQueueGig, src/genome_store.ts:532,:493). It closes the asymmetry the
3
+ // SPEC (docs/specs/SPEC-local-queue-contract.md) names: the genome port already ships a LOCAL sibling
4
+ // (fileGenomeStore, src/genome_store.ts:77) so a genome can be READ from files, but the queue port
5
+ // had none — so an open-source user could run gigs in-process yet never enqueue. This module is that
6
+ // missing sibling: clone → build → enqueue → `coltrane work` in another terminal claims and runs it,
7
+ // with no Supabase, no service origin, no cdk_ key, no minting backend.
8
+ //
9
+ // MUTUAL EXCLUSION WITHOUT A DATABASE OR A LOCK. State is a directory-per-state layout under `root`
10
+ // (queued/, claimed/, parked/, done/, failed/, cancelled/), and every transition is a single POSIX
11
+ // rename(2), which is atomic within a filesystem. A claim renames queued/<id> → claimed/<id>: the
12
+ // winner's rename removes the source, and every loser's rename of the same source fails ENOENT — that
13
+ // is how a loser learns it lost (maildir new/→cur/, cr.yp.to; FSQ tmp/→queue/→done/). No lockfile
14
+ // (which would leave stale residue reintroducing the race), no in-process mutex (which cannot cross
15
+ // the server / `coltrane work` process boundary this queue exists to bridge), no SQLite (a forbidden
16
+ // dependency). node's own fs is sufficient, and the atomicity argument depends on staying on one FS.
17
+ //
18
+ // LEASE, not lock. A claim carries a lease {holder, renewed_at, expires_at} embedded in the moved
19
+ // file, so one atomic rename carries the claim AND its lease together — there is never a window where
20
+ // a claim exists without its lease. The holder renews with heartbeat (strictly advances the lease);
21
+ // a crashed holder's grip falls open by timeout, and reap() returns lapsed claims to queued while
22
+ // never touching a fresh one. A clock may be injected (opts.clock) so lease/reap laws are
23
+ // deterministic and fast; it defaults to Date.now().
24
+ //
25
+ // IDEMPOTENT EFFECT. Because a lapsed lease lets a second worker re-run a gig, the honest guarantee
26
+ // is at-least-once + idempotent-effect: complete() seals the output under content_sha (the same
27
+ // sha256Hex(canonJson(...)) primitive the rest of the codebase uses), a re-run with the SAME output
28
+ // re-seals rather than duplicating (duplicated:true), and a re-run that would seal a DIFFERENT output
29
+ // fails closed rather than forking.
30
+ //
31
+ // This module is NOT wired into any surface (deps.queueGig / deps.cancelGig) — shipping the module
32
+ // and its laws going green is a separate act from selecting it as a backing.
33
+ import * as fs from "node:fs";
34
+ import * as fsp from "node:fs/promises";
35
+ import { join } from "node:path";
36
+ import { randomUUID } from "node:crypto";
37
+ import { sha256Hex, canonJson } from "./canonical_form.js";
38
+ // ── The env-presence contract. ────────────────────────────────────────────────────────────────────
39
+ /** The env var whose presence selects the local backing. */
40
+ export const LOCAL_QUEUE_DIR_VAR = "COLTRANE_QUEUE_DIR";
41
+ /** The drain's five-variable contract (drain_preflight.ts:55-61), kept SORTED. The local path must
42
+ * never read a VALUE of any of these; selectQueueBacking only ever inspects key PRESENCE. */
43
+ export const DRAIN_VARS = [
44
+ "COLTRANE_DRAIN_KEY",
45
+ "COLTRANE_DRAIN_URL",
46
+ "COLTRANE_INSTANCE",
47
+ "COLTRANE_STORE_ANON",
48
+ "COLTRANE_STORE_URL",
49
+ ];
50
+ /**
51
+ * The single backing selector — file when the local dir is present, hosted for the drain env,
52
+ * conflict when both, none otherwise. It reads the VALUE of exactly one variable, LOCAL_QUEUE_DIR_VAR
53
+ * (not a drain var), and detects hosted presence by KEY PRESENCE via Object.keys — never by reading a
54
+ * drain variable's value. That distinction is load-bearing for F8: the test passes an env Proxy whose
55
+ * `get` trap throws on any drain-var read, so hosted detection must go through `ownKeys` (Object.keys
56
+ * does not trip the `get` trap), letting a local-present env resolve to `file` without touching one of
57
+ * the five. Values of the drain vars are never needed — their mere presence is the whole signal.
58
+ */
59
+ export function selectQueueBacking(env) {
60
+ const localRaw = env[LOCAL_QUEUE_DIR_VAR];
61
+ const localPresent = typeof localRaw === "string" && localRaw.length > 0;
62
+ const keys = Object.keys(env);
63
+ const hostedPresent = DRAIN_VARS.some((v) => keys.includes(v));
64
+ if (localPresent && hostedPresent) {
65
+ return {
66
+ backing: "conflict",
67
+ why: `both ${LOCAL_QUEUE_DIR_VAR} and the hosted drain environment are set — refusing to guess which backing owns the gig`,
68
+ };
69
+ }
70
+ if (localPresent)
71
+ return { backing: "file", root: localRaw };
72
+ if (hostedPresent)
73
+ return { backing: "hosted" };
74
+ return {
75
+ backing: "none",
76
+ why: `no queue backing configured — set ${LOCAL_QUEUE_DIR_VAR} for a local file queue, or the drain environment for the hosted queue`,
77
+ };
78
+ }
79
+ function isRecord(v) {
80
+ return typeof v === "object" && v !== null && !Array.isArray(v);
81
+ }
82
+ const DEFAULT_LEASE_MS = 30_000;
83
+ export function openLocalQueue(root, opts) {
84
+ const leaseMs = opts?.leaseMs ?? DEFAULT_LEASE_MS;
85
+ const clock = opts?.clock ?? Date.now;
86
+ const queuedDir = join(root, "queued");
87
+ const claimedDir = join(root, "claimed");
88
+ const parkedDir = join(root, "parked");
89
+ const doneDir = join(root, "done");
90
+ const failedDir = join(root, "failed");
91
+ const cancelledDir = join(root, "cancelled");
92
+ const tmpDir = join(root, "tmp");
93
+ const dirsByState = [
94
+ [queuedDir, "queued"],
95
+ [claimedDir, "claimed"],
96
+ [parkedDir, "awaiting_approval"],
97
+ [doneDir, "complete"],
98
+ [failedDir, "failed"],
99
+ [cancelledDir, "cancelled"],
100
+ ];
101
+ // A tmp+rename atomic write: a reader of the destination sees either the OLD bytes or the whole NEW
102
+ // bytes, never a mixture. tmp lives in a dedicated dir so a claim's readdir of queued/ never lists a
103
+ // half-written temp file (F4).
104
+ async function atomicWrite(dir, name, obj) {
105
+ await fsp.mkdir(tmpDir, { recursive: true });
106
+ const tmp = join(tmpDir, `${randomUUID()}.tmp`);
107
+ await fsp.writeFile(tmp, JSON.stringify(obj), "utf8");
108
+ await fsp.mkdir(dir, { recursive: true });
109
+ await fsp.rename(tmp, join(dir, name));
110
+ }
111
+ async function readGig(path) {
112
+ try {
113
+ return JSON.parse(await fsp.readFile(path, "utf8"));
114
+ }
115
+ catch {
116
+ return null;
117
+ }
118
+ }
119
+ function isEnoent(e) {
120
+ return typeof e === "object" && e !== null && e.code === "ENOENT";
121
+ }
122
+ async function enqueue(args) {
123
+ // F10 — a payload with no standard to run is unrunnable. Refuse at enqueue and persist nothing,
124
+ // rather than enqueue a row that can only fail on a drain thirty minutes later.
125
+ const slug = args["standard_slug"];
126
+ if (typeof slug !== "string" || slug.length === 0) {
127
+ throw new Error("enqueue requires a non-empty standard_slug — nothing to run");
128
+ }
129
+ const gig_id = randomUUID();
130
+ const now = clock();
131
+ const record = {
132
+ gig_id,
133
+ standard_slug: slug,
134
+ standard_version: typeof args["standard_version"] === "number" ? args["standard_version"] : null,
135
+ mode: typeof args["mode"] === "string" ? args["mode"] : "live",
136
+ input: isRecord(args["input"]) ? args["input"] : {},
137
+ acting_for: typeof args["acting_for"] === "string" ? args["acting_for"] : "",
138
+ venue: typeof args["venue"] === "string" ? args["venue"] : null,
139
+ enqueued_at: now,
140
+ };
141
+ // F1/F4 — write then rename over queued/<gig_id>. If the root cannot be persisted to (mkdir/rename
142
+ // fails, e.g. ENOTDIR under a regular file), this throws and NO success is reported.
143
+ await atomicWrite(queuedDir, gig_id, record);
144
+ return { gig_id, status: "queued" };
145
+ }
146
+ async function claim(worker) {
147
+ let candidates;
148
+ try {
149
+ candidates = (await fsp.readdir(queuedDir)).sort();
150
+ }
151
+ catch {
152
+ return null; // no queued/ dir yet ⇒ nothing to claim
153
+ }
154
+ await fsp.mkdir(claimedDir, { recursive: true });
155
+ for (const id of candidates) {
156
+ const src = join(queuedDir, id);
157
+ const dst = join(claimedDir, id);
158
+ try {
159
+ // The arbiter. Exactly one concurrent claimer's rename of a given source succeeds; every other
160
+ // gets ENOENT (I4/I5/F3) and moves on to the next candidate (I19). A live gig is not in
161
+ // queued/ at all, so it is never a candidate here (F7).
162
+ await fsp.rename(src, dst);
163
+ }
164
+ catch {
165
+ // A lost rename race (ENOENT) is how a loser learns it lost; any other per-row fault is
166
+ // likewise "could not take this row". Either way, move to the next candidate — a lost row is
167
+ // the null sentinel, never a thrown claim (I5/F3).
168
+ continue;
169
+ }
170
+ const record = await readGig(dst);
171
+ if (record === null)
172
+ continue;
173
+ const now = clock();
174
+ const lease = { holder: worker, renewed_at: now, expires_at: now + leaseMs };
175
+ record.worker = worker;
176
+ record.lease = lease;
177
+ // Persist the lease alongside the claim (idempotent overwrite of a file only this claimer owns).
178
+ await atomicWrite(claimedDir, id, record);
179
+ const claimed = {
180
+ gig_id: record.gig_id,
181
+ standard_slug: record.standard_slug,
182
+ standard_version: record.standard_version,
183
+ mode: record.mode,
184
+ input: record.input,
185
+ acting_for: record.acting_for,
186
+ venue: record.venue,
187
+ worker,
188
+ lease,
189
+ approvals: record.approvals ?? null,
190
+ };
191
+ return claimed;
192
+ }
193
+ return null;
194
+ }
195
+ async function heartbeat(worker, gig_id) {
196
+ const path = join(claimedDir, gig_id);
197
+ const record = await readGig(path);
198
+ // F5 — the caller must still HOLD the claim. A heartbeat against a lease that was lost (the gig
199
+ // lapsed and someone else took it) or that no longer exists is a loss, never a false "still held".
200
+ if (record === null || record.lease === undefined || record.lease.holder !== worker)
201
+ return false;
202
+ const now = clock();
203
+ record.lease = { holder: worker, renewed_at: now, expires_at: now + leaseMs };
204
+ record.worker = worker;
205
+ await atomicWrite(claimedDir, gig_id, record);
206
+ return true;
207
+ }
208
+ function reap() {
209
+ // SYNCHRONOUS and best-effort (mirrors worker.ts reapWorkerState): a single unreadable claim never
210
+ // aborts the sweep. Only claimed/ is scanned, so a parked or terminal gig is structurally out of
211
+ // reach (I13) rather than guarded by a per-file predicate a future edit could forget.
212
+ const requeued = [];
213
+ const errors = [];
214
+ let kept = 0;
215
+ const now = clock();
216
+ let entries;
217
+ try {
218
+ entries = fs.readdirSync(claimedDir);
219
+ }
220
+ catch {
221
+ return { requeued, kept, errors };
222
+ }
223
+ for (const id of entries) {
224
+ const path = join(claimedDir, id);
225
+ try {
226
+ const record = JSON.parse(fs.readFileSync(path, "utf8"));
227
+ const expires = record.lease?.expires_at;
228
+ if (typeof expires === "number" && expires <= now) {
229
+ // Lapsed (I9/I10/I11) — return it to queued for the next worker. The rename is atomic; the
230
+ // stale lease left in the file is inert (list() reports no lease for a queued row, and the
231
+ // next claim overwrites it).
232
+ fs.mkdirSync(queuedDir, { recursive: true });
233
+ fs.renameSync(path, join(queuedDir, id));
234
+ requeued.push(id);
235
+ }
236
+ else {
237
+ kept++; // fresh (I8/I10) — never touched
238
+ }
239
+ }
240
+ catch (e) {
241
+ errors.push(`${id}: ${e instanceof Error ? e.message : String(e)}`);
242
+ }
243
+ }
244
+ return { requeued, kept, errors };
245
+ }
246
+ async function park(worker, gig_id) {
247
+ const src = join(claimedDir, gig_id);
248
+ const record = await readGig(src);
249
+ if (record === null || record.lease?.holder !== worker)
250
+ return false;
251
+ // Move claimed/ → parked/ first (one atomic rename), THEN clear the lease. The gig is never in two
252
+ // places, and the reaper (which scans only claimed/) can never mistake it for an abandoned claim
253
+ // (I13). awaiting_approval is not a live claim.
254
+ await fsp.mkdir(parkedDir, { recursive: true });
255
+ await fsp.rename(src, join(parkedDir, gig_id));
256
+ delete record.lease;
257
+ delete record.worker;
258
+ await atomicWrite(parkedDir, gig_id, record);
259
+ return true;
260
+ }
261
+ async function approve(gig_id, role, verdict, approved_by) {
262
+ // F6 — an empty verdict is not an approval. Fail closed rather than resume past the human chair on
263
+ // a verdict that says nothing.
264
+ if (!isRecord(verdict) || Object.keys(verdict).length === 0) {
265
+ throw new Error("an empty verdict is not an approval — refusing to resume past the human chair");
266
+ }
267
+ const src = join(parkedDir, gig_id);
268
+ const record = await readGig(src);
269
+ if (record === null)
270
+ return false;
271
+ const entry = approved_by !== undefined ? { verdict, approved_by } : { verdict };
272
+ const approvals = {
273
+ ...(record.approvals ?? {}),
274
+ };
275
+ approvals[role] = entry;
276
+ record.approvals = approvals;
277
+ // Seal the verdict into the parked row, THEN move parked/ → queued/ in one atomic rename, so the
278
+ // re-claimable row appears in queued/ already carrying its verdicts (I12).
279
+ await atomicWrite(parkedDir, gig_id, record);
280
+ await fsp.mkdir(queuedDir, { recursive: true });
281
+ await fsp.rename(join(parkedDir, gig_id), join(queuedDir, gig_id));
282
+ return true;
283
+ }
284
+ async function cancel(args) {
285
+ const gig_id = typeof args["gig_id"] === "string" ? args["gig_id"] : String(args["gig_id"] ?? "");
286
+ // Sibling of postgrestCancelGig: cancels a QUEUED row so it can never be claimed (I18). Moving it
287
+ // out of queued/ is the whole mechanism — a cancelled gig is simply no longer a claim candidate.
288
+ try {
289
+ await fsp.mkdir(cancelledDir, { recursive: true });
290
+ await fsp.rename(join(queuedDir, gig_id), join(cancelledDir, gig_id));
291
+ }
292
+ catch (e) {
293
+ if (!isEnoent(e))
294
+ throw e; // not-queued (already gone) is idempotent; a real IO fault is not
295
+ }
296
+ return { gig_id, status: "cancelled" };
297
+ }
298
+ async function locate(gig_id) {
299
+ for (const [dir] of dirsByState) {
300
+ const path = join(dir, gig_id);
301
+ try {
302
+ await fsp.access(path);
303
+ return { dir, path };
304
+ }
305
+ catch {
306
+ /* not in this state dir */
307
+ }
308
+ }
309
+ return null;
310
+ }
311
+ async function complete(worker, gig_id, output) {
312
+ const loc = await locate(gig_id);
313
+ if (loc === null)
314
+ throw new Error(`cannot complete unknown gig ${gig_id}`);
315
+ const record = await readGig(loc.path);
316
+ if (record === null)
317
+ throw new Error(`cannot complete unreadable gig ${gig_id}`);
318
+ // content_sha is a pure function of the output via the codebase's own canonical hash, so two
319
+ // separate completions of identical output hash identically by construction (I14).
320
+ const content_sha = sha256Hex(canonJson(output));
321
+ if (record.content_sha !== undefined) {
322
+ // I14 — a re-run (after a lapsed lease let a second worker take the gig) re-seals the SAME output
323
+ // rather than duplicating. F9 — a DIFFERENT output for the same gig fails closed, never forks.
324
+ if (record.content_sha === content_sha)
325
+ return { content_sha, duplicated: true };
326
+ throw new Error(`gig ${gig_id} already sealed a different output — refusing to fork the result`);
327
+ }
328
+ // Record the seal in place. The gig stays where it is (typically still claimed): a lapsed lease can
329
+ // then let a second worker re-run it, and that re-run dedups against this recorded content_sha.
330
+ record.content_sha = content_sha;
331
+ record.output = output;
332
+ await atomicWrite(loc.dir, gig_id, record);
333
+ return { content_sha, duplicated: false };
334
+ }
335
+ function list() {
336
+ const views = [];
337
+ for (const [dir, state] of dirsByState) {
338
+ let entries;
339
+ try {
340
+ entries = fs.readdirSync(dir);
341
+ }
342
+ catch {
343
+ continue; // dir not created yet
344
+ }
345
+ for (const id of entries) {
346
+ if (state === "claimed") {
347
+ try {
348
+ const record = JSON.parse(fs.readFileSync(join(dir, id), "utf8"));
349
+ if (record.lease && typeof record.lease.holder === "string") {
350
+ views.push({ gig_id: id, state, holder: record.lease.holder, lease: record.lease });
351
+ continue;
352
+ }
353
+ }
354
+ catch {
355
+ /* fall through to the lease-less view */
356
+ }
357
+ views.push({ gig_id: id, state });
358
+ }
359
+ else {
360
+ views.push({ gig_id: id, state });
361
+ }
362
+ }
363
+ }
364
+ return views;
365
+ }
366
+ return { enqueue, claim, heartbeat, reap, park, approve, cancel, complete, list, leaseMs };
367
+ }
368
+ /** The deps.queueGig-shaped enqueue seam — byte-compatible with postgrestQueueGig / rpcQueueGig
369
+ * ({gig_id, status:'queued'}), so a caller cannot tell which backing answered (I1). */
370
+ export function fileQueueGig(root) {
371
+ const q = openLocalQueue(root);
372
+ return (args) => q.enqueue(args);
373
+ }
374
+ /** The deps.cancelGig-shaped seam — sibling of postgrestCancelGig ({gig_id, status:'cancelled'})
375
+ * (I18). */
376
+ export function fileCancelGig(root) {
377
+ const q = openLocalQueue(root);
378
+ return (args) => q.cancel(args);
379
+ }
380
+ //# sourceMappingURL=local_queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local_queue.js","sourceRoot":"","sources":["../../src/local_queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ export { workOnce as residencyGigPath } from "./worker.js";
2
+ export type ResidencyState = "seated" | "listening" | "playing" | "hibernated" | "drained" | "unseated";
3
+ export declare const RESIDENCY_STATES: readonly ResidencyState[];
4
+ export declare const LIVE_STATES: ReadonlySet<ResidencyState>;
5
+ export type ResidencyOpKind = "claim" | "listen" | "play" | "wake_seal" | "ack" | "heartbeat" | "hibernate" | "thaw" | "drain" | "unseat" | "reap";
6
+ export declare const RESIDENCY_OPS: readonly ResidencyOpKind[];
7
+ export type ResidencyActor = "holder" | "reaper" | "operator";
8
+ export interface LegalTransition {
9
+ from: ResidencyState;
10
+ op: ResidencyOpKind;
11
+ to: ResidencyState;
12
+ }
13
+ export declare const LEGAL_TRANSITIONS: readonly LegalTransition[];
14
+ export declare const RESIDENCY_ROW_FIELDS: readonly string[];
15
+ export declare const REFLEX_BUDGET_TICKS = 8;
16
+ export interface ResidencyRecord {
17
+ agent_slug: string;
18
+ org: string;
19
+ venue_slug: string;
20
+ channel_id: string;
21
+ soul_output_id: string | null;
22
+ status: ResidencyState;
23
+ session_id: string | null;
24
+ cursor: number;
25
+ host: string | null;
26
+ lease_until: number;
27
+ heartbeat_at: number;
28
+ fence: number;
29
+ last_sealed_sha: string | null;
30
+ private_memory?: unknown;
31
+ }
32
+ export interface ResidencyOp {
33
+ kind: ResidencyOpKind;
34
+ by?: ResidencyActor;
35
+ fence?: number;
36
+ now?: number;
37
+ host?: string;
38
+ session_id?: string;
39
+ message_index?: number;
40
+ sealed_output_sha?: string | null;
41
+ cortex_alive?: boolean;
42
+ agent_slug?: string;
43
+ org?: string;
44
+ channel_id?: string;
45
+ }
46
+ export type ResidencyRefusal = "illegal_transition" | "wrong_party" | "stale_fence" | "dead_cortex" | "immutable_identity" | "cursor_without_seal" | "double_activation";
47
+ export type ResidencyTransition = {
48
+ ok: true;
49
+ next: ResidencyRecord;
50
+ } | {
51
+ ok: false;
52
+ reason: ResidencyRefusal;
53
+ };
54
+ export interface InboundMessage {
55
+ id: string;
56
+ text: string;
57
+ at: number;
58
+ }
59
+ export interface SimClock {
60
+ now(): number;
61
+ tick(n?: number): void;
62
+ }
63
+ export interface ReflexDeps {
64
+ invoke: (...a: unknown[]) => unknown;
65
+ clock: SimClock;
66
+ }
67
+ export interface ReflexResult {
68
+ acked: true;
69
+ elapsed_ticks: number;
70
+ }
71
+ export interface ResidencySpec {
72
+ agent_slug: string;
73
+ org: string;
74
+ venue_slug: string;
75
+ channel_id: string;
76
+ }
77
+ export interface BootDeps {
78
+ resolveAgent: (slug: string) => unknown | null;
79
+ resolveVenue: (slug: string) => unknown | null;
80
+ cortexPresent: () => boolean;
81
+ seatRow: (rec: ResidencyRecord) => void;
82
+ }
83
+ export type BootRefusal = "no_such_agent" | "no_such_venue" | "no_cortex";
84
+ export type BootResult = {
85
+ ok: true;
86
+ rec: ResidencyRecord;
87
+ } | {
88
+ ok: false;
89
+ refusal: BootRefusal;
90
+ };
91
+ export interface VenueLike {
92
+ credential_surface: readonly string[];
93
+ }
94
+ export type CredentialAdmission = {
95
+ ok: true;
96
+ } | {
97
+ ok: false;
98
+ reason: "credential_breach";
99
+ };
100
+ /**
101
+ * Apply one residency op under its party constraint. TOTAL: for any (state, op) pair in the closed
102
+ * domain it never throws — a refusal is a decision, always a discriminated {ok:false,reason}. Every
103
+ * pair outside LEGAL_TRANSITIONS is refused AND leaves state unchanged (the caller keeps `rec`).
104
+ */
105
+ export declare function applyResidencyOp(rec: ResidencyRecord, op: ResidencyOp): ResidencyTransition;
106
+ /**
107
+ * Ack an inbound message in reflex: dumb by design. Invokes the model-invoker EXACTLY zero times
108
+ * (even when one is present) and completes within REFLEX_BUDGET_TICKS SIMULATED ticks on the
109
+ * injected clock — never a wall-clock read, so the budget holds identically on any machine.
110
+ */
111
+ export declare function reflexAck(_msg: InboundMessage, deps: ReflexDeps): ReflexResult;
112
+ /**
113
+ * The named reader for a dead-hibernated residency: a hibernated seat whose lease has lapsed is
114
+ * forced to `unseated`. It reaps the DEAD and not the living — a hibernated seat still inside its
115
+ * lease, or any non-hibernated record, is left untouched (a refusal, so "nothing reaped" is
116
+ * unambiguous). `hibernated` is a valid state, so without this reader a dead hibernated residency
117
+ * would read as healthy because nothing queries it.
118
+ */
119
+ export declare function reapResidency(rec: ResidencyRecord, now: number): ResidencyTransition;
120
+ /**
121
+ * A presence cannot read its OWN impressions as content: sealing an impression as evidence would let
122
+ * it witness itself. The self-read is scoped out — no impression content is ever returned.
123
+ */
124
+ export declare function readOwnImpressions(_rec: ResidencyRecord): {
125
+ content: null;
126
+ scoped_out: true;
127
+ } | {
128
+ content: unknown;
129
+ };
130
+ /**
131
+ * Admit a credential class only if the venue explicitly declares it in its credential_surface. The
132
+ * venue is the SOLE hands contract; a class it does not declare — including a channel token, which
133
+ * belongs to the distinct voice axis — is a breach.
134
+ */
135
+ export declare function admitVenueCredential(venue: VenueLike, credentialClass: string): CredentialAdmission;
136
+ /**
137
+ * Seat a residency, fail-closed. Three preflight checks run IN ORDER before seatRow ever runs, so a
138
+ * refused boot writes no row: an unresolvable agent → no_such_agent, an unresolvable venue →
139
+ * no_such_venue, an absent cortex → no_cortex. Cortex liveness is not a one-shot boot assertion — it
140
+ * also surfaces on every subsequent heartbeat (applyResidencyOp's dead_cortex path).
141
+ */
142
+ export declare function bootResidency(spec: ResidencySpec, deps: BootDeps): BootResult;
143
+ /**
144
+ * The `reside` verb REUSES work's gig path — it does not fork the drain's five-variable env contract.
145
+ * Missing COLTRANE_STORE_URL / COLTRANE_STORE_ANON is a usage refusal (exit 2), the same door work
146
+ * uses (src/cli.ts:241-248). The gig itself is workOnce, re-exported above as residencyGigPath; the
147
+ * store/channel wiring is a deployment seam the laws inject rather than assert here.
148
+ */
149
+ export declare function runReside(_argv: readonly string[], io: unknown): Promise<number>;