@cotal-ai/core 0.23.0 → 0.25.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 (62) hide show
  1. package/dist/checkpoint-answer.d.ts +46 -0
  2. package/dist/checkpoint-answer.d.ts.map +1 -0
  3. package/dist/checkpoint-answer.js +112 -0
  4. package/dist/checkpoint-answer.js.map +1 -0
  5. package/dist/connector-config.d.ts +23 -1
  6. package/dist/connector-config.d.ts.map +1 -1
  7. package/dist/connector-config.js +13 -1
  8. package/dist/connector-config.js.map +1 -1
  9. package/dist/connector.d.ts +20 -0
  10. package/dist/connector.d.ts.map +1 -1
  11. package/dist/endpoint-action.d.ts +2 -0
  12. package/dist/endpoint-action.d.ts.map +1 -1
  13. package/dist/endpoint-action.js +13 -2
  14. package/dist/endpoint-action.js.map +1 -1
  15. package/dist/endpoint-binding.d.ts +61 -0
  16. package/dist/endpoint-binding.d.ts.map +1 -1
  17. package/dist/endpoint-binding.js +109 -0
  18. package/dist/endpoint-binding.js.map +1 -1
  19. package/dist/endpoint-checkpoint.d.ts +21 -0
  20. package/dist/endpoint-checkpoint.d.ts.map +1 -1
  21. package/dist/endpoint-checkpoint.js +41 -3
  22. package/dist/endpoint-checkpoint.js.map +1 -1
  23. package/dist/endpoint-envelope.d.ts.map +1 -1
  24. package/dist/endpoint-envelope.js +13 -2
  25. package/dist/endpoint-envelope.js.map +1 -1
  26. package/dist/endpoint-invoke.d.ts.map +1 -1
  27. package/dist/endpoint-invoke.js +40 -4
  28. package/dist/endpoint-invoke.js.map +1 -1
  29. package/dist/endpoint-records.d.ts.map +1 -1
  30. package/dist/endpoint-records.js +86 -0
  31. package/dist/endpoint-records.js.map +1 -1
  32. package/dist/endpoint.d.ts.map +1 -1
  33. package/dist/endpoint.js +21 -0
  34. package/dist/endpoint.js.map +1 -1
  35. package/dist/index.d.ts +6 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +6 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/launch-material.d.ts +86 -0
  40. package/dist/launch-material.d.ts.map +1 -0
  41. package/dist/launch-material.js +217 -0
  42. package/dist/launch-material.js.map +1 -0
  43. package/dist/provision.d.ts.map +1 -1
  44. package/dist/provision.js +54 -11
  45. package/dist/provision.js.map +1 -1
  46. package/dist/run-journal.d.ts +337 -0
  47. package/dist/run-journal.d.ts.map +1 -0
  48. package/dist/run-journal.js +703 -0
  49. package/dist/run-journal.js.map +1 -0
  50. package/dist/run-migration.d.ts +85 -0
  51. package/dist/run-migration.d.ts.map +1 -0
  52. package/dist/run-migration.js +201 -0
  53. package/dist/run-migration.js.map +1 -0
  54. package/dist/run-notice.d.ts +84 -0
  55. package/dist/run-notice.d.ts.map +1 -0
  56. package/dist/run-notice.js +212 -0
  57. package/dist/run-notice.js.map +1 -0
  58. package/dist/run-record.d.ts +104 -0
  59. package/dist/run-record.d.ts.map +1 -0
  60. package/dist/run-record.js +58 -0
  61. package/dist/run-record.js.map +1 -0
  62. package/package.json +1 -1
@@ -0,0 +1,212 @@
1
+ /**
2
+ * The RUN NOTICE record: a bounded decision a workflow told an agent about, written onto the run.
3
+ *
4
+ * **A record and not a channel post.** `notify` is the only primitive that moves program-authored
5
+ * bytes toward an agent's context, and a post would put the program into the conversation as a
6
+ * participant — the one thing this plane's first non-negotiable forbids. So a notice is filed here,
7
+ * addressed to one agent, and rendered as a fixed key→value table ahead of that agent's next turn.
8
+ *
9
+ * **Keyed by a DERIVED addressee id.** An agent's name is dotted and a dot is the records-key
10
+ * separator, so a raw name in the key would silently re-tokenize it into a key of another shape —
11
+ * and a name is not an id token in the first place. The id is a digest of the name; a reader holding
12
+ * the handle re-derives it, so enumerating one agent's notices is still a single prefix scan.
13
+ *
14
+ * **The spec is create-only; the status is the consumption.** A notice is something the program
15
+ * decided, so its content is immutable — a retry after a crash re-derives the same id and lands on
16
+ * its own record rather than filing a second one. Whether it has been CONSUMED is a fact somebody
17
+ * else establishes later, which is why it lives in the status half: the migrate rule refuses to
18
+ * move a run whose notice has not yet been consumed by its addressee's next turn, and that rule
19
+ * needs something to read.
20
+ */
21
+ import { createHash } from "node:crypto";
22
+ import { EpEnvelopeError } from "./endpoint-envelope.js";
23
+ import { assertIdToken } from "./endpoint-subjects.js";
24
+ import { RECORD_KINDS, createRecordEntry, readRecord, recordSpecKey, recordStatusKey, assertStatusValue, } from "./endpoint-records.js";
25
+ import { canonicalJson } from "./canonical.js";
26
+ const SPEC_KEYS = ["v", "run", "step", "addressee", "fact", "at"];
27
+ const STATUS_KEYS = ["v", "consumedAt", "by", "observedSpecRevision"];
28
+ function qualifiers(endpoint, runId, addresseeId, noticeId) {
29
+ return [endpoint, runId, addresseeId, noticeId];
30
+ }
31
+ /** base64url of the sha256, truncated to 43 characters — the same shape and alphabet as a run's
32
+ * request ids and a checkpoint answer id, so a derived id is an `<id-token>` by construction. */
33
+ function digestId(canonical) {
34
+ return createHash("sha256").update(canonical, "utf8").digest("base64url").slice(0, 43);
35
+ }
36
+ /** The key token standing for an agent. Derived from the name, never the name itself. */
37
+ export function noticeAddresseeId(agent) {
38
+ if (agent.length === 0)
39
+ throw new EpEnvelopeError("failed-precondition", `a notice addressee is an agent name; the empty string names nobody`);
40
+ return digestId(canonicalJson({ agent }));
41
+ }
42
+ /**
43
+ * The id one notice is filed under.
44
+ *
45
+ * Derived from the step's own request id and the addressee, so the same `notify` call re-run after
46
+ * a crash re-derives exactly the same ids and its create-only writes land on their own records. One
47
+ * call to N agents writes N notices, and the addressee is what separates them.
48
+ */
49
+ export function runNoticeId(requestId, addressee) {
50
+ return digestId(canonicalJson({ requestId, addressee }));
51
+ }
52
+ function parseSpec(raw, key) {
53
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw))
54
+ throw new EpEnvelopeError("internal", `notice ${key} is not an object; garbled state never authorizes`);
55
+ const o = raw;
56
+ for (const k of Object.keys(o))
57
+ if (!SPEC_KEYS.includes(k))
58
+ throw new EpEnvelopeError("internal", `notice ${key} carries the unknown field "${k}"; record schemas are closed`);
59
+ if (o.v !== 1 || typeof o.run !== "string" || typeof o.step !== "string"
60
+ || typeof o.addressee !== "string" || o.addressee.length === 0
61
+ || typeof o.at !== "number" || !Number.isSafeInteger(o.at) || o.at < 0)
62
+ throw new EpEnvelopeError("internal", `notice ${key} is malformed; garbled state never authorizes`);
63
+ const fact = o.fact;
64
+ if (fact === null || fact === undefined || typeof fact !== "object" || Array.isArray(fact)
65
+ || typeof fact.decision !== "string" || typeof fact.outcome !== "string")
66
+ throw new EpEnvelopeError("internal", `notice ${key} carries no decision fact; garbled state never authorizes`);
67
+ return {
68
+ v: 1,
69
+ run: o.run,
70
+ step: o.step,
71
+ addressee: o.addressee,
72
+ fact: fact,
73
+ at: o.at,
74
+ };
75
+ }
76
+ function parseStatus(raw, key) {
77
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw))
78
+ throw new EpEnvelopeError("internal", `notice status ${key} is not an object; garbled state never authorizes`);
79
+ const o = raw;
80
+ for (const k of Object.keys(o))
81
+ if (!STATUS_KEYS.includes(k))
82
+ throw new EpEnvelopeError("internal", `notice status ${key} carries the unknown field "${k}"; record schemas are closed`);
83
+ if (o.v !== 1 || typeof o.consumedAt !== "number" || !Number.isSafeInteger(o.consumedAt) || o.consumedAt < 0
84
+ || typeof o.by !== "string" || o.by.length === 0)
85
+ throw new EpEnvelopeError("internal", `notice status ${key} is malformed; garbled state never authorizes`);
86
+ return {
87
+ v: 1,
88
+ consumedAt: o.consumedAt,
89
+ by: o.by,
90
+ observedSpecRevision: o.observedSpecRevision,
91
+ };
92
+ }
93
+ /**
94
+ * File one notice, create-only.
95
+ *
96
+ * A retry of the same notice is not a conflict: the id is derived from the step's request id and
97
+ * the addressee, so an existing record with identical bytes is this run's own earlier attempt.
98
+ * Different bytes under the same id would mean two different decisions claiming one identity, which
99
+ * is refused rather than overwritten — a notice that could be rewritten would be a message.
100
+ */
101
+ export async function writeRunNotice(kv, endpoint, noticeId, value) {
102
+ assertIdToken(noticeId, "noticeId");
103
+ const addresseeId = noticeAddresseeId(value.addressee);
104
+ const key = recordSpecKey(RECORD_KINDS.notice, qualifiers(endpoint, value.run, addresseeId, noticeId));
105
+ try {
106
+ await createRecordEntry(kv, key, value);
107
+ return { key, created: true };
108
+ }
109
+ catch (e) {
110
+ if (!(e instanceof EpEnvelopeError && e.code === "conflict"))
111
+ throw e;
112
+ const existing = await kv.get(key);
113
+ if (!existing || existing.operation !== "PUT")
114
+ throw new EpEnvelopeError("internal", `notice ${key} lost its create CAS but is not readable; reconcile the store`);
115
+ const parsed = parseSpec(JSON.parse(new TextDecoder().decode(existing.value)), key);
116
+ if (canonicalJson(parsed) !== canonicalJson(value))
117
+ throw new EpEnvelopeError("conflict", `notice ${key} already exists with a different decision; a notice id is derived from the step that decided it, so a differing one under the same id is never overwritten`);
118
+ return { key, created: false };
119
+ }
120
+ }
121
+ /** Read one notice with its consumption, or `undefined` when nothing was filed under this id. */
122
+ export async function readRunNotice(kv, endpoint, runId, addressee, noticeId) {
123
+ return await readByQualifiers(kv, qualifiers(endpoint, runId, noticeAddresseeId(addressee), noticeId), noticeId);
124
+ }
125
+ /** The same read from the KEY's own tokens, for a caller enumerating a run rather than an agent. */
126
+ async function readByQualifiers(kv, q, noticeId) {
127
+ const merged = await readRecord(kv, RECORD_KINDS.notice, q);
128
+ if (merged === undefined)
129
+ return undefined;
130
+ const spec = parseSpec(merged.spec.value, recordSpecKey(RECORD_KINDS.notice, q));
131
+ const status = merged.status === undefined
132
+ ? undefined
133
+ : parseStatus(merged.status.value, recordStatusKey(RECORD_KINDS.notice, q));
134
+ return {
135
+ noticeId,
136
+ spec,
137
+ specRevision: merged.spec.revision,
138
+ ...(status !== undefined ? { consumed: status } : {}),
139
+ };
140
+ }
141
+ /**
142
+ * Every notice addressed to one agent on one run, oldest first.
143
+ *
144
+ * ORDER IS PART OF THE CONTRACT, because the render is a table a person or an agent reads top to
145
+ * bottom: `at` first, then the notice id, so two notices filed in the same millisecond still come
146
+ * back in one fixed order rather than in whatever order the store enumerated its keys.
147
+ */
148
+ export async function listRunNotices(kv, endpoint, runId, addressee) {
149
+ const addresseeId = noticeAddresseeId(addressee);
150
+ const prefix = recordSpecKey(RECORD_KINDS.notice, qualifiers(endpoint, runId, addresseeId, "x")).slice(0, -"x.spec".length);
151
+ // ONE wildcard token, because the addressee is fixed and only the notice id varies.
152
+ return await scan(kv, `${prefix}*.spec`);
153
+ }
154
+ /**
155
+ * Every notice filed on one RUN, whoever it was addressed to, oldest first.
156
+ *
157
+ * The migrate rule asks a question the journal cannot answer on its own: a `notify` entry
158
+ * records an input HASH, not the agents it addressed, so "has this orphaned notify been consumed?"
159
+ * cannot be asked per addressee. It is asked per RUN, and each notice's own `step` says which entry
160
+ * it came from — which is why the step is in the value rather than only in the key.
161
+ */
162
+ export async function listRunNoticesForRun(kv, endpoint, runId) {
163
+ const prefix = recordSpecKey(RECORD_KINDS.notice, qualifiers(endpoint, runId, "a", "n")).slice(0, -"a.n.spec".length);
164
+ // TWO, because both the addressee and the notice id vary — a KV filter's `*` is one token, and a
165
+ // single wildcard here would match a key shape that does not exist and return nothing at all.
166
+ return await scan(kv, `${prefix}*.*.spec`);
167
+ }
168
+ /** Read every notice a KV key filter matches. The filter is the caller's: `*` is one token. */
169
+ async function scan(kv, filter) {
170
+ const found = [];
171
+ const seen = await kv.keys(filter);
172
+ const qs = [];
173
+ for await (const key of seen) {
174
+ // The key is `notice.<endpoint>.<runId>.<addresseeId>.<noticeId>.spec` and every qualifier is
175
+ // an id token, so the four the read wants are the four before `spec`. Taken from the KEY and
176
+ // not re-derived: an enumeration holds the addressee's digest, never the name it came from.
177
+ const parts = key.split(".");
178
+ qs.push(parts.slice(parts.length - 5, parts.length - 1));
179
+ }
180
+ for (const q of qs) {
181
+ const one = await readByQualifiers(kv, q, q[q.length - 1]);
182
+ if (one !== undefined)
183
+ found.push(one);
184
+ }
185
+ found.sort((a, b) => (a.spec.at - b.spec.at) || (a.noticeId < b.noticeId ? -1 : a.noticeId > b.noticeId ? 1 : 0));
186
+ return found;
187
+ }
188
+ /**
189
+ * Record that a turn carried this notice.
190
+ *
191
+ * **The create-only CAS is the arbiter, and it is the only one.** Two turns racing to claim one
192
+ * notice both read no status and both write; the store decides, and the loser gets a loud conflict.
193
+ * A "has it been consumed already?" check before the write would be a fast path that lies under
194
+ * exactly the race it looks like it is preventing, so there is one gate rather than two — which
195
+ * turn delivered a notice is a fact about something that happened once.
196
+ */
197
+ export async function markRunNoticeConsumed(kv, endpoint, runId, addressee, noticeId, by, at) {
198
+ const q = qualifiers(endpoint, runId, noticeAddresseeId(addressee), noticeId);
199
+ const specKey = recordSpecKey(RECORD_KINDS.notice, q);
200
+ const statusKey = recordStatusKey(RECORD_KINDS.notice, q);
201
+ const merged = await readRecord(kv, RECORD_KINDS.notice, q);
202
+ if (merged === undefined)
203
+ throw new EpEnvelopeError("failed-precondition", `no notice is filed at ${specKey}; a consumption names the notice it consumed`);
204
+ const value = assertStatusValue({
205
+ v: 1,
206
+ consumedAt: at,
207
+ by,
208
+ observedSpecRevision: merged.spec.revision,
209
+ });
210
+ await createRecordEntry(kv, statusKey, value);
211
+ }
212
+ //# sourceMappingURL=run-notice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-notice.js","sourceRoot":"","sources":["../src/run-notice.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * The run record: what a workflow run IS, beside the journal that says what it DID.
3
+ *
4
+ * The journal on WFJ is append-only and authoritative about events. This is last-value-wins and
5
+ * authoritative about state — who holds the run, what state it is in, and the PIN SET resolved once
6
+ * at start. Two runs of one program under different pins are two different runs, so a resume reads
7
+ * the pins back rather than re-deriving them: "the default" is a property of the interpreter, and
8
+ * the interpreter is the thing that may have changed between attempts.
9
+ *
10
+ * It also carries the one fact the journal cannot hold about itself: **how far the journal has
11
+ * got**. A record deleted from the TAIL of a run's subject leaves the survivors contiguous — the
12
+ * ordinal chain sees nothing missing, because the missing part is the part it would have compared
13
+ * against — and the per-subject head is recalculated backwards, so the fence accepts an append at a
14
+ * head the run already moved past. Measured end to end: the run replays SHORT and intact, a
15
+ * successor activates on it, and it resumes from a prefix that is missing work the run really did.
16
+ * No anchor inside the journal can detect that. `journalHigh` is the anchor OUTSIDE it.
17
+ *
18
+ * What that anchor does and does not cover, stated plainly because a guard believed to be wider
19
+ * than it is is worse than none: it is written at each ACTIVATION, so it detects truncation back
20
+ * past the last takeover. Steps appended since that activation are not covered — writing the record
21
+ * per append would double every step's cost, and the journal's own ordinal chain already covers
22
+ * every interior loss.
23
+ */
24
+ import type { KV } from "@nats-io/kv";
25
+ import { type MergedRecord } from "./endpoint-records.js";
26
+ /**
27
+ * The pins, resolved. Structurally the language's `RunPins` — `@cotal-ai/core` does not depend on
28
+ * `@cotal-ai/lang`, and the wire shape is the contract between them rather than a shared type.
29
+ */
30
+ export interface RunPinsValue {
31
+ readonly seed: string;
32
+ /** The run's logical epoch. `now()` derives from THIS, never from the resuming host's clock. */
33
+ readonly startedAt: number;
34
+ readonly yieldEvery: number;
35
+ readonly stepBudget: number;
36
+ readonly effectCeiling: number;
37
+ readonly languageVersion: string;
38
+ }
39
+ /**
40
+ * The immutable half: what this run IS, decided once and never re-decided.
41
+ *
42
+ * Deliberately NOT carrying a program hash yet. The interpreter reports one, but only after a run,
43
+ * and a hash computed here from the source would be a different function's answer wearing the same
44
+ * name — the divergence check that matters is per-step and the language already makes it from the
45
+ * recorded input hashes. A source-identity pin is its own item, not a field filled with a guess.
46
+ */
47
+ export interface RunSpecValue {
48
+ readonly v: 1;
49
+ readonly run: string;
50
+ readonly pins: RunPinsValue;
51
+ readonly createdAt: number;
52
+ }
53
+ /**
54
+ * What a run is doing now.
55
+ *
56
+ * `released` and `failed` are not the same thing and the distinction is the point: a program that
57
+ * failed has a result and the journal has it, while a released run has no result at all — its
58
+ * driver stopped holding it. Recording one as the other would write down a conclusion about work
59
+ * nobody observed.
60
+ */
61
+ export type RunState = "running" | "released" | "completed" | "failed";
62
+ export interface RunStatusValue {
63
+ readonly v: 1;
64
+ readonly observedSpecRevision: number;
65
+ readonly state: RunState;
66
+ readonly holder: string;
67
+ readonly epoch: number;
68
+ readonly fencingToken: number;
69
+ /**
70
+ * The highest journal ordinal this run is KNOWN to have reached, written at each activation.
71
+ * A replay whose last ordinal is BELOW this has lost records from its tail.
72
+ */
73
+ readonly journalHigh: number;
74
+ readonly at: number;
75
+ }
76
+ /** A run's journal is missing records from its END — which nothing inside the journal can see. */
77
+ export declare class RunJournalTailTruncated extends Error {
78
+ readonly run: string;
79
+ readonly recordedHigh: number;
80
+ readonly replayedHigh: number;
81
+ constructor(run: string, recordedHigh: number, replayedHigh: number);
82
+ }
83
+ /** Read a run's record. `undefined` = this run has never been started. */
84
+ export declare function readRunRecord(kv: KV, endpoint: string, runId: string): Promise<MergedRecord<RunSpecValue, RunStatusValue> | undefined>;
85
+ /**
86
+ * Create a run's spec. Create-only: a spec that already exists means this run was started before,
87
+ * and starting it again under a fresh set of pins would be a different run wearing the same id.
88
+ */
89
+ export declare function createRunSpec(kv: KV, endpoint: string, runId: string, value: Omit<RunSpecValue, "v" | "run">): Promise<number>;
90
+ /**
91
+ * Write a run's status. `expectedRevision` is `undefined` for the first write and the last read
92
+ * revision thereafter — the CAS is what keeps two drivers from taking turns overwriting each
93
+ * other's view of who holds the run.
94
+ */
95
+ export declare function writeRunStatus(kv: KV, endpoint: string, runId: string, value: Omit<RunStatusValue, "v">, expectedRevision?: number): Promise<number>;
96
+ /**
97
+ * The tail check, run BETWEEN the replay and the activation.
98
+ *
99
+ * Before, and not after, because an activation appended over a rolled-back head is itself a record
100
+ * written into a journal we already know is wrong — and it would be written at an ordinal the
101
+ * deleted records already used, which is a hole the chain would then blame on someone else.
102
+ */
103
+ export declare function assertJournalTailIntact(runId: string, recorded: RunStatusValue | undefined, replayedHigh: number): void;
104
+ //# sourceMappingURL=run-record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-record.d.ts","sourceRoot":"","sources":["../src/run-record.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAQL,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAE/B;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gGAAgG;IAChG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;IACd,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,QAAQ,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC;IACd,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,kGAAkG;AAClG,qBAAa,uBAAwB,SAAQ,KAAK;IAE9C,QAAQ,CAAC,GAAG,EAAE,MAAM;IACpB,QAAQ,CAAC,YAAY,EAAE,MAAM;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM;gBAFpB,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM;CAUhC;AAED,0EAA0E;AAC1E,wBAAsB,aAAa,CACjC,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,YAAY,CAAC,YAAY,EAAE,cAAc,CAAC,GAAG,SAAS,CAAC,CAEjE;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,GAAG,GAAG,KAAK,CAAC,GACrC,OAAO,CAAC,MAAM,CAAC,CAGjB;AAED;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,GAAG,CAAC,EAChC,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,cAAc,GAAG,SAAS,EACpC,YAAY,EAAE,MAAM,GACnB,IAAI,CAKN"}
@@ -0,0 +1,58 @@
1
+ import { RECORD_KINDS, createRecordEntry, updateRecordEntry, readRecord, recordSpecKey, recordStatusKey, assertStatusValue, } from "./endpoint-records.js";
2
+ /** A run's journal is missing records from its END — which nothing inside the journal can see. */
3
+ export class RunJournalTailTruncated extends Error {
4
+ run;
5
+ recordedHigh;
6
+ replayedHigh;
7
+ constructor(run, recordedHigh, replayedHigh) {
8
+ super(`run ${run}: the journal replayed to ordinal ${replayedHigh}, but this run is recorded as having reached ${recordedHigh}. ` +
9
+ `Records are missing from the END of the subject: the surviving prefix is contiguous, so the ordinal chain cannot see it, ` +
10
+ `and the subject's head has rolled back with them. Resuming here would repeat work the run already did. ` +
11
+ `Recover the missing records or retire the run; do not drive it.`);
12
+ this.run = run;
13
+ this.recordedHigh = recordedHigh;
14
+ this.replayedHigh = replayedHigh;
15
+ this.name = "RunJournalTailTruncated";
16
+ }
17
+ }
18
+ /** Read a run's record. `undefined` = this run has never been started. */
19
+ export async function readRunRecord(kv, endpoint, runId) {
20
+ return await readRecord(kv, RECORD_KINDS.run, [endpoint, runId]);
21
+ }
22
+ /**
23
+ * Create a run's spec. Create-only: a spec that already exists means this run was started before,
24
+ * and starting it again under a fresh set of pins would be a different run wearing the same id.
25
+ */
26
+ export async function createRunSpec(kv, endpoint, runId, value) {
27
+ const spec = { v: 1, run: runId, ...value };
28
+ return await createRecordEntry(kv, recordSpecKey(RECORD_KINDS.run, [endpoint, runId]), spec);
29
+ }
30
+ /**
31
+ * Write a run's status. `expectedRevision` is `undefined` for the first write and the last read
32
+ * revision thereafter — the CAS is what keeps two drivers from taking turns overwriting each
33
+ * other's view of who holds the run.
34
+ */
35
+ export async function writeRunStatus(kv, endpoint, runId, value, expectedRevision) {
36
+ const status = assertStatusValue({ v: 1, ...value });
37
+ // Through the key BUILDER, never a join of our own: it is what asserts the endpoint and the run
38
+ // id are grammatical tokens, and a run id that tokenized loose would write into another run's key.
39
+ const key = recordStatusKey(RECORD_KINDS.run, [endpoint, runId]);
40
+ return expectedRevision === undefined
41
+ ? await createRecordEntry(kv, key, status)
42
+ : await updateRecordEntry(kv, key, status, expectedRevision);
43
+ }
44
+ /**
45
+ * The tail check, run BETWEEN the replay and the activation.
46
+ *
47
+ * Before, and not after, because an activation appended over a rolled-back head is itself a record
48
+ * written into a journal we already know is wrong — and it would be written at an ordinal the
49
+ * deleted records already used, which is a hole the chain would then blame on someone else.
50
+ */
51
+ export function assertJournalTailIntact(runId, recorded, replayedHigh) {
52
+ if (recorded === undefined)
53
+ return;
54
+ if (replayedHigh < recorded.journalHigh) {
55
+ throw new RunJournalTailTruncated(runId, recorded.journalHigh, replayedHigh);
56
+ }
57
+ }
58
+ //# sourceMappingURL=run-record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-record.js","sourceRoot":"","sources":["../src/run-record.ts"],"names":[],"mappings":"AAwBA,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACV,aAAa,EACb,eAAe,EACf,iBAAiB,GAElB,MAAM,uBAAuB,CAAC;AAwD/B,kGAAkG;AAClG,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAErC;IACA;IACA;IAHX,YACW,GAAW,EACX,YAAoB,EACpB,YAAoB;QAE7B,KAAK,CACH,OAAO,GAAG,qCAAqC,YAAY,gDAAgD,YAAY,IAAI;YACzH,2HAA2H;YAC3H,yGAAyG;YACzG,iEAAiE,CACpE,CAAC;QATO,QAAG,GAAH,GAAG,CAAQ;QACX,iBAAY,GAAZ,YAAY,CAAQ;QACpB,iBAAY,GAAZ,YAAY,CAAQ;QAQ7B,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,EAAM,EACN,QAAgB,EAChB,KAAa;IAEb,OAAO,MAAM,UAAU,CAA+B,EAAE,EAAE,YAAY,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;AACjG,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,EAAM,EACN,QAAgB,EAChB,KAAa,EACb,KAAsC;IAEtC,MAAM,IAAI,GAAiB,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,EAAE,CAAC;IAC1D,OAAO,MAAM,iBAAiB,CAAC,EAAE,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAC/F,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAM,EACN,QAAgB,EAChB,KAAa,EACb,KAAgC,EAChC,gBAAyB;IAEzB,MAAM,MAAM,GAAG,iBAAiB,CAAC,EAAE,CAAC,EAAE,CAAU,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;IAC9D,gGAAgG;IAChG,mGAAmG;IACnG,MAAM,GAAG,GAAG,eAAe,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC;IACjE,OAAO,gBAAgB,KAAK,SAAS;QACnC,CAAC,CAAC,MAAM,iBAAiB,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC;QAC1C,CAAC,CAAC,MAAM,iBAAiB,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAa,EACb,QAAoC,EACpC,YAAoB;IAEpB,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO;IACnC,IAAI,YAAY,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;QACxC,MAAM,IAAI,uBAAuB,CAAC,KAAK,EAAE,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;IAC/E,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cotal-ai/core",
3
3
  "description": "The Cotal protocol: endpoint, subjects, message types, the NATS client layer, and the extension contracts.",
4
- "version": "0.23.0",
4
+ "version": "0.25.0",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
7
7
  "cotal",