@cotal-ai/runtime 0.0.1 → 0.24.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,108 @@
1
+ /**
2
+ * `resolveCheckpoint` — the run-driver command through which a checkpoint is answered.
3
+ *
4
+ * **Nothing outside presents the token.** A checkpoint's resume is holder-bound (SPEC §13.10), and
5
+ * a workflow checkpoint's holder is the run driver: it is the one principal guaranteed to exist for
6
+ * the pause's whole life. So an observer UI, a notification action, or another agent does not talk
7
+ * to `endpoint-checkpoint` at all — each calls this, which authorizes the caller under the run's
8
+ * own ACL, files their answer, and then presents the token as the driver. "Resolvable from
9
+ * anywhere" is true at the product level while resume stays holder-bound at the protocol level, and
10
+ * §13.10 is not weakened by a millimetre. The cost is that the driver must be reachable to answer a
11
+ * checkpoint, which is the same condition under which the run advances at all.
12
+ *
13
+ * **The answer is written BEFORE the token is presented,** and the two are separate facts on
14
+ * purpose. The record is the payload; the settle is the one-use arbiter that releases the run. In
15
+ * that order a crash in between leaves an answer nobody accepted — orphaned, read by nothing, and
16
+ * harmless. In the other order it would leave a run released with its answer nowhere.
17
+ *
18
+ * **The step is addressed by its KEY, not by its token.** A token is `ctx.requestId`, derived from
19
+ * the run, the step key, the input hash and the attempt, and a resolver has none of those: it knows
20
+ * "the checkpoint named `approve` in this run". The journal is what maps one to the other, and it is
21
+ * also what says whether that step is still open — which is the question a resolver most needs
22
+ * answered before it collects a human's decision.
23
+ */
24
+ import { replayRunJournal, newTakeoverId, recordCheckpointAnswer, checkpointAnswerId, resumeCheckpoint, } from "@cotal-ai/core";
25
+ import { journalEntryKeyString } from "@cotal-ai/lang";
26
+ /** No open checkpoint answers to this address in this run. */
27
+ export class CheckpointNotOpen extends Error {
28
+ runId;
29
+ stepKey;
30
+ why;
31
+ constructor(runId, stepKey, why) {
32
+ super(`run ${runId} has no open checkpoint at ${stepKey}: ${{
33
+ unknown: "no step is recorded under that key",
34
+ settled: "that step has already settled",
35
+ "not-a-checkpoint": "that step is not a checkpoint",
36
+ "no-identity": "that step is pending but carries no request id, so the checkpoint it is waiting on cannot be named",
37
+ }[why]}`);
38
+ this.runId = runId;
39
+ this.stepKey = stepKey;
40
+ this.why = why;
41
+ this.name = "CheckpointNotOpen";
42
+ }
43
+ }
44
+ /**
45
+ * Answer a run's open checkpoint.
46
+ *
47
+ * Refusals are the plane's own and are not softened here: a checkpoint already resumed is a
48
+ * `conflict` (resume authorization is one-use) and one already expired is a `failed-precondition`
49
+ * (expiry fails closed). Both mean the answer arrived too late, and both leave this resolver's
50
+ * record filed and unaccepted — which is what the caller needs to be told rather than a success
51
+ * that names a settlement somebody else won.
52
+ */
53
+ export async function resolveCheckpoint(deps, req) {
54
+ const entries = await replayRunEntries(deps, req.runId);
55
+ const token = openCheckpointToken(entries, req.runId, req.stepKey);
56
+ const answerId = checkpointAnswerId({
57
+ token,
58
+ by: req.by,
59
+ ...(req.value !== undefined ? { value: req.value } : {}),
60
+ ...(req.artifact !== undefined ? { artifact: req.artifact } : {}),
61
+ });
62
+ await recordCheckpointAnswer(deps.kv, deps.endpoint, {
63
+ v: 1,
64
+ token,
65
+ answerId,
66
+ ...(req.value !== undefined ? { value: req.value } : {}),
67
+ ...(req.artifact !== undefined ? { artifact: req.artifact } : {}),
68
+ by: req.by,
69
+ at: req.now,
70
+ });
71
+ const settle = await resumeCheckpoint(deps.kv, deps.js, deps.jsm, deps.space, {
72
+ ref: { endpoint: deps.endpoint, token },
73
+ presenter: deps.holder,
74
+ now: req.now,
75
+ answerId,
76
+ });
77
+ return { token, answerId, settle };
78
+ }
79
+ /** The token of the open checkpoint at this address, or a loud refusal naming which it is not. */
80
+ export function openCheckpointToken(entries, runId, stepKey) {
81
+ // Append order, later record wins: a settled step has a settled entry written after its pending
82
+ // one, and answering the pending one would present a token whose pause is already over.
83
+ let entry;
84
+ for (const e of entries)
85
+ if (journalEntryKeyString(e) === stepKey)
86
+ entry = e;
87
+ if (entry === undefined)
88
+ throw new CheckpointNotOpen(runId, stepKey, "unknown");
89
+ if (entry.kind !== "checkpoint")
90
+ throw new CheckpointNotOpen(runId, stepKey, "not-a-checkpoint");
91
+ if (entry.state !== "pending")
92
+ throw new CheckpointNotOpen(runId, stepKey, "settled");
93
+ if (entry.requestId === undefined)
94
+ throw new CheckpointNotOpen(runId, stepKey, "no-identity");
95
+ return entry.requestId;
96
+ }
97
+ /** The run's step entries, in append order. Read-only: this replays under its own consumer name and
98
+ * activates nothing, so it never contends with the driver actually holding the run. */
99
+ async function replayRunEntries(deps, runId) {
100
+ const replay = await replayRunJournal(deps.js, deps.jsm, deps.space, runId, newTakeoverId());
101
+ const entries = [];
102
+ for (const stored of replay.records) {
103
+ if (stored.record.kind === "step")
104
+ entries.push(stored.record.entry);
105
+ }
106
+ return entries;
107
+ }
108
+ //# sourceMappingURL=resolve-checkpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-checkpoint.js","sourceRoot":"","sources":["../src/resolve-checkpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,GAEjB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,qBAAqB,EAAqB,MAAM,gBAAgB,CAAC;AAE1E,8DAA8D;AAC9D,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAE/B;IACA;IACA;IAHX,YACW,KAAa,EACb,OAAe,EACf,GAA+D;QAExE,KAAK,CACH,OAAO,KAAK,8BAA8B,OAAO,KAC/C;YACE,OAAO,EAAE,oCAAoC;YAC7C,OAAO,EAAE,+BAA+B;YACxC,kBAAkB,EAAE,+BAA+B;YACnD,aAAa,EAAE,oGAAoG;SACpH,CAAC,GAAG,CACP,EAAE,CACH,CAAC;QAbO,UAAK,GAAL,KAAK,CAAQ;QACb,YAAO,GAAP,OAAO,CAAQ;QACf,QAAG,GAAH,GAAG,CAA4D;QAYxE,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AA8BD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAA2B,EAC3B,GAA6B;IAE7B,MAAM,OAAO,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,mBAAmB,CAAC,OAAO,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAEnE,MAAM,QAAQ,GAAG,kBAAkB,CAAC;QAClC,KAAK;QACL,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,GAAG,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClE,CAAC,CAAC;IACH,MAAM,sBAAsB,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,EAAE;QACnD,CAAC,EAAE,CAAC;QACJ,KAAK;QACL,QAAQ;QACR,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,GAAG,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjE,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,EAAE,EAAE,GAAG,CAAC,GAAG;KACZ,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE;QAC5E,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE;QACvC,SAAS,EAAE,IAAI,CAAC,MAAM;QACtB,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,QAAQ;KACT,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AACrC,CAAC;AAED,kGAAkG;AAClG,MAAM,UAAU,mBAAmB,CACjC,OAAgC,EAChC,KAAa,EACb,OAAe;IAEf,gGAAgG;IAChG,wFAAwF;IACxF,IAAI,KAA+B,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,IAAI,qBAAqB,CAAC,CAAC,CAAC,KAAK,OAAO;YAAE,KAAK,GAAG,CAAC,CAAC;IAC7E,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,IAAI,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAChF,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY;QAAE,MAAM,IAAI,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC;IACjG,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS;QAAE,MAAM,IAAI,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACtF,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS;QAAE,MAAM,IAAI,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;IAC9F,OAAO,KAAK,CAAC,SAAS,CAAC;AACzB,CAAC;AAED;wFACwF;AACxF,KAAK,UAAU,gBAAgB,CAAC,IAA2B,EAAE,KAAa;IACxE,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,CAAC;IAC7F,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACpC,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,MAAM;YAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAqB,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The `<run-context>` render: what a workflow's notices look like in an agent's context.
3
+ *
4
+ * **A fixed key→value table, never a sentence.** The property this buys is the whole reason
5
+ * `notify` exists in its bounded form: a notice reads as DATA in the receiving agent's context and
6
+ * cannot be mistaken for an instruction from the workflow. Prose would be an instruction whatever
7
+ * intended, because an agent reading prose in its prompt has no way to tell who wrote it.
8
+ *
9
+ * Eight short scalars in a labelled table is not enough room to write an instruction. That is the
10
+ * bound's purpose rather than a side effect of it, and it is enforced at the effect boundary
11
+ * (L3043) before a notice is ever written — so this renderer never has to decide what to do with a
12
+ * value it cannot render. It REFUSES one instead: a value that could end a line could forge a row
13
+ * or a closing tag, and a renderer that quietly escaped it would be the one place where the bound
14
+ * is a formatting convention rather than a rule.
15
+ */
16
+ import type { RunNoticeRead } from "@cotal-ai/core";
17
+ /** A notice this renderer cannot put in one row. Loud, because the alternative is a forged row. */
18
+ export declare class UnrenderableNotice extends Error {
19
+ readonly noticeId: string;
20
+ readonly field: string;
21
+ constructor(noticeId: string, field: string);
22
+ }
23
+ export interface RunContextRender {
24
+ /** The run whose notices these are. */
25
+ readonly run: string;
26
+ /** The step the addressee is about to take — the coordinates of the turn this precedes, not of
27
+ * the steps that decided the notices. Each notice's own step is a fact about the program's
28
+ * history and belongs to the run, not to this header. */
29
+ readonly step: string;
30
+ readonly notices: readonly RunNoticeRead[];
31
+ }
32
+ /**
33
+ * Render the notices addressed to one agent, ahead of one turn.
34
+ *
35
+ * Columns are padded to a fixed layout so the table reads as a table; the detail column is
36
+ * `key=value` pairs in the order the notice recorded them, which is the order the program wrote
37
+ * them. An empty set renders as an empty table rather than as nothing: "no decisions were told to
38
+ * you" and "nobody rendered your context" are different facts, and only one of them is this
39
+ * renderer's to state.
40
+ */
41
+ export declare function renderRunContext(req: RunContextRender): string;
42
+ //# sourceMappingURL=run-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-context.d.ts","sourceRoot":"","sources":["../src/run-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAOpD,mGAAmG;AACnG,qBAAa,kBAAmB,SAAQ,KAAK;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM;gBAAxC,QAAQ,EAAE,MAAM,EAAW,KAAK,EAAE,MAAM;CAO9D;AAED,MAAM,WAAW,gBAAgB;IAC/B,uCAAuC;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;8DAE0D;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE,CAAC;CAC5C;AAUD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CA0B9D"}
@@ -0,0 +1,55 @@
1
+ /** A value that would break out of one table row — a control character, a line separator, or one
2
+ * of the characters the header line is built from. The effect boundary already excludes these from
3
+ * a notice; this is the second reader of the same rule, at the point where breaking out matters. */
4
+ const UNRENDERABLE = /[\u0000-\u001f\u007f-\u009f\u2028\u2029"<>]/;
5
+ /** A notice this renderer cannot put in one row. Loud, because the alternative is a forged row. */
6
+ export class UnrenderableNotice extends Error {
7
+ noticeId;
8
+ field;
9
+ constructor(noticeId, field) {
10
+ super(`notice ${noticeId} carries a line break, a control character or a delimiter in ${field}; ` +
11
+ `a run-context row is one line, and a value that can end a line can forge a row or the closing tag`);
12
+ this.noticeId = noticeId;
13
+ this.field = field;
14
+ this.name = "UnrenderableNotice";
15
+ }
16
+ }
17
+ const HEADER = { decision: "decision", outcome: "outcome", detail: "detail" };
18
+ /**
19
+ * Render the notices addressed to one agent, ahead of one turn.
20
+ *
21
+ * Columns are padded to a fixed layout so the table reads as a table; the detail column is
22
+ * `key=value` pairs in the order the notice recorded them, which is the order the program wrote
23
+ * them. An empty set renders as an empty table rather than as nothing: "no decisions were told to
24
+ * you" and "nobody rendered your context" are different facts, and only one of them is this
25
+ * renderer's to state.
26
+ */
27
+ export function renderRunContext(req) {
28
+ for (const [field, value] of [["run", req.run], ["step", req.step]])
29
+ if (UNRENDERABLE.test(value))
30
+ throw new UnrenderableNotice(`<${field}>`, field);
31
+ const rows = req.notices.map((n) => {
32
+ const fact = n.spec.fact;
33
+ for (const [field, value] of [["decision", fact.decision], ["outcome", fact.outcome]])
34
+ if (UNRENDERABLE.test(value))
35
+ throw new UnrenderableNotice(n.noticeId, field);
36
+ const detail = Object.entries(fact.detail ?? {}).map(([k, v]) => {
37
+ if (UNRENDERABLE.test(k))
38
+ throw new UnrenderableNotice(n.noticeId, `detail key ${k}`);
39
+ if (typeof v === "string" && UNRENDERABLE.test(v))
40
+ throw new UnrenderableNotice(n.noticeId, `detail.${k}`);
41
+ return `${k}=${String(v)}`;
42
+ });
43
+ return { decision: fact.decision, outcome: fact.outcome, detail: detail.join(" ") };
44
+ });
45
+ const all = [HEADER, ...rows];
46
+ const dW = Math.max(...all.map((r) => r.decision.length));
47
+ const oW = Math.max(...all.map((r) => r.outcome.length));
48
+ const line = (r) => `${r.decision.padEnd(dW)} ${r.outcome.padEnd(oW)} ${r.detail}`.trimEnd();
49
+ return [
50
+ `<run-context run="${req.run}" step="${req.step}">`,
51
+ ...all.map(line),
52
+ "</run-context>",
53
+ ].join("\n");
54
+ }
55
+ //# sourceMappingURL=run-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-context.js","sourceRoot":"","sources":["../src/run-context.ts"],"names":[],"mappings":"AAiBA;;qGAEqG;AACrG,MAAM,YAAY,GAAG,6CAA6C,CAAC;AAEnE,mGAAmG;AACnG,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IACtB;IAA2B;IAAhD,YAAqB,QAAgB,EAAW,KAAa;QAC3D,KAAK,CACH,UAAU,QAAQ,gEAAgE,KAAK,IAAI;YACzF,mGAAmG,CACtG,CAAC;QAJiB,aAAQ,GAAR,QAAQ,CAAQ;QAAW,UAAK,GAAL,KAAK,CAAQ;QAK3D,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAkBD,MAAM,MAAM,GAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAEnF;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAqB;IACpD,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,CAAU;QAC1E,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,MAAM,IAAI,kBAAkB,CAAC,IAAI,KAAK,GAAG,EAAE,KAAK,CAAC,CAAC;IAElF,MAAM,IAAI,GAAU,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACxC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACzB,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,CAAU;YAC5F,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;gBAAE,MAAM,IAAI,kBAAkB,CAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAChF,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE;YAC9D,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;gBAAE,MAAM,IAAI,kBAAkB,CAAC,CAAC,CAAC,QAAQ,EAAE,cAAc,CAAC,EAAE,CAAC,CAAC;YACtF,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;gBAAE,MAAM,IAAI,kBAAkB,CAAC,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC;YAC3G,OAAO,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC;IAC9B,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1D,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,CAAC,CAAM,EAAU,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,CAAC;IAE5G,OAAO;QACL,qBAAqB,GAAG,CAAC,GAAG,WAAW,GAAG,CAAC,IAAI,IAAI;QACnD,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;QAChB,gBAAgB;KACjB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,124 @@
1
+ import type { JetStreamClient, JetStreamManager } from "@nats-io/jetstream";
2
+ import type { KV } from "@nats-io/kv";
3
+ import { type EffectHandler, type JournalEntry, type RunResult } from "@cotal-ai/lang";
4
+ /**
5
+ * The lease this driver holds the run under, from the work pool.
6
+ *
7
+ * `fencingToken` is `WorkLease.fencingToken` — monotonic per item, and the coordinate the barrier
8
+ * orders takeovers by. `holder` and `epoch` are the identity it is bound to: a token alone would let
9
+ * a returning process re-establish itself on a lease it still remembers, which is the same defect
10
+ * the barrier exists to prevent.
11
+ */
12
+ export interface RunLease {
13
+ readonly holder: string;
14
+ readonly epoch: number;
15
+ readonly fencingToken: number;
16
+ /**
17
+ * The takeover id this driver's journal credential was minted for.
18
+ *
19
+ * It names the replay consumer, and a consumer name is one subject token, so it cannot be covered
20
+ * by a grant pattern — it has to be known when the rows are minted. That is when the lease is
21
+ * handed out, which is why it arrives with the lease rather than being chosen here.
22
+ */
23
+ readonly takeoverId: string;
24
+ }
25
+ /**
26
+ * A pause an operator can ask for while a run is being driven.
27
+ *
28
+ * The driver reads it before each effect it has not already recorded, so a pause takes effect at the
29
+ * next boundary and never in the middle of one. It is one-way on purpose: resuming is starting a
30
+ * drive again, which is the same act as any other takeover and goes through the barrier like one.
31
+ */
32
+ export declare class PauseToken {
33
+ private why;
34
+ pause(reason: string): void;
35
+ get reason(): string | undefined;
36
+ }
37
+ export interface DriveRequest {
38
+ readonly space: string;
39
+ /**
40
+ * The endpoint HOSTING this driver — the manager daemon. It leads the run record's
41
+ * key, so a retirement drain and a per-endpoint enumeration both work by prefix.
42
+ */
43
+ readonly endpoint: string;
44
+ readonly runId: string;
45
+ /** The program. A resume MUST be handed the same source: a different one is a fork, not a resume. */
46
+ readonly source: string;
47
+ readonly lease: RunLease;
48
+ readonly handler: EffectHandler;
49
+ /**
50
+ * The records bucket. NOT optional, and deliberately so: the run record holds the pins a resume
51
+ * must read back and the high-water ordinal that is the only thing able to see a truncated
52
+ * journal tail. A driver that could run without it would skip both silently, which is the failure
53
+ * mode both exist to prevent.
54
+ */
55
+ readonly kv: KV;
56
+ readonly seed?: string;
57
+ readonly file?: string;
58
+ readonly effectCeiling?: number;
59
+ readonly stepBudget?: number;
60
+ /**
61
+ * The ABSOLUTE work horizon this driver accepted the item under (`WorkLease.workExpiry`).
62
+ *
63
+ * Past it the pool has already reconciled the item, so a driver still appending is writing into a
64
+ * run the authority considers finished with. Nothing needs to be read to know this: the horizon is
65
+ * fixed at acceptance and never re-set (SPEC 13.8), which is exactly what makes it safe to check
66
+ * locally — unlike a lease deadline, whose current value is a fact on another machine and whose
67
+ * check would be a read-then-publish with a gap that cannot be closed.
68
+ */
69
+ readonly workExpiry?: number;
70
+ /** An operator's pause, honoured at the next effect boundary. */
71
+ readonly pause?: PauseToken;
72
+ /**
73
+ * Repair external state bound to the PREVIOUS holder, once this driver holds the run and before
74
+ * the program is resumed.
75
+ *
76
+ * The case that exists is timers: a checkpoint's armed schedule fires onto a subject derived from
77
+ * the instance and epoch that armed it, so a run adopted by another host has live timers firing
78
+ * where nobody is listening, and resuming the program does not repair that — the pause replays as
79
+ * pending and goes straight back to waiting. What to re-arm is the mesh handler's business, not
80
+ * the driver's, so the driver only says WHEN: after the activation, because arming timers for a
81
+ * run this process turned out not to hold would point another driver's fires at this one.
82
+ *
83
+ * A failure here is a failure to take the run over, and is not swallowed: a driver that resumed a
84
+ * program whose pauses it could not re-arm would look like it was holding a run it cannot advance.
85
+ *
86
+ * OPTIONAL BECAUSE IT IS AN OVERRIDE, NOT BECAUSE THE REPAIR IS. A handler that knows how to
87
+ * repair its own external state says so with an `adopted` method, and the driver calls that when
88
+ * no callback is supplied — found by review, which noticed that this hook had NO caller anywhere
89
+ * in the tree, so every adopted run left its timers armed at the predecessor's coordinates. A
90
+ * seam that every future host must remember to wire is a defect waiting on its first host.
91
+ */
92
+ readonly onActivated?: (entries: readonly JournalEntry[]) => Promise<void>;
93
+ }
94
+ /**
95
+ * A handler that owns external state bound to whoever was holding the run, and can repair it.
96
+ *
97
+ * Declared here rather than on `EffectHandler` because it is the DRIVER's concern: the language's
98
+ * handler interface describes performing effects, and nothing in `packages/lang` has a notion of one
99
+ * host taking a run over from another.
100
+ */
101
+ export interface AdoptingHandler {
102
+ adopted(entries: readonly JournalEntry[]): Promise<unknown>;
103
+ }
104
+ /**
105
+ * What a drive attempt did, as a two-exit answer rather than a value plus exceptions.
106
+ *
107
+ * `completed` is the program finishing under this driver. `released` is this driver ceasing to hold
108
+ * the run — superseded, stalled, retired — which says nothing about the program and must never be
109
+ * recorded as if it did. A program that FAILS is still `completed`: the failure is the run's result,
110
+ * and the journal has it.
111
+ */
112
+ export type DriveOutcome = {
113
+ readonly status: "completed";
114
+ readonly result: RunResult;
115
+ } | {
116
+ readonly status: "released";
117
+ readonly reason: Error;
118
+ };
119
+ /** Start a run that has never been driven. Refused if the journal already has records. */
120
+ export declare function startRun(js: JetStreamClient, jsm: JetStreamManager, req: DriveRequest): Promise<DriveOutcome>;
121
+ /** Take over a run that already exists and drive it to quiescence. Refused if its journal is empty:
122
+ * a run whose records were purged is retired, and re-running it would repeat what it already did. */
123
+ export declare function driveRun(js: JetStreamClient, jsm: JetStreamManager, req: DriveRequest): Promise<DriveOutcome>;
124
+ //# sourceMappingURL=run-driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-driver.d.ts","sourceRoot":"","sources":["../src/run-driver.ts"],"names":[],"mappings":"AA0CA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EASL,KAAK,aAAa,EAClB,KAAK,YAAY,EAEjB,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAC;AAGxB;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;;;;OAMG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAqB;IAEhC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI3B,IAAI,MAAM,IAAI,MAAM,GAAG,SAAS,CAE/B;CACF;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,qGAAqG;IACrG,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,EAAE,EAAE,CAAC;IAChB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,iEAAiE;IACjE,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC5B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5E;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7D;AAOD;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GACpB;IAAE,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAA;CAAE,CAAC;AAE5D,0FAA0F;AAC1F,wBAAsB,QAAQ,CAC5B,EAAE,EAAE,eAAe,EACnB,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,YAAY,CAAC,CAEvB;AAED;sGACsG;AACtG,wBAAsB,QAAQ,CAC5B,EAAE,EAAE,eAAe,EACnB,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,YAAY,CAAC,CAEvB"}
@@ -0,0 +1,228 @@
1
+ /**
2
+ * The run driver: what actually advances a workflow run, and the only thing allowed to.
3
+ *
4
+ * A driver is not a scheduler and not a supervisor. Its whole job is to be the ONE process holding a
5
+ * run, to hand the interpreter a journal that is durable and complete, and to stop the moment it is
6
+ * no longer that process. Everything hard about the first and third parts lives in the activation
7
+ * barrier (`@cotal-ai/core`); everything hard about the middle lives in the language. This file is
8
+ * the join, and it is deliberately small — a driver with its own opinions about durability would be
9
+ * a second answer to a question that already has one.
10
+ *
11
+ * **Start and resume are the same act with one bit of difference**, and the bit is not cosmetic. A
12
+ * run's journal cannot say whether an empty subject means "never started" or "retired by purge", so
13
+ * the caller states which it means: `startRun` activates with `expect: "new"` and `driveRun` with
14
+ * `expect: "existing"`, and the barrier refuses the mismatch either way. That is why there are two
15
+ * entry points rather than one that guesses from what it finds.
16
+ *
17
+ * **The prefix the barrier replayed IS the journal the interpreter resumes from.** Not a copy of it,
18
+ * not a second read: the appender hands back exactly the records it validated as complete before it
19
+ * activated, so there is no window in which the driver could resume from a different prefix than the
20
+ * one it took the run over on.
21
+ *
22
+ * **A durability failure is not a run failure.** If the journal refuses an append — superseded,
23
+ * stalled, retired — the run is not "failed", it is no longer THIS process's to speak for. The
24
+ * distinction is the whole reason `RunJournalStore` maps those to L5010: a driver that reported them
25
+ * as an outcome would be writing down a conclusion about work it can no longer see.
26
+ */
27
+ import { activateRun, readRunRecord, createRunSpec, writeRunStatus, assertJournalTailIntact, RunJournalTailTruncated, RunSuperseded, RunJournalStalled, StaleLeaseToken, ActivationNotAuthorized, RunNotResumable, RunAlreadyStarted, RunJournalPrefixTruncated, } from "@cotal-ai/core";
28
+ import { Journal, JournalAppendRejected, run as runProgram, resume as resumeProgram, RunReleased, resolvePins, LANGUAGE_VERSION, PIN_DEFAULTS, } from "@cotal-ai/lang";
29
+ import { RunJournalStore } from "./journal-store.js";
30
+ /**
31
+ * A pause an operator can ask for while a run is being driven.
32
+ *
33
+ * The driver reads it before each effect it has not already recorded, so a pause takes effect at the
34
+ * next boundary and never in the middle of one. It is one-way on purpose: resuming is starting a
35
+ * drive again, which is the same act as any other takeover and goes through the barrier like one.
36
+ */
37
+ export class PauseToken {
38
+ why;
39
+ pause(reason) {
40
+ this.why ??= reason;
41
+ }
42
+ get reason() {
43
+ return this.why;
44
+ }
45
+ }
46
+ const adoptionOf = (handler) => typeof handler?.adopted === "function"
47
+ ? handler
48
+ : undefined;
49
+ /** Start a run that has never been driven. Refused if the journal already has records. */
50
+ export async function startRun(js, jsm, req) {
51
+ return await drive(js, jsm, req, "new");
52
+ }
53
+ /** Take over a run that already exists and drive it to quiescence. Refused if its journal is empty:
54
+ * a run whose records were purged is retired, and re-running it would repeat what it already did. */
55
+ export async function driveRun(js, jsm, req) {
56
+ return await drive(js, jsm, req, "existing");
57
+ }
58
+ async function drive(js, jsm, req, expect) {
59
+ // The record FIRST, because two of the things it holds decide whether this attempt may proceed at
60
+ // all: the pins the run was started under, and how far its journal is known to have got.
61
+ const record = await readRunRecord(req.kv, req.endpoint, req.runId);
62
+ const recordedStatus = record?.status?.value;
63
+ let pins;
64
+ let statusRevision;
65
+ if (expect === "new") {
66
+ if (record !== undefined) {
67
+ // Not `RunAlreadyStarted` from the journal — this run has a SPEC, which is the stronger
68
+ // statement: it was started, pinned, and those pins are not this attempt's to re-decide.
69
+ return { status: "released", reason: new RunAlreadyStarted(req.runId, 0) };
70
+ }
71
+ // Resolved ONCE, here, from the host clock read exactly once — from here on the epoch is a
72
+ // recorded fact, and a second read could not be the same run's epoch.
73
+ pins = resolvePins({
74
+ runId: req.runId,
75
+ ...(req.seed !== undefined ? { seed: req.seed } : {}),
76
+ ...(req.effectCeiling !== undefined ? { effectCeiling: req.effectCeiling } : {}),
77
+ ...(req.stepBudget !== undefined ? { stepBudget: req.stepBudget } : {}),
78
+ }, req.handler.now());
79
+ }
80
+ else {
81
+ if (record === undefined)
82
+ return { status: "released", reason: new RunNotResumable(req.runId, req.runId) };
83
+ // READ BACK, never re-derived. A default is a property of the interpreter, and the interpreter
84
+ // is the thing that may have changed between attempts.
85
+ pins = record.spec.value.pins;
86
+ statusRevision = record.status?.revision;
87
+ }
88
+ let appender;
89
+ try {
90
+ appender = await activateRun(js, jsm, {
91
+ space: req.space,
92
+ runId: req.runId,
93
+ holder: req.lease.holder,
94
+ fencingToken: req.lease.fencingToken,
95
+ epoch: req.lease.epoch,
96
+ takeoverId: req.lease.takeoverId,
97
+ at: req.handler.now(),
98
+ expect,
99
+ }, {
100
+ // BETWEEN the replay and the activation, which is the only place this check is worth
101
+ // anything: an activation appended over a rolled-back head is another record written into a
102
+ // journal already known to be wrong, at an ordinal the deleted records already used.
103
+ onReplayed: (replay) => {
104
+ assertJournalTailIntact(req.runId, recordedStatus, lastOrdinal(replay.records));
105
+ },
106
+ });
107
+ }
108
+ catch (e) {
109
+ // Every one of these means "this driver does not hold this run", and none of them is a fact
110
+ // about the program. A caller that treated them as a run result would be recording a conclusion
111
+ // about work it never saw.
112
+ if (isNotOurs(e))
113
+ return { status: "released", reason: e };
114
+ throw e;
115
+ }
116
+ const resumed = appender.steps();
117
+ // The explicit callback wins; otherwise a handler that declares `adopted` repairs its own state.
118
+ // The default is the point: the hook was optional AND unwired, which is indistinguishable at
119
+ // runtime from a driver that has nothing to repair.
120
+ const adopt = req.onActivated ?? adoptionOf(req.handler)?.adopted.bind(req.handler);
121
+ if (adopt !== undefined)
122
+ await adopt(resumed);
123
+ const store = new RunJournalStore(appender);
124
+ const journal = new Journal({
125
+ run: req.runId,
126
+ // The prefix the barrier validated and activated on, not a second read of the subject.
127
+ entries: resumed,
128
+ store,
129
+ });
130
+ // Asked before every effect that is not already recorded. Both reasons are the HOST's and neither
131
+ // is the program's, so neither may be recorded as its outcome — the run stops where its journal
132
+ // already says it is, and the next driver resumes from there.
133
+ const shouldStop = () => {
134
+ if (req.workExpiry !== undefined) {
135
+ const now = req.handler.now();
136
+ if (now >= req.workExpiry)
137
+ return `the work horizon ${req.workExpiry} passed at ${now}`;
138
+ }
139
+ return req.pause?.reason;
140
+ };
141
+ const options = {
142
+ runId: req.runId,
143
+ handler: req.handler,
144
+ shouldStop,
145
+ pins,
146
+ ...(req.seed !== undefined ? { seed: req.seed } : {}),
147
+ ...(req.file !== undefined ? { file: req.file } : {}),
148
+ ...(req.effectCeiling !== undefined ? { effectCeiling: req.effectCeiling } : {}),
149
+ ...(req.stepBudget !== undefined ? { stepBudget: req.stepBudget } : {}),
150
+ };
151
+ // The spec is created AFTER the activation, not before: until this driver holds the run it has
152
+ // decided nothing, and a spec written by a driver that then lost the activation race would pin a
153
+ // run for a winner who never agreed to those pins.
154
+ if (expect === "new") {
155
+ await createRunSpec(req.kv, req.endpoint, req.runId, {
156
+ pins,
157
+ createdAt: pins.startedAt,
158
+ });
159
+ }
160
+ const specRevision = expect === "new"
161
+ ? (await readRunRecord(req.kv, req.endpoint, req.runId)).spec.revision
162
+ : record.spec.revision;
163
+ statusRevision = await note(req, "running", appender.journalHigh, specRevision, statusRevision);
164
+ try {
165
+ const result = expect === "new"
166
+ ? await runProgram(req.source, { ...options, journal })
167
+ : await resumeProgram(req.source, journal, options);
168
+ await note(req, "completed", appender.journalHigh, specRevision, statusRevision);
169
+ return { status: "completed", result };
170
+ }
171
+ catch (e) {
172
+ // L5010 is the journal saying it could not record — the run is not this driver's any more. It
173
+ // arrives here rather than at the append because the interpreter is what was holding the stack.
174
+ if (e instanceof JournalAppendRejected) {
175
+ // Recorded on a BEST-EFFORT basis and never allowed to mask the real answer: the record is a
176
+ // projection, and a driver that could not append to the journal may not be able to write here
177
+ // either. What it must not do is turn a lost run into a different-looking failure.
178
+ await noteQuietly(req, "released", appender.journalHigh, specRevision, statusRevision);
179
+ return { status: "released", reason: e };
180
+ }
181
+ // The host stopping is the same kind of answer: this driver no longer holds the run, and the
182
+ // program has neither failed nor finished.
183
+ if (e instanceof RunReleased) {
184
+ await note(req, "released", appender.journalHigh, specRevision, statusRevision);
185
+ return { status: "released", reason: e };
186
+ }
187
+ // A program that FAILED is a fact about the program, and the run record is where a reader looks
188
+ // for it. Recorded, then re-raised: swallowing it here would leave the caller believing the
189
+ // driver finished normally.
190
+ await note(req, "failed", appender.journalHigh, specRevision, statusRevision);
191
+ throw e;
192
+ }
193
+ }
194
+ function isNotOurs(e) {
195
+ return (e instanceof RunSuperseded ||
196
+ e instanceof RunJournalStalled ||
197
+ e instanceof StaleLeaseToken ||
198
+ e instanceof ActivationNotAuthorized ||
199
+ e instanceof RunNotResumable ||
200
+ e instanceof RunAlreadyStarted ||
201
+ e instanceof RunJournalPrefixTruncated);
202
+ }
203
+ /** The last ordinal in a replayed prefix, or -1 for a run that has none yet. */
204
+ function lastOrdinal(records) {
205
+ return records.length === 0 ? -1 : records[records.length - 1].record.n;
206
+ }
207
+ /** Write the run's status. Returns the new revision so the next write can pin it. */
208
+ async function note(req, state, journalHigh, observedSpecRevision, expectedRevision) {
209
+ return await writeRunStatus(req.kv, req.endpoint, req.runId, {
210
+ observedSpecRevision,
211
+ state,
212
+ holder: req.lease.holder,
213
+ epoch: req.lease.epoch,
214
+ fencingToken: req.lease.fencingToken,
215
+ journalHigh,
216
+ at: req.handler.now(),
217
+ }, expectedRevision);
218
+ }
219
+ /** The same write, where failing to make it must not replace the answer the caller is owed. */
220
+ async function noteQuietly(req, state, journalHigh, observedSpecRevision, expectedRevision) {
221
+ try {
222
+ await note(req, state, journalHigh, observedSpecRevision, expectedRevision);
223
+ }
224
+ catch {
225
+ /* the record is a projection; the journal is the authority and it has already spoken */
226
+ }
227
+ }
228
+ //# sourceMappingURL=run-driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-driver.js","sourceRoot":"","sources":["../src/run-driver.ts"],"names":[],"mappings":"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"}