@cotal-ai/lang 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 (101) hide show
  1. package/README.md +68 -0
  2. package/dist/effects.d.ts +19 -0
  3. package/dist/effects.d.ts.map +1 -1
  4. package/dist/effects.js +23 -0
  5. package/dist/effects.js.map +1 -1
  6. package/dist/engine/bridge.d.ts +71 -0
  7. package/dist/engine/bridge.d.ts.map +1 -0
  8. package/dist/engine/bridge.js +277 -0
  9. package/dist/engine/bridge.js.map +1 -0
  10. package/dist/engine/ctx.d.ts +140 -0
  11. package/dist/engine/ctx.d.ts.map +1 -0
  12. package/dist/engine/ctx.js +834 -0
  13. package/dist/engine/ctx.js.map +1 -0
  14. package/dist/engine/frame.d.ts +69 -0
  15. package/dist/engine/frame.d.ts.map +1 -0
  16. package/dist/engine/frame.js +105 -0
  17. package/dist/engine/frame.js.map +1 -0
  18. package/dist/engine/host.d.ts +77 -0
  19. package/dist/engine/host.d.ts.map +1 -0
  20. package/dist/engine/host.js +134 -0
  21. package/dist/engine/host.js.map +1 -0
  22. package/dist/engine/worker-entry.d.ts +26 -0
  23. package/dist/engine/worker-entry.d.ts.map +1 -0
  24. package/dist/engine/worker-entry.js +175 -0
  25. package/dist/engine/worker-entry.js.map +1 -0
  26. package/dist/engine/worker.d.ts +156 -0
  27. package/dist/engine/worker.d.ts.map +1 -0
  28. package/dist/engine/worker.js +123 -0
  29. package/dist/engine/worker.js.map +1 -0
  30. package/dist/errors.d.ts +92 -2
  31. package/dist/errors.d.ts.map +1 -1
  32. package/dist/errors.js +187 -2
  33. package/dist/errors.js.map +1 -1
  34. package/dist/grammar.d.ts.map +1 -1
  35. package/dist/grammar.js +561 -128
  36. package/dist/grammar.js.map +1 -1
  37. package/dist/index.d.ts +19 -6
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +19 -6
  40. package/dist/index.js.map +1 -1
  41. package/dist/interpret.d.ts +59 -12
  42. package/dist/interpret.d.ts.map +1 -1
  43. package/dist/interpret.js +831 -613
  44. package/dist/interpret.js.map +1 -1
  45. package/dist/journal.d.ts +218 -9
  46. package/dist/journal.d.ts.map +1 -1
  47. package/dist/journal.js +306 -12
  48. package/dist/journal.js.map +1 -1
  49. package/dist/keys.d.ts +39 -1
  50. package/dist/keys.d.ts.map +1 -1
  51. package/dist/keys.js +61 -0
  52. package/dist/keys.js.map +1 -1
  53. package/dist/library.d.ts +65 -0
  54. package/dist/library.d.ts.map +1 -0
  55. package/dist/library.js +537 -0
  56. package/dist/library.js.map +1 -0
  57. package/dist/notify-fact.d.ts +8 -0
  58. package/dist/notify-fact.d.ts.map +1 -0
  59. package/dist/notify-fact.js +69 -0
  60. package/dist/notify-fact.js.map +1 -0
  61. package/dist/perform.d.ts +138 -0
  62. package/dist/perform.d.ts.map +1 -0
  63. package/dist/perform.js +1052 -0
  64. package/dist/perform.js.map +1 -0
  65. package/dist/pins.d.ts +102 -0
  66. package/dist/pins.d.ts.map +1 -0
  67. package/dist/pins.js +107 -0
  68. package/dist/pins.js.map +1 -0
  69. package/dist/primitives.d.ts +14 -0
  70. package/dist/primitives.d.ts.map +1 -1
  71. package/dist/primitives.js +45 -5
  72. package/dist/primitives.js.map +1 -1
  73. package/dist/sim.d.ts +24 -2
  74. package/dist/sim.d.ts.map +1 -1
  75. package/dist/sim.js +9 -1
  76. package/dist/sim.js.map +1 -1
  77. package/dist/syntax.d.ts +34 -0
  78. package/dist/syntax.d.ts.map +1 -0
  79. package/dist/syntax.js +178 -0
  80. package/dist/syntax.js.map +1 -0
  81. package/dist/transform/emit.d.ts +23 -0
  82. package/dist/transform/emit.d.ts.map +1 -0
  83. package/dist/transform/emit.js +934 -0
  84. package/dist/transform/emit.js.map +1 -0
  85. package/dist/transform/index.d.ts +34 -0
  86. package/dist/transform/index.d.ts.map +1 -0
  87. package/dist/transform/index.js +31 -0
  88. package/dist/transform/index.js.map +1 -0
  89. package/dist/transform/scope.d.ts +58 -0
  90. package/dist/transform/scope.d.ts.map +1 -0
  91. package/dist/transform/scope.js +500 -0
  92. package/dist/transform/scope.js.map +1 -0
  93. package/dist/transform/seam.d.ts +78 -0
  94. package/dist/transform/seam.d.ts.map +1 -0
  95. package/dist/transform/seam.js +111 -0
  96. package/dist/transform/seam.js.map +1 -0
  97. package/dist/values.d.ts +35 -1
  98. package/dist/values.d.ts.map +1 -1
  99. package/dist/values.js +0 -0
  100. package/dist/values.js.map +1 -1
  101. package/package.json +9 -4
package/dist/journal.js CHANGED
@@ -11,29 +11,193 @@
11
11
  * found, so a changed input is a diagnosable divergence naming the step, rather than a silent
12
12
  * miss that quietly re-runs the effect and lets two versions of the truth coexist.
13
13
  */
14
+ import { NotCrossable, assertCrossable, assertScopeValueCrossable, deepFreeze } from "./values.js";
15
+ import { RuntimeFault } from "./errors.js";
14
16
  import { stepKeyString } from "./keys.js";
17
+ import { EFFECT_KINDS } from "./primitives.js";
18
+ /**
19
+ * A durable append the store REFUSED.
20
+ *
21
+ * This is not an effect failure, and conflating the two is not cosmetic. A handler that completed
22
+ * plus a log that would not accept the completion, recorded as one fact, is an entry saying the
23
+ * work FAILED: a later replay then reports failure for work the world actually did, which is the
24
+ * journal lying about the one thing it exists to remember. The domains are separate: "the world
25
+ * said no" is the run's result, "the log said no" is the run losing its ability to have one. A
26
+ * driver reads the second as
27
+ * "stop, and do not record anything else", never as an outcome.
28
+ *
29
+ * Nothing was written and nothing in memory moved, so a caller holding this error knows exactly as
30
+ * much as it did before the call.
31
+ */
32
+ export class JournalAppendRejected extends Error {
33
+ stepKey;
34
+ state;
35
+ reason;
36
+ code = "L5010";
37
+ /** True when the store could not tell whether the entry landed. See {@link IndeterminateAppend}. */
38
+ indeterminate;
39
+ constructor(stepKey, state, reason) {
40
+ const indeterminate = reason?.indeterminate === true;
41
+ super(`L5010 Journal append rejected\n\n step ${stepKey} ${state}\n\n${reason.message}\n\n${indeterminate
42
+ ? "Whether the entry was recorded is UNKNOWN — the store could not tell — and the in-memory journal was left as it was."
43
+ : "The entry was not recorded and the in-memory journal was left as it was."} This is a durability failure, not an effect failure: whatever the effect did, it stands, and this run can no longer say so.`);
44
+ this.stepKey = stepKey;
45
+ this.state = state;
46
+ this.reason = reason;
47
+ this.indeterminate = indeterminate;
48
+ this.name = "JournalAppendRejected";
49
+ }
50
+ }
15
51
  export class JournalReadOnlyError extends Error {
16
52
  constructor(key) {
17
53
  super(`journal is read-only; ${stepKeyString(key)} would have been appended`);
18
54
  this.name = "JournalReadOnlyError";
19
55
  }
20
56
  }
57
+ /**
58
+ * The step-key string an entry was written under, rebuilt from the entry itself.
59
+ *
60
+ * A recorded entry keeps the scope path as a STRING and its own `(kind, name, occurrence)` beside
61
+ * it, so the key it was filed under is recoverable — but only by re-applying the grammar that
62
+ * `stepKeyString` owns. That grammar lives in exactly one place and this is how anything outside
63
+ * the language addresses a recorded step: a caller that re-joined the parts by hand would be
64
+ * maintaining a second copy of a rule, and the first edit to the naming would silently address a
65
+ * different step rather than fail.
66
+ */
67
+ export function journalEntryKeyString(entry) {
68
+ const named = entry.name === "" ? entry.kind : `${entry.kind}:${entry.name}`;
69
+ return `${entry.scope}/${named}#${entry.occurrence}`;
70
+ }
71
+ /**
72
+ * WHY EACH FIELD MATTERS, said in its own words. One sentence for all three would have to be vague
73
+ * enough to fit the loosest, and the operator reading this is deciding whether to repair a store.
74
+ */
75
+ const WHAT_THE_FIELD_IS = {
76
+ external: "`external` is what a resume re-binds the handler's own record to",
77
+ "error.detail": "`error.detail` is how a failed step explains itself, and a resume hands it to the program that catches it",
78
+ result: "`result` is what a resume hands back INSTEAD of running the step again",
79
+ };
80
+ function bindingWithoutCanonicalForm(entry, field, cause) {
81
+ const step = `${entry.scope}/${entry.name === "" ? entry.kind : `${entry.kind}:${entry.name}`}#${entry.occurrence}`;
82
+ return new RuntimeFault("L5024", `A recorded value has no canonical form\n\n entry seq ${entry.seq} ${entry.kind} \`${field}\` UNREADABLE\n`
83
+ + ` step ${step}\n cause ${cause.message}\n\n`
84
+ + `${WHAT_THE_FIELD_IS[field]}, so a value the language cannot express is one `
85
+ + "this run would hand back to the program as if it had been recorded. The entry cannot be read, and reading it as "
86
+ + `anything else would invent a fact.\n\nOptions\n repair the entry at seq ${entry.seq} in the store, so its `
87
+ + `\`${field}\` is a value an effect boundary can carry\n fork(run, "${step}") start again from before this step`);
88
+ }
89
+ /** The entry kinds whose `result` is an assembly of branches rather than one handler's value. */
90
+ const SCOPE_KINDS = new Set(["parallel", "race", "fanOut", "conclave"]);
91
+ /** What the crossing rule calls the value it is refusing, so its path reads as the record's own. */
92
+ const LABEL_OF = {
93
+ external: "the recorded binding",
94
+ "error.detail": "the recorded failure detail",
95
+ result: "the recorded result",
96
+ };
21
97
  export class Journal {
22
98
  run;
23
99
  readOnly;
100
+ store;
24
101
  byKey = new Map();
25
102
  order = [];
103
+ /**
104
+ * Append order, allocated where the entry is BUILT rather than read off `order.length`.
105
+ *
106
+ * `begin` awaits a durable append before the key joins `order`, so two concurrent branches — which
107
+ * is the normal shape, not an edge case — both read the same length and both claimed the same
108
+ * `seq`. Rendering then showed two "first" steps, and any tooling ordering by it saw a tie it had
109
+ * no way to break. A counter is allocated synchronously, so the two branches cannot observe the
110
+ * same value however their awaits interleave.
111
+ */
112
+ nextSeq = 0;
26
113
  /** Every key the current replay has looked up. What is left over is an orphan. */
27
114
  consumed = new Set();
28
115
  constructor(init) {
29
116
  this.run = init.run;
30
117
  this.readOnly = init.readOnly === true;
118
+ if (init.store !== undefined)
119
+ this.store = init.store;
31
120
  for (const e of init.entries ?? []) {
121
+ // A journal is ONE run's. Seeding it with another run's entry would make this run resume
122
+ // against a history it never had — the keys are structural, so a foreign entry with the same
123
+ // scope and name matches, and its recorded result is returned as if this run had produced it.
124
+ if (e.run !== this.run)
125
+ throw new Error(`journal for run ${this.run} was seeded with an entry from run ${e.run}; a run resumes only from its own journal`);
32
126
  // The stored `scope` string is authoritative: it is what makes a journal readable back
33
127
  // without re-running the program that produced it.
128
+ // THE BINDING IS THE FIELD WITH NO WRITE-SIDE HISTORY. `result` crossed `assertCrossable` when
129
+ // it settled and the arguments crossed it when they dispatched; `external` reached the record
130
+ // through {@link Journal.bind} with nothing between it and the store until the guards in
131
+ // `performEffect` and `performScope`. Those fence every shipped caller, exactly two of them,
132
+ // both in perform.ts, but they fence it by ENUMERATION, and a record already written is behind
133
+ // them either way. This door is the one a loaded journal cannot go around.
134
+ // TWO FIELDS, ONE RULE. `external` is what a resume re-binds to; `error.detail` is what a
135
+ // failed step reports itself with. Both are values a handler chose and both reached the record
136
+ // with no domain check until the guards in `performEffect` and `performScope`. `detail` is the
137
+ // second one and it is not hypothetical: a program that CATCHES an effect failure succeeds,
138
+ // so a run can complete with an unreadable value sitting in a settled entry. Measured, and
139
+ // through the worker that run dies on a structured-clone error naming a host algorithm.
140
+ for (const [field, value] of [["external", e.external], ["error.detail", e.error?.detail]]) {
141
+ if (value === undefined)
142
+ continue;
143
+ try {
144
+ assertCrossable(value, LABEL_OF[field]);
145
+ }
146
+ catch (cause) {
147
+ if (!(cause instanceof NotCrossable))
148
+ throw cause;
149
+ throw bindingWithoutCanonicalForm(e, field, cause);
150
+ }
151
+ }
152
+ // `result` IS THE THIRD FIELD, AND IT IS NOT READ LIKE THE OTHER TWO. An effect's result is
153
+ // the handler's own value and answers to the rule whole. A SCOPE's result is the
154
+ // interpreter's assembly `{ branches, value }`, and its branch positions may legitimately be
155
+ // absent, so it answers to the same absence-exempt rule its write fence uses. `branches` is a
156
+ // list of branch NAMES (strings) and needs no exemption.
157
+ if (e.result !== undefined) {
158
+ try {
159
+ if (SCOPE_KINDS.has(e.kind)) {
160
+ const assembled = e.result;
161
+ if (assembled.branches !== undefined)
162
+ assertCrossable(assembled.branches, "the recorded branch list");
163
+ assertScopeValueCrossable(assembled.value, "the recorded result.value", e.kind);
164
+ }
165
+ else {
166
+ assertCrossable(e.result, LABEL_OF.result);
167
+ }
168
+ }
169
+ catch (cause) {
170
+ if (!(cause instanceof NotCrossable))
171
+ throw cause;
172
+ throw bindingWithoutCanonicalForm(e, "result", cause);
173
+ }
174
+ }
34
175
  const full = `${e.scope}/${e.name === "" ? e.kind : `${e.kind}:${e.name}`}#${e.occurrence}`;
35
- this.byKey.set(full, e);
36
- this.order.push(full);
176
+ // FROZEN ON THE WAY IN, because replay returns `entry.result` to the program as a value that
177
+ // already crossed an effect boundary. The LIVE path freezes the result before it settles, but
178
+ // a journal read back from a durable store is fresh deserialized data — measured before this
179
+ // line: a program mutated a replayed spawn handle, and pushed into a replayed scope result,
180
+ // with no L2031, on exactly the values whose recorded form is the one thing a resume trusts.
181
+ // The journal never mutates an entry in place (every transition builds a new record), so
182
+ // freezing the seed changes nothing else.
183
+ this.byKey.set(full, deepFreeze(e));
184
+ // FOLD THE LOG. A seed is an APPEND LOG, not a keyed view: the stream carries the pending
185
+ // record and the settled one as two records (`journal-store.smoke`: "settling appends a second
186
+ // record rather than editing the first"), `RunJournalAppender.steps()` replays both, and the
187
+ // driver seeds a journal straight from that. `byKey` already folds — last write wins, which is
188
+ // the settled row — so pushing the key again put the SAME entry in `order` twice and left the
189
+ // journal's two views disagreeing: the ceiling counted one step and `entries()` reported two,
190
+ // both resolving through `byKey`, so the pending row came back as a second copy of the settled
191
+ // one. `orphans()` reads `order`, so an unconsumed step reached the migrate table twice — one
192
+ // decision presented to an operator as two, about a step that happened once.
193
+ //
194
+ // FIRST occurrence, not last: `order` is the order the run PERFORMED its steps in, and a step
195
+ // begins when its pending row is written. Re-pushing on settle would reorder history by
196
+ // completion, which is a different sequence and not the one a reader is looking for.
197
+ if (!this.order.includes(full))
198
+ this.order.push(full);
199
+ if (e.seq >= this.nextSeq)
200
+ this.nextSeq = e.seq + 1;
37
201
  }
38
202
  }
39
203
  static keyOf(key) {
@@ -65,14 +229,41 @@ export class Journal {
65
229
  return { verdict: "replay-cancelled", entry };
66
230
  return { verdict: "replay", entry };
67
231
  }
68
- /** Append the `pending` half: the effect is about to be performed. */
69
- begin(key, inputHash, startedAt, requestId) {
232
+ /**
233
+ * Durably record one entry, BEFORE the in-memory map is allowed to hold it.
234
+ *
235
+ * The order is the whole point. Mutating first leaves a volatile transition behind when the store
236
+ * refuses: a `begin` whose append was rejected still reads as `pending`, and a `settle` whose
237
+ * append was rejected still reads as settled, so the in-memory journal claims a durability the
238
+ * store explicitly declined to provide. Persisting first means a rejected append changes nothing
239
+ * at all, which is the only state a caller can reason about.
240
+ *
241
+ * With no store there is nothing to refuse: `persist` returns, the map is updated, and nothing is
242
+ * awaited that could fail.
243
+ */
244
+ async persist(k, entry) {
245
+ if (this.store === undefined)
246
+ return;
247
+ try {
248
+ await this.store.append(entry);
249
+ }
250
+ catch (e) {
251
+ throw new JournalAppendRejected(k, entry.state, e);
252
+ }
253
+ }
254
+ /**
255
+ * Append the `pending` half: the effect is about to be performed.
256
+ *
257
+ * AWAIT THIS BEFORE DISPATCHING. The entry carries the request id the handler will submit under,
258
+ * and an identity that is not durable when the work is issued names nothing a resume can find.
259
+ */
260
+ async begin(key, inputHash, startedAt, requestId) {
70
261
  if (this.readOnly)
71
262
  throw new JournalReadOnlyError(key);
72
263
  const k = Journal.keyOf(key);
73
264
  const entry = {
74
265
  v: 1,
75
- seq: this.order.length,
266
+ seq: this.nextSeq++,
76
267
  run: this.run,
77
268
  scope: k.slice(0, k.lastIndexOf("/")),
78
269
  kind: key.kind,
@@ -83,6 +274,7 @@ export class Journal {
83
274
  state: "pending",
84
275
  startedAt,
85
276
  };
277
+ await this.persist(k, entry);
86
278
  this.byKey.set(k, entry);
87
279
  this.order.push(k);
88
280
  this.consumed.add(k);
@@ -100,26 +292,38 @@ export class Journal {
100
292
  * The INDEX moves with the id, and it is the half that recovery reads: an id says what to submit
101
293
  * under, the index says how much of the chain is already spent.
102
294
  */
103
- reissueAs(key, requestId, attempt) {
295
+ async reissueAs(key, requestId, attempt) {
104
296
  if (this.readOnly)
105
297
  throw new JournalReadOnlyError(key);
106
298
  const k = Journal.keyOf(key);
107
299
  const entry = this.byKey.get(k);
108
300
  if (entry === undefined)
109
301
  throw new Error(`reissueAs before begin for ${k}`);
110
- this.byKey.set(k, { ...entry, requestId, attempt });
302
+ const next = { ...entry, requestId, attempt };
303
+ await this.persist(k, next);
304
+ this.byKey.set(k, next);
111
305
  }
112
- bind(key, external) {
306
+ async bind(key, external) {
113
307
  if (this.readOnly)
114
308
  throw new JournalReadOnlyError(key);
115
309
  const k = Journal.keyOf(key);
116
310
  const entry = this.byKey.get(k);
117
311
  if (entry === undefined)
118
312
  throw new Error(`bind before begin for ${k}`);
119
- this.byKey.set(k, { ...entry, external });
313
+ const next = { ...entry, external };
314
+ await this.persist(k, next);
315
+ this.byKey.set(k, next);
120
316
  }
121
- /** Append the `settled` half. */
122
- settle(key, outcome, endedAt) {
317
+ /**
318
+ * Append the `settled` half.
319
+ *
320
+ * `facts.cancel` is for a scope that cancels siblings: the intent is recorded WITH the outcome
321
+ * rather than after it, because a process dies between instructions and two appends are two
322
+ * network operations however few keywords separate them. `facts.closed` is a `conclave`'s
323
+ * membership disposition, for the same reason and with the same rule: it goes down with the
324
+ * outcome or not at all.
325
+ */
326
+ async settle(key, outcome, endedAt, facts = {}) {
123
327
  if (this.readOnly)
124
328
  throw new JournalReadOnlyError(key);
125
329
  const k = Journal.keyOf(key);
@@ -133,10 +337,58 @@ export class Journal {
133
337
  endedAt,
134
338
  ...(outcome.status === "ok" ? { result: outcome.result } : {}),
135
339
  ...(outcome.status === "failed" ? { error: outcome.error } : {}),
340
+ ...(facts.cancel !== undefined ? { cancel: facts.cancel } : {}),
341
+ ...(facts.closed !== undefined ? { closed: facts.closed } : {}),
342
+ ...(facts.branchDigest !== undefined ? { branchDigest: facts.branchDigest } : {}),
343
+ // Only where `result` is not carrying them, so the two can never disagree.
344
+ ...(outcome.status !== "ok" && facts.branches !== undefined ? { branches: facts.branches } : {}),
136
345
  };
346
+ await this.persist(k, settled);
137
347
  this.byKey.set(k, settled);
138
348
  return settled;
139
349
  }
350
+ /**
351
+ * Account for everything under a settled scope WITHOUT entering a branch.
352
+ *
353
+ * A settled scope is delivered from its own entry, so the branches are never walked — and an
354
+ * entry nothing walks is an orphan, which on a migration means "the edit removed this step". The
355
+ * branches were not removed; they were decided. So the subtree is marked consumed explicitly.
356
+ *
357
+ * A loser still sitting `pending` is settled `cancelled` in the same pass, because that is what
358
+ * it is: the scope resolved without it. Settling the record is NOT the cancellation — the world
359
+ * has to be told separately, which is what `cancel.issued` tracks — but leaving it pending would
360
+ * make a resumed run try to recover work the scope already decided to abandon.
361
+ */
362
+ async consumeScope(scopeKeyString, endedAt,
363
+ /**
364
+ * Restrict the accounting to these branch keys.
365
+ *
366
+ * A resume passes nothing and takes the whole subtree, which is correct because the program
367
+ * hash is unchanged and nothing under the scope can have been removed. A MIGRATION passes the
368
+ * losers alone: the branches it does not name are walked instead, so that an effect the edited
369
+ * source removed still shows up as an orphan rather than being accounted for by a scope that
370
+ * never entered it.
371
+ */
372
+ only) {
373
+ const prefix = `${scopeKeyString}/b:`;
374
+ const wanted = only === undefined ? undefined : new Set([...only].map((b) => `${prefix}${b}/`));
375
+ const touched = [];
376
+ for (const k of this.order) {
377
+ if (!k.startsWith(prefix))
378
+ continue;
379
+ if (wanted !== undefined && ![...wanted].some((w) => k.startsWith(w)))
380
+ continue;
381
+ this.consumed.add(k);
382
+ touched.push(k);
383
+ const entry = this.byKey.get(k);
384
+ if (entry === undefined || entry.state !== "pending")
385
+ continue;
386
+ const cancelled = { ...entry, state: "settled", status: "cancelled", endedAt };
387
+ await this.persist(k, cancelled);
388
+ this.byKey.set(k, cancelled);
389
+ }
390
+ return touched;
391
+ }
140
392
  /** Every entry, in append order. The journal is the prompt context for repair. */
141
393
  entries() {
142
394
  return this.order.map((k) => this.byKey.get(k)).filter((e) => e !== undefined);
@@ -155,6 +407,33 @@ export class Journal {
155
407
  .map((k) => this.byKey.get(k))
156
408
  .filter((e) => e !== undefined);
157
409
  }
410
+ /**
411
+ * How many EFFECTS this run has already dispatched, counted from what is recorded.
412
+ *
413
+ * The effect ceiling is a RUN bound (L4009, "Run effect ceiling reached") and the
414
+ * interpreter's counter is per-instance, so without this a run got a fresh allowance at every
415
+ * activation and a runaway loop that crashed periodically could never reach the ceiling. The
416
+ * journal is the only thing that survives an activation, and it already holds the answer.
417
+ *
418
+ * Distinct KEYS, not entries: a dispatch writes a pending entry and then a settled one under the
419
+ * same key, and the interpreter counts the dispatch once. A pending entry still counts — the
420
+ * effect was performed, which is exactly why it was written before the handler was called.
421
+ *
422
+ * `conclave` is excluded because the interpreter does not count it either: it dispatches
423
+ * `openConclave` from the scope walker rather than through `performEffect`, so counting it here
424
+ * would make a resumed run's tally disagree with a fresh one's. That asymmetry is a real gap in
425
+ * what the ceiling sees and it is reported separately; this method mirrors the counter rather
426
+ * than quietly repairing it, because a seed that does not match the thing it seeds is worse than
427
+ * the gap it would paper over.
428
+ */
429
+ dispatchedEffects() {
430
+ let n = 0;
431
+ for (const e of this.byKey.values()) {
432
+ if (e.kind !== "conclave" && EFFECT_KINDS.includes(e.kind))
433
+ n += 1;
434
+ }
435
+ return n;
436
+ }
158
437
  /** Start a fresh replay pass. */
159
438
  resetConsumed() {
160
439
  this.consumed.clear();
@@ -174,16 +453,31 @@ export class Journal {
174
453
  */
175
454
  export class RunClock {
176
455
  value;
456
+ listeners;
177
457
  constructor(startedAt) {
178
458
  this.value = startedAt;
179
459
  }
180
460
  now() {
181
461
  return this.value;
182
462
  }
463
+ /**
464
+ * Observe every forward move of THIS clock. A `race` subscribes to each arm's clock, because an
465
+ * in-flight effect that lands after the arm was cancelled advances the arm past the frontier,
466
+ * and the cut has to be re-decided on the fact rather than left where the settle put it. A fork
467
+ * does not inherit listeners: the subscriber asked about one branch, not its descendants — a
468
+ * nested branch's history reaches the arm's own clock at the join, which fires this then.
469
+ */
470
+ onAdvance(fn) {
471
+ (this.listeners ??= []).push(fn);
472
+ }
183
473
  /** Advance past an effect this branch awaited. Monotone: an out-of-order settle cannot rewind. */
184
474
  advance(endedAt) {
185
- if (endedAt > this.value)
475
+ if (endedAt > this.value) {
186
476
  this.value = endedAt;
477
+ if (this.listeners !== undefined)
478
+ for (const l of this.listeners)
479
+ l(this.value);
480
+ }
187
481
  }
188
482
  /** A branch inherits its parent's clock at the moment it forks. */
189
483
  fork() {
@@ -1 +1 @@
1
- {"version":3,"file":"journal.js","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"journal.js","sourceRoot":"","sources":["../src/journal.ts"],"names":[],"mappings":"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"}
package/dist/keys.d.ts CHANGED
@@ -16,6 +16,15 @@
16
16
  import type { EffectKind } from "./primitives.js";
17
17
  /** The concurrency combinators that open a scope. */
18
18
  export type ScopeKind = "parallel" | "race" | "fanOut" | "conclave";
19
+ /**
20
+ * What a journal entry can be keyed as: an effect, or a concurrency SCOPE.
21
+ *
22
+ * The scope kinds are here because a combinator writes an entry for itself, and without them that
23
+ * entry has no legal key and no legal kind — which is the state this package was in: scopes pushed
24
+ * a frame, allocated an occurrence, and journalled nothing, so a replayed `race` re-raced and could
25
+ * resolve a different arm with nothing recorded saying which one had won.
26
+ */
27
+ export type JournalKind = EffectKind | ScopeKind;
19
28
  export interface ScopeFrame {
20
29
  readonly kind: ScopeKind;
21
30
  /** The combinator's step name, or null when it was not named. */
@@ -27,7 +36,7 @@ export interface ScopeFrame {
27
36
  }
28
37
  export interface StepKey {
29
38
  readonly scope: readonly ScopeFrame[];
30
- readonly kind: EffectKind;
39
+ readonly kind: JournalKind;
31
40
  /** The literal step name, or "" when the effect was not named. */
32
41
  readonly name: string;
33
42
  readonly occurrence: number;
@@ -51,6 +60,27 @@ export declare const DIGEST_PREFIX: "sha256:";
51
60
  */
52
61
  export declare function requestId(runId: string, key: StepKey, inputHash: string, attempt?: number): string;
53
62
  export declare function digest(value: unknown): string;
63
+ /**
64
+ * A program's identity, as one function so there is only one answer.
65
+ *
66
+ * The interpreter pins a run to this and a migration records the source it moved TO, and those two
67
+ * must be the same hash of the same thing — a second copy of `digest({ source })` in another package
68
+ * is a different function's answer wearing this one's name the moment either side changes.
69
+ */
70
+ export declare function programHashOf(source: string): string;
71
+ /**
72
+ * The characters the key grammar reserves as STRUCTURE.
73
+ *
74
+ * `frameString` and `stepKeyString` below build a key by concatenation and escape nothing, so any
75
+ * of these appearing inside a name or a branch key forges a path segment: a single branch keyed
76
+ * `a/parallel:inner#0/b:b` prints exactly what a genuinely nested `a` → `inner` → `b` prints. The
77
+ * validator refuses them at the source rather than escaping them here, because escaping would
78
+ * change every key already written to a journal.
79
+ *
80
+ * It lives beside the grammar that reserves them: a key format that gains a delimiter and leaves
81
+ * this set behind gives a validator that guards the wrong characters and still passes its tests.
82
+ */
83
+ export declare const KEY_RESERVED_RE: RegExp;
54
84
  /** The canonical string form, used in the journal, the trace, and error messages. */
55
85
  export declare function scopePathString(scope: readonly ScopeFrame[]): string;
56
86
  export declare function stepKeyString(key: StepKey): string;
@@ -75,6 +105,14 @@ export declare class KeyScope {
75
105
  * per combinator call, then {@link branch} once per branch.
76
106
  */
77
107
  nextScope(kind: ScopeKind, name?: string | null): number;
108
+ /**
109
+ * The scope's OWN key, in the namespace that opened it.
110
+ *
111
+ * Allocation-free on purpose: {@link KeyScope.nextScope} already allocated the occurrence, and
112
+ * calling this must not consume a second one. The scope entry therefore sits beside the effects
113
+ * of the namespace that opened it (`/race:first-answer#0`), while its branches live under it.
114
+ */
115
+ scopeKey(kind: ScopeKind, name: string | null, occurrence: number): StepKey;
78
116
  /** The child namespace for one branch of a scope opened from here. */
79
117
  branch(kind: ScopeKind, name: string | null, occurrence: number, branchKey: string): KeyScope;
80
118
  }
@@ -1 +1 @@
1
- {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,qDAAqD;AACrD,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEpE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;gDACgD;AAChD,eAAO,MAAM,aAAa,EAAG,SAAkB,CAAC;AAEhD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,MAAM,CAI7F;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE7C;AAOD,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAEpE;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAGlD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAE7D;AAED;;;;;;;GAOG;AACH,qBAAa,QAAQ;IAIP,QAAQ,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE;IAHhD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAC1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;gBAEpC,IAAI,GAAE,SAAS,UAAU,EAAO;IAErD,uFAAuF;IACvF,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,SAAK,GAAG,OAAO;IAOhD;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,GAAE,MAAM,GAAG,IAAW,GAAG,MAAM;IAO9D,sEAAsE;IACtE,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ;CAG9F;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,EAAE,CAIrG"}
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAGlD,qDAAqD;AACrD,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEpE;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,SAAS,CAAC;AAEjD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,iEAAiE;IACjE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED;gDACgD;AAChD,eAAO,MAAM,aAAa,EAAG,SAAkB,CAAC;AAEhD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,MAAM,CAI7F;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE7C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,eAAe,QAAU,CAAC;AA0BvC,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAEpE;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAGlD;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CAE7D;AAED;;;;;;;GAOG;AACH,qBAAa,QAAQ;IAIP,QAAQ,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE;IAHhD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAC1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;gBAEpC,IAAI,GAAE,SAAS,UAAU,EAAO;IAErD,uFAAuF;IACvF,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,SAAK,GAAG,OAAO;IAchD;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,GAAE,MAAM,GAAG,IAAW,GAAG,MAAM;IAO9D;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO;IAI3E,sEAAsE;IACtE,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,QAAQ;CAO9F;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,EAAE,CAIrG"}
package/dist/keys.js CHANGED
@@ -15,6 +15,7 @@
15
15
  */
16
16
  import { createHash } from "node:crypto";
17
17
  import { canonicalize } from "json-canonicalize";
18
+ import { RuntimeFault } from "./errors.js";
18
19
  /** `sha256:<hex>` over the RFC 8785 canonical form, matching the digest discipline used for
19
20
  * contract artifacts elsewhere in the repo. */
20
21
  export const DIGEST_PREFIX = "sha256:";
@@ -40,6 +41,45 @@ export function requestId(runId, key, inputHash, attempt = 0) {
40
41
  export function digest(value) {
41
42
  return DIGEST_PREFIX + createHash("sha256").update(canonicalize(value), "utf8").digest("hex");
42
43
  }
44
+ /**
45
+ * A program's identity, as one function so there is only one answer.
46
+ *
47
+ * The interpreter pins a run to this and a migration records the source it moved TO, and those two
48
+ * must be the same hash of the same thing — a second copy of `digest({ source })` in another package
49
+ * is a different function's answer wearing this one's name the moment either side changes.
50
+ */
51
+ export function programHashOf(source) {
52
+ return digest({ source });
53
+ }
54
+ /**
55
+ * The characters the key grammar reserves as STRUCTURE.
56
+ *
57
+ * `frameString` and `stepKeyString` below build a key by concatenation and escape nothing, so any
58
+ * of these appearing inside a name or a branch key forges a path segment: a single branch keyed
59
+ * `a/parallel:inner#0/b:b` prints exactly what a genuinely nested `a` → `inner` → `b` prints. The
60
+ * validator refuses them at the source rather than escaping them here, because escaping would
61
+ * change every key already written to a journal.
62
+ *
63
+ * It lives beside the grammar that reserves them: a key format that gains a delimiter and leaves
64
+ * this set behind gives a validator that guards the wrong characters and still passes its tests.
65
+ */
66
+ export const KEY_RESERVED_RE = /[/#:]/;
67
+ /**
68
+ * Refuse a name or branch key that would forge structure, at the point the key is MINTED.
69
+ *
70
+ * The validator closes the static case, and it is the better place to close it — an author gets the
71
+ * refusal before the run starts. But it can only see a LITERAL. `fanOut(items, (i) => sleep("1m",
72
+ * { name: i }))` names each step after its item, which is idiomatic and is how a fan-out gets
73
+ * distinct keys at all, and those values are usually data from outside the program. **A forged key
74
+ * built from data is strictly easier to reach than one written in the source, and it is exactly the
75
+ * case static analysis cannot see.** So the guard exists in both places on purpose: this is not a
76
+ * belt on the validator's braces, it covers inputs the validator provably cannot.
77
+ */
78
+ function assertKeySafe(value, what) {
79
+ if (!KEY_RESERVED_RE.test(value))
80
+ return;
81
+ throw new RuntimeFault("L3025", `${what} is ${JSON.stringify(value)}, which contains a character the step-key grammar reserves (\`/\`, \`#\` or \`:\`). Keys are built by concatenation and nothing is escaped, so this value would forge a scope path that a genuinely nested scope also produces — and two locations sharing a key share a durable journal row, silently when their inputs match.`);
82
+ }
43
83
  function frameString(f) {
44
84
  const named = f.name === null ? f.kind : `${f.kind}:${f.name}`;
45
85
  return `/${named}#${f.occurrence}/b:${f.branch}`;
@@ -72,6 +112,13 @@ export class KeyScope {
72
112
  }
73
113
  /** Allocate the next occurrence for an effect in this namespace, and build its key. */
74
114
  nextEffect(kind, name = "") {
115
+ // The validator refuses a reserved character in a LITERAL name, but a name can be computed —
116
+ // `fanOut(items, (lens) => sleep("1m", { name: lens }))` is idiomatic and its name is only
117
+ // known here. A static check cannot see that value, so the refusal has to exist at the point
118
+ // where it does. Without this, a fan-out over items containing a `/` forges scope structure
119
+ // from data, which is the same collision the validator closes for the static case and is
120
+ // strictly easier to hit, because the items usually come from outside the program.
121
+ assertKeySafe(name, `the name of this \`${kind}\``);
75
122
  const tag = `${kind}:${name}`;
76
123
  const occurrence = this.effectCounts.get(tag) ?? 0;
77
124
  this.effectCounts.set(tag, occurrence + 1);
@@ -87,8 +134,22 @@ export class KeyScope {
87
134
  this.scopeCounts.set(tag, occurrence + 1);
88
135
  return occurrence;
89
136
  }
137
+ /**
138
+ * The scope's OWN key, in the namespace that opened it.
139
+ *
140
+ * Allocation-free on purpose: {@link KeyScope.nextScope} already allocated the occurrence, and
141
+ * calling this must not consume a second one. The scope entry therefore sits beside the effects
142
+ * of the namespace that opened it (`/race:first-answer#0`), while its branches live under it.
143
+ */
144
+ scopeKey(kind, name, occurrence) {
145
+ return { scope: this.path, kind, name: name ?? "", occurrence };
146
+ }
90
147
  /** The child namespace for one branch of a scope opened from here. */
91
148
  branch(kind, name, occurrence, branchKey) {
149
+ // The other half of the same hazard, and the one the review actually found. A `fanOut` keyed by
150
+ // a function over its items produces branch keys from DATA, so this is reachable without anyone
151
+ // writing a suspicious literal anywhere in the program.
152
+ assertKeySafe(branchKey, `the branch key of this \`${kind}\``);
92
153
  return new KeyScope([...this.path, { kind, name, occurrence, branch: branchKey }]);
93
154
  }
94
155
  }
package/dist/keys.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../src/keys.ts"],"names":[],"mappings":"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"}