@yielded/agent-storage-cloudflare 0.1.0-beta.173 → 0.1.0-beta.175

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 (44) hide show
  1. package/dist/DoMemoryStore.mjs +1 -1
  2. package/dist/DoMessageDeliveryStore.mjs +1 -1
  3. package/dist/DoStorageFailpoint.d.mts +3 -1
  4. package/dist/DoStorageFailpoint.mjs +7 -2
  5. package/dist/DoStorageFailpoint.mjs.map +1 -1
  6. package/dist/DoStorageFailpointTesting.mjs +1 -4
  7. package/dist/DoStorageFailpointTesting.mjs.map +1 -1
  8. package/dist/{DoStorageVersion-NKnQU3eR.d.mts → DoStorageVersion-Mc7CXMdN.d.mts} +2 -2
  9. package/dist/DoStorageVersion.d.mts +1 -1
  10. package/dist/DoStorageVersion.mjs +2 -2
  11. package/dist/DoSubmissionLedger.mjs +121 -67
  12. package/dist/DoSubmissionLedger.mjs.map +1 -1
  13. package/dist/DoSubscriptionStore.mjs.map +1 -1
  14. package/dist/{DoThreadStore-CtyahRTW.mjs → DoThreadStore-CgIZQUNR.mjs} +30 -25
  15. package/dist/DoThreadStore-CgIZQUNR.mjs.map +1 -0
  16. package/dist/DoThreadStore.mjs +1 -1
  17. package/dist/PortProtocol.d.mts +12 -0
  18. package/dist/PortRouting.mjs +6 -1
  19. package/dist/PortRouting.mjs.map +1 -1
  20. package/dist/{do-journal-_MdLGTd3.mjs → do-journal-7P3DUBz0.mjs} +140 -65
  21. package/dist/do-journal-7P3DUBz0.mjs.map +1 -0
  22. package/dist/index.d.mts +1 -1
  23. package/dist/index.mjs +1 -1
  24. package/dist/{migrations-C3N9GN6A.mjs → migrations-CAO_akhD.mjs} +45 -22
  25. package/dist/migrations-CAO_akhD.mjs.map +1 -0
  26. package/dist/{owned-state-BHzUi0eb.mjs → owned-state-B4QhezMp.mjs} +8 -6
  27. package/dist/owned-state-B4QhezMp.mjs.map +1 -0
  28. package/package.json +1 -1
  29. package/src/DoStorageFailpoint.ts +4 -0
  30. package/src/DoStorageFailpointTesting.ts +9 -7
  31. package/src/DoSubmissionLedger.ts +271 -150
  32. package/src/DoSubscriptionStore.ts +1 -0
  33. package/src/DoThreadStore.ts +27 -50
  34. package/src/PortRouting.ts +10 -2
  35. package/src/internal/canonical-append.ts +1 -1
  36. package/src/internal/do-journal.ts +987 -800
  37. package/src/internal/migrations.ts +53 -10
  38. package/src/internal/owned-state.ts +18 -7
  39. package/src/internal/prompt-checkpoint.ts +19 -13
  40. package/src/internal/storage-span.ts +22 -13
  41. package/dist/DoThreadStore-CtyahRTW.mjs.map +0 -1
  42. package/dist/do-journal-_MdLGTd3.mjs.map +0 -1
  43. package/dist/migrations-C3N9GN6A.mjs.map +0 -1
  44. package/dist/owned-state-BHzUi0eb.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { r as ownedState } from "./owned-state-BHzUi0eb.mjs";
2
+ import { r as ownedState } from "./owned-state-B4QhezMp.mjs";
3
3
  import { SqlMemoryLimits, SqlStorageOwner, memoryStoreLayerWithFailpoints } from "@yielded/agent/sql-memory-store";
4
4
  import { Effect, Layer, Schema } from "effect";
5
5
  import * as SqlClientService from "effect/sql/SqlClient";
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { DoStorageConfig } from "./DoStorageConfig.mjs";
3
3
  import { DoStorageFailpoint } from "./DoStorageFailpoint.mjs";
4
- import { i as initializeDoJournal } from "./do-journal-_MdLGTd3.mjs";
4
+ import { i as initializeDoJournal } from "./do-journal-7P3DUBz0.mjs";
5
5
  import { BrowserCrypto } from "@effect/platform-browser";
6
6
  import { SqlLifecycleSource } from "@yielded/agent-storage-sql/sql-lifecycle-publication";
7
7
  import { makeSqlMessageDeliveryStore } from "@yielded/agent-storage-sql/sql-message-delivery-store";
@@ -1,9 +1,11 @@
1
1
  import { c as DoStorageFailpointError, l as DoStorageFailpointLocation } from "./DoStorageError-CxjMnzUA.mjs";
2
2
  import { Context, Effect, Layer } from "effect";
3
3
  declare namespace DoStorageFailpoint_d_exports {
4
- export { DoStorageFailpoint, DoStorageFailpointHandler };
4
+ export { DoStorageFailpoint, DoStorageFailpointHandler, isDefaultDoStorageFailpoint };
5
5
  }
6
6
  export type DoStorageFailpointHandler = (location: DoStorageFailpointLocation) => Effect.Effect<void, DoStorageFailpointError>;
7
+ /** @internal Select a plain native body only for the library's no-op handler. */
8
+ export declare const isDefaultDoStorageFailpoint: (handler: DoStorageFailpointHandler) => boolean;
7
9
  declare const DoStorageFailpoint_base: Context.ServiceClass<DoStorageFailpoint, "@effect-agent/storage-cloudflare/DoStorageFailpoint", {
8
10
  readonly hit: DoStorageFailpointHandler;
9
11
  }>;
@@ -1,14 +1,19 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { Context, Effect, Layer } from "effect";
3
3
  //#region src/DoStorageFailpoint.ts
4
- var DoStorageFailpoint_exports = /* @__PURE__ */ __exportAll({ DoStorageFailpoint: () => DoStorageFailpoint });
4
+ var DoStorageFailpoint_exports = /* @__PURE__ */ __exportAll({
5
+ DoStorageFailpoint: () => DoStorageFailpoint,
6
+ isDefaultDoStorageFailpoint: () => isDefaultDoStorageFailpoint
7
+ });
5
8
  const noFailpoint = () => Effect.void;
9
+ /** @internal Select a plain native body only for the library's no-op handler. */
10
+ const isDefaultDoStorageFailpoint = (handler) => handler === noFailpoint;
6
11
  /** Explicit fault-injection authority used at Durable Object storage operation boundaries. */
7
12
  var DoStorageFailpoint = class extends Context.Service()("@effect-agent/storage-cloudflare/DoStorageFailpoint") {
8
13
  /** Production default: no fault injection. */
9
14
  static layer = Layer.succeed(this)({ hit: noFailpoint });
10
15
  };
11
16
  //#endregion
12
- export { DoStorageFailpoint, DoStorageFailpoint_exports as t };
17
+ export { DoStorageFailpoint, isDefaultDoStorageFailpoint, DoStorageFailpoint_exports as t };
13
18
 
14
19
  //# sourceMappingURL=DoStorageFailpoint.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"DoStorageFailpoint.mjs","names":[],"sources":["../src/DoStorageFailpoint.ts"],"sourcesContent":["import { Context, Effect, Layer } from \"effect\";\n\nimport type { DoStorageFailpointError, DoStorageFailpointLocation } from \"./DoStorageError.ts\";\n\nexport type DoStorageFailpointHandler = (\n location: DoStorageFailpointLocation,\n) => Effect.Effect<void, DoStorageFailpointError>;\n\nconst noFailpoint: DoStorageFailpointHandler = () => Effect.void;\n\n/** Explicit fault-injection authority used at Durable Object storage operation boundaries. */\nexport class DoStorageFailpoint extends Context.Service<\n DoStorageFailpoint,\n {\n readonly hit: DoStorageFailpointHandler;\n }\n>()(\"@effect-agent/storage-cloudflare/DoStorageFailpoint\") {\n /** Production default: no fault injection. */\n static readonly layer = Layer.succeed(this)({ hit: noFailpoint });\n}\n"],"mappings":";;;;AAQA,MAAM,oBAA+C,OAAO;;AAG5D,IAAa,qBAAb,cAAwC,QAAQ,QAK9C,CAAC,CAAC,qDAAqD,CAAC,CAAC;;CAEzD,OAAgB,QAAQ,MAAM,QAAQ,IAAI,CAAC,CAAC,EAAE,KAAK,YAAY,CAAC;AAClE"}
1
+ {"version":3,"file":"DoStorageFailpoint.mjs","names":[],"sources":["../src/DoStorageFailpoint.ts"],"sourcesContent":["import { Context, Effect, Layer } from \"effect\";\n\nimport type { DoStorageFailpointError, DoStorageFailpointLocation } from \"./DoStorageError.ts\";\n\nexport type DoStorageFailpointHandler = (\n location: DoStorageFailpointLocation,\n) => Effect.Effect<void, DoStorageFailpointError>;\n\nconst noFailpoint: DoStorageFailpointHandler = () => Effect.void;\n\n/** @internal Select a plain native body only for the library's no-op handler. */\nexport const isDefaultDoStorageFailpoint = (handler: DoStorageFailpointHandler): boolean =>\n handler === noFailpoint;\n\n/** Explicit fault-injection authority used at Durable Object storage operation boundaries. */\nexport class DoStorageFailpoint extends Context.Service<\n DoStorageFailpoint,\n {\n readonly hit: DoStorageFailpointHandler;\n }\n>()(\"@effect-agent/storage-cloudflare/DoStorageFailpoint\") {\n /** Production default: no fault injection. */\n static readonly layer = Layer.succeed(this)({ hit: noFailpoint });\n}\n"],"mappings":";;;;;;;AAQA,MAAM,oBAA+C,OAAO;;AAG5D,MAAa,+BAA+B,YAC1C,YAAY;;AAGd,IAAa,qBAAb,cAAwC,QAAQ,QAK9C,CAAC,CAAC,qDAAqD,CAAC,CAAC;;CAEzD,OAAgB,QAAQ,MAAM,QAAQ,IAAI,CAAC,CAAC,EAAE,KAAK,YAAY,CAAC;AAClE"}
@@ -12,10 +12,7 @@ import { Effect } from "effect";
12
12
  * The handles stay injected: this package never imports `cloudflare:workers`, so the harness
13
13
  * that owns a `DurableObjectState` supplies the thunk.
14
14
  */
15
- const evictionFailpointHandler = (options) => (location) => options.isArmed(location).pipe(Effect.flatMap((armed) => armed ? Effect.sync(() => {
16
- options.evict(location);
17
- throw new Error(`Durable Object eviction did not interrupt execution at ${location}.`);
18
- }) : Effect.void));
15
+ const evictionFailpointHandler = (options) => (location) => options.isArmed(location).pipe(Effect.flatMap((armed) => armed ? Effect.sync(() => options.evict(location)).pipe(Effect.andThen(Effect.die(/* @__PURE__ */ new Error(`Durable Object eviction did not interrupt execution at ${location}.`)))) : Effect.void));
19
16
  //#endregion
20
17
  export { evictionFailpointHandler };
21
18
 
@@ -1 +1 @@
1
- {"version":3,"file":"DoStorageFailpointTesting.mjs","names":[],"sources":["../src/DoStorageFailpointTesting.ts"],"sourcesContent":["import { Effect } from \"effect\";\n\nimport type { DoStorageFailpointLocation } from \"./DoStorageError.ts\";\nimport type { DoStorageFailpointHandler } from \"./DoStorageFailpoint.ts\";\n\n/**\n * The DC-specific eviction failpoint mode: instead of failing typed, an armed hit evicts the\n * Durable Object through an injected `evict` thunk — in production-shaped harnesses that thunk\n * is `() => ctx.abort()`, the platform's real failure mode. `ctx.abort()` never returns (it\n * throws while destroying the in-memory instance and every in-flight implicit or explicit\n * storage transaction rolls back), so an armed hit ends the current Attempt exactly like an\n * unannounced platform eviction; DO storage — the only correctness-critical state — survives\n * for the next incarnation, which the persisted alarm wakes without any incoming request.\n *\n * The handles stay injected: this package never imports `cloudflare:workers`, so the harness\n * that owns a `DurableObjectState` supplies the thunk.\n */\nexport const evictionFailpointHandler =\n (options: {\n readonly isArmed: (location: DoStorageFailpointLocation) => Effect.Effect<boolean>;\n /** Kills the incarnation — e.g. `() => ctx.abort()`. Typed `void` because the platform\n * declares `abort` as returning, but it throws while destroying the instance. */\n readonly evict: (location: DoStorageFailpointLocation) => void;\n }): DoStorageFailpointHandler =>\n (location) =>\n options.isArmed(location).pipe(\n Effect.flatMap((armed) =>\n armed\n ? // `ctx.abort()` throws while destroying the instance; that throw surfaces as a\n // defect in the (already dying) incarnation. The defensive throw below keeps the\n // guarantee — nothing after an armed hit may observe in-memory state — even if a\n // harness supplies an evict thunk that returns.\n Effect.sync((): never => {\n options.evict(location);\n throw new Error(\n `Durable Object eviction did not interrupt execution at ${location}.`,\n );\n })\n : Effect.void,\n ),\n );\n"],"mappings":";;;;;;;;;;;;;;AAiBA,MAAa,4BACV,aAMA,aACC,QAAQ,QAAQ,QAAQ,CAAC,CAAC,KACxB,OAAO,SAAS,UACd,QAKI,OAAO,WAAkB;CACvB,QAAQ,MAAM,QAAQ;CACtB,MAAM,IAAI,MACR,0DAA0D,SAAS,EACrE;AACF,CAAC,IACD,OAAO,IACb,CACF"}
1
+ {"version":3,"file":"DoStorageFailpointTesting.mjs","names":[],"sources":["../src/DoStorageFailpointTesting.ts"],"sourcesContent":["import { Effect } from \"effect\";\n\nimport type { DoStorageFailpointLocation } from \"./DoStorageError.ts\";\nimport type { DoStorageFailpointHandler } from \"./DoStorageFailpoint.ts\";\n\n/**\n * The DC-specific eviction failpoint mode: instead of failing typed, an armed hit evicts the\n * Durable Object through an injected `evict` thunk — in production-shaped harnesses that thunk\n * is `() => ctx.abort()`, the platform's real failure mode. `ctx.abort()` never returns (it\n * throws while destroying the in-memory instance and every in-flight implicit or explicit\n * storage transaction rolls back), so an armed hit ends the current Attempt exactly like an\n * unannounced platform eviction; DO storage — the only correctness-critical state — survives\n * for the next incarnation, which the persisted alarm wakes without any incoming request.\n *\n * The handles stay injected: this package never imports `cloudflare:workers`, so the harness\n * that owns a `DurableObjectState` supplies the thunk.\n */\nexport const evictionFailpointHandler =\n (options: {\n readonly isArmed: (location: DoStorageFailpointLocation) => Effect.Effect<boolean>;\n /** Kills the incarnation — e.g. `() => ctx.abort()`. Typed `void` because the platform\n * declares `abort` as returning, but it throws while destroying the instance. */\n readonly evict: (location: DoStorageFailpointLocation) => void;\n }): DoStorageFailpointHandler =>\n (location) =>\n options.isArmed(location).pipe(\n Effect.flatMap((armed) =>\n armed\n ? // `ctx.abort()` throws while destroying the instance; that throw surfaces as a\n // defect in the (already dying) incarnation. The defensive defect below keeps the\n // guarantee — nothing after an armed hit may observe in-memory state — even if a\n // harness supplies an evict thunk that returns.\n Effect.sync(() => options.evict(location)).pipe(\n Effect.andThen(\n Effect.die(\n // oxlint-disable-next-line effect/no-native-error -- A returning native eviction callback violates the host contract and must remain a defect.\n new Error(`Durable Object eviction did not interrupt execution at ${location}.`),\n ),\n ),\n )\n : Effect.void,\n ),\n );\n"],"mappings":";;;;;;;;;;;;;;AAiBA,MAAa,4BACV,aAMA,aACC,QAAQ,QAAQ,QAAQ,CAAC,CAAC,KACxB,OAAO,SAAS,UACd,QAKI,OAAO,WAAW,QAAQ,MAAM,QAAQ,CAAC,CAAC,CAAC,KACzC,OAAO,QACL,OAAO,oBAEL,IAAI,MAAM,0DAA0D,SAAS,EAAE,CACjF,CACF,CACF,IACA,OAAO,IACb,CACF"}
@@ -2,10 +2,10 @@ import "./DoStorageError-CxjMnzUA.mjs";
2
2
  import { Effect } from "effect";
3
3
  import "effect/sql/SqlClient";
4
4
  //#region src/internal/migrations.d.ts
5
- declare const CurrentDoStorageVersion = 27;
5
+ declare const CurrentDoStorageVersion = 28;
6
6
  declare namespace DoStorageVersion_d_exports {
7
7
  export { CurrentDoStorageVersion };
8
8
  }
9
9
  //#endregion
10
10
  export { CurrentDoStorageVersion as n, DoStorageVersion_d_exports as t };
11
- //# sourceMappingURL=DoStorageVersion-NKnQU3eR.d.mts.map
11
+ //# sourceMappingURL=DoStorageVersion-Mc7CXMdN.d.mts.map
@@ -1,2 +1,2 @@
1
- import { n as CurrentDoStorageVersion } from "./DoStorageVersion-NKnQU3eR.mjs";
1
+ import { n as CurrentDoStorageVersion } from "./DoStorageVersion-Mc7CXMdN.mjs";
2
2
  export { CurrentDoStorageVersion };
@@ -1,7 +1,7 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
- import { t as CurrentDoStorageVersion } from "./migrations-C3N9GN6A.mjs";
2
+ import { t as CurrentDoStorageVersion } from "./migrations-CAO_akhD.mjs";
3
3
  //#region src/DoStorageVersion.ts
4
- var DoStorageVersion_exports = /* @__PURE__ */ __exportAll({ CurrentDoStorageVersion: () => 27 });
4
+ var DoStorageVersion_exports = /* @__PURE__ */ __exportAll({ CurrentDoStorageVersion: () => 28 });
5
5
  //#endregion
6
6
  export { CurrentDoStorageVersion, DoStorageVersion_exports as t };
7
7
 
@@ -2,18 +2,18 @@ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
2
  import { DoStorageConfig } from "./DoStorageConfig.mjs";
3
3
  import { DoStorageFailpoint } from "./DoStorageFailpoint.mjs";
4
4
  import { DoLedgerError, DoStorageCorruptionError, DoStorageError } from "./DoStorageError.mjs";
5
- import { n as ownedRows } from "./owned-state-BHzUi0eb.mjs";
6
- import { i as initializeDoJournal, r as decodeRows } from "./do-journal-_MdLGTd3.mjs";
7
- import { l as prepareCanonicalAppend, o as storageConfigLayer, s as storageFailpointLayer } from "./DoThreadStore-CtyahRTW.mjs";
5
+ import { n as ownedRows } from "./owned-state-B4QhezMp.mjs";
6
+ import { i as initializeDoJournal, r as decodeRows } from "./do-journal-7P3DUBz0.mjs";
7
+ import { l as prepareCanonicalAppend, o as storageConfigLayer, s as storageFailpointLayer } from "./DoThreadStore-CgIZQUNR.mjs";
8
8
  import { BrowserCrypto } from "@effect/platform-browser";
9
9
  import { Cause, Clock, Context, Crypto, DateTime, Effect, Layer, Option, Schema, Stream } from "effect";
10
10
  import * as SqlClientService from "effect/sql/SqlClient";
11
+ import { SqliteClient } from "@effect/sql-sqlite-do";
11
12
  import { definitionJson, makeCanonicalStorage, recordBatchId, runKey } from "@yielded/agent-storage-sql/sql-canonical-storage";
12
13
  import { SqlStorageProgress } from "@yielded/agent-storage-sql/sql-storage-progress";
13
14
  import { canonicalRecordJson } from "@yielded/agent-storage-sql/sql-thread-archive-range";
14
- import { ApprovalDecision, CanonicalSequence, DefinitionDigests, Digest, PersistedJson, RecordEnvelope, SettlementOutcome, WorkerAdmission } from "@yielded/agent/records";
15
+ import { ApprovalDecision, CanonicalSequence, DefinitionDigests, Digest, PersistedJson, RecordEnvelope, RecordId, SettlementOutcome, WorkerAdmission } from "@yielded/agent/records";
15
16
  import { AppendConflict, ThreadNotMaterialized, ThreadStoreDiagnostic, ThreadStoreError, makeTransferFactCheck } from "@yielded/agent/thread-store";
16
- import { SqliteClient } from "@effect/sql-sqlite-do";
17
17
  import { StorageOwner } from "@yielded/agent/run-storage";
18
18
  import { decodeAbortFact, decodeAdmissionFact, decodeApprovalFact, decodeResolutionFact } from "@yielded/agent-storage-sql/sql-admission-facts";
19
19
  import { InputMessage } from "@yielded/agent/messaging";
@@ -55,7 +55,7 @@ var SubmissionRow = class extends Schema.Class("SubmissionRow")({
55
55
  receipt_id: BoundedIdentifier,
56
56
  state: SubmissionState,
57
57
  settled_outcome: Schema.NullOr(SettlementOutcome),
58
- settled_record_id: Schema.NullOr(BoundedIdentifier),
58
+ settled_record_id: Schema.NullOr(BoundedIdentifier.pipe(Schema.decodeTo(RecordId))),
59
59
  finalized_at: Schema.NullOr(BoundedTimestamp),
60
60
  created_at: BoundedTimestamp,
61
61
  ready_at: Schema.NullOr(BoundedTimestamp),
@@ -191,7 +191,7 @@ const decodeClaim = Schema.decodeUnknownEffect(Claim);
191
191
  const decodeSettlement = Schema.decodeUnknownEffect(Settlement);
192
192
  const decodeAbortIntent = Schema.decodeUnknownEffect(AbortIntent);
193
193
  const decodeInputAppliedMarker = Schema.decodeUnknownEffect(InputAppliedMarker);
194
- const decodeSubmissionSnapshotType = (input) => Schema.decodeEffect(Schema.toType(Schema.Struct(SubmissionSnapshot.fields)))(input).pipe(Effect.map((fields) => SubmissionSnapshot.make(fields)));
194
+ const decodeSubmissionSnapshotType = (input) => SubmissionSnapshot.makeEffect(input).pipe(Effect.mapError((issue) => new Schema.SchemaError(issue)));
195
195
  const decodeSubmissionId = Schema.decodeUnknownEffect(SubmissionSnapshot.fields.submissionId);
196
196
  const decodeQueueSequence = Schema.decodeUnknownEffect(QueueSequence);
197
197
  const decodeUtcInstant = Schema.decodeUnknownEffect(Schema.DateTimeUtcFromString);
@@ -205,6 +205,26 @@ const decodeChildReservationSnapshotUnknown = Schema.decodeUnknownEffect(ChildBu
205
205
  const decodeChildAttachmentSnapshot = Schema.decodeUnknownEffect(ChildAttachmentSnapshot);
206
206
  const equivalentPersistedJson = Schema.toEquivalence(PersistedJson);
207
207
  const equivalentUnknownResolution = Schema.toEquivalence(UnknownResolution);
208
+ const decodeAdmissionRequestType = Schema.decodeEffect(Schema.toType(AdmissionRequest));
209
+ const decodeSubmissionLookupType = Schema.decodeEffect(Schema.toType(SubmissionLookup));
210
+ const decodeClaimRequestType = Schema.decodeEffect(Schema.toType(ClaimRequest));
211
+ const decodeMarkInputAppliedRequestType = Schema.decodeEffect(Schema.toType(MarkInputAppliedRequest));
212
+ const decodeSettlementFinalizationType = Schema.decodeEffect(Schema.toType(SettlementFinalization));
213
+ const decodeClaimJoiningRequestType = Schema.decodeEffect(Schema.toType(ClaimJoiningRequest));
214
+ const decodeAbortIntentRequestType = Schema.decodeEffect(Schema.toType(AbortIntentRequest));
215
+ const decodeRecoverySnapshotRequestType = Schema.decodeEffect(Schema.toType(RecoverySnapshotRequest));
216
+ const SubmissionRows = Schema.Array(SubmissionRow);
217
+ const ChildReservationRows = Schema.Array(ChildReservationRow);
218
+ const MaxQueueSequenceRows = Schema.Array(MaxQueueSequenceRow);
219
+ const SubmissionWorkItems = Schema.Array(SubmissionWorkItem);
220
+ const decodeSubmissionWorkItems = Schema.decodeEffect(SubmissionWorkItems);
221
+ const equivalentWorkerOrigin = Schema.toEquivalence(Schema.optional(WorkerAdmission.fields.origin));
222
+ const decodeFirstWorkerAdmissions = Schema.decodeUnknownEffect(Schema.Array(Schema.Struct({ worker_admission_json: Schema.NullOr(BoundedStoredText) })));
223
+ const CanonicalSettlementRows = Schema.Array(Schema.Struct({
224
+ batch_id: Schema.fromJsonString(BoundedIdentifier),
225
+ record_id: Schema.fromJsonString(BoundedIdentifier),
226
+ record_json: BoundedStoredText
227
+ }));
208
228
  const isDoStorageError = Schema.is(DoStorageError);
209
229
  /** Wrap an adapter-internal failure into the port's LedgerError without erasing its tag. */
210
230
  const internalFailure = (operation) => (error) => LedgerError.make({
@@ -319,7 +339,7 @@ const makeServices = Effect.fnUntraced(function* () {
319
339
  millis,
320
340
  iso: new Date(millis).toISOString()
321
341
  }));
322
- const decodeSubmissionRows = (operation, rowKey, rows) => decodeRows(Schema.Array(SubmissionRow), "effect_agent_submissions", rowKey, rows).pipe(Effect.mapError(internalFailure(operation)));
342
+ const decodeSubmissionRows = (operation, rowKey, rows) => decodeRows(SubmissionRows, "effect_agent_submissions", rowKey, rows).pipe(Effect.mapError(internalFailure(operation)));
323
343
  const readSubmission = Effect.fnUntraced(function* (operation, submissionId) {
324
344
  const found = yield* cached(rows.submissions.by("submission_id", submissionId), operation);
325
345
  return Option.fromUndefinedOr(found[0]);
@@ -354,11 +374,14 @@ const makeServices = Effect.fnUntraced(function* () {
354
374
  }));
355
375
  if (row.parent_submission_id === null !== (row.parent_tool_call_id === null)) return yield* corruptionFailure(operation, "effect_agent_submissions", row.submission_id, "A parent linkage must record both the parent Submission and the parent Tool Call.");
356
376
  const admission = yield* decodeAdmissionFact(row).pipe(Effect.mapError(decodeFailure));
377
+ const settledAt = row.finalized_at === null ? void 0 : yield* decodeUtcInstant(row.finalized_at).pipe(Effect.mapError(decodeFailure));
357
378
  const readyAt = row.ready_at === null ? void 0 : yield* decodeUtcInstant(row.ready_at).pipe(Effect.mapError(decodeFailure));
358
379
  const snapshot = yield* decodeSubmissionSnapshotType({
359
380
  ...admission,
360
381
  state: row.state,
361
382
  ...row.settled_outcome === null ? {} : { settledOutcome: row.settled_outcome },
383
+ ...settledAt === void 0 ? {} : { settledAt },
384
+ ...row.settled_record_id === null ? {} : { settledRecordId: row.settled_record_id },
362
385
  ...readyAt === void 0 ? {} : { readyAt }
363
386
  }).pipe(Effect.mapError(decodeFailure));
364
387
  submissions.set(row, snapshot);
@@ -370,11 +393,7 @@ const makeServices = Effect.fnUntraced(function* () {
370
393
  const found = yield* sql`SELECT ${recordBatchId(sql)} AS batch_id, record_id, ${canonicalRecordJson(sql)} AS record_json
371
394
  FROM effect_agent_canonical_records WHERE thread_id = ${submission.thread_id}
372
395
  AND record_id = ${JSON.stringify(recordId)}`.pipe(Effect.mapError(sqlFailure(operation)));
373
- const decoded = yield* decodeRows(Schema.Array(Schema.Struct({
374
- batch_id: Schema.fromJsonString(BoundedIdentifier),
375
- record_id: Schema.fromJsonString(BoundedIdentifier),
376
- record_json: BoundedStoredText
377
- })), "effect_agent_canonical_records", recordId, found).pipe(Effect.mapError(internalFailure(operation)));
396
+ const decoded = yield* decodeRows(CanonicalSettlementRows, "effect_agent_canonical_records", recordId, found).pipe(Effect.mapError(internalFailure(operation)));
378
397
  if (decoded.length === 0) return void 0;
379
398
  const row = decoded[0];
380
399
  if (decoded.length !== 1 || row.batch_id !== submissionSettlementBatchId(expected.submissionId) || row.record_id !== recordId) return yield* corruptionFailure(operation, "effect_agent_canonical_records", recordId, "Canonical settlement identity is inconsistent.");
@@ -407,7 +426,7 @@ const makeServices = Effect.fnUntraced(function* () {
407
426
  const childRow = yield* readSubmission(operation, childSubmissionId);
408
427
  return Option.isSome(childRow) && (yield* readCanonicalSettlement(operation, childRow.value)) !== void 0;
409
428
  });
410
- const decodeChildReservationRows = (operation, rowKey, rows) => decodeRows(Schema.Array(ChildReservationRow), "effect_agent_child_reservations", rowKey, rows).pipe(Effect.mapError(internalFailure(operation)));
429
+ const decodeChildReservationRows = (operation, rowKey, rows) => decodeRows(ChildReservationRows, "effect_agent_child_reservations", rowKey, rows).pipe(Effect.mapError(internalFailure(operation)));
411
430
  const readChildReservation = Effect.fnUntraced(function* (operation, reservationId) {
412
431
  const rows = yield* sql`
413
432
  SELECT ${sql.literal(CHILD_RESERVATION_COLUMNS)}
@@ -480,9 +499,9 @@ const makeServices = Effect.fnUntraced(function* () {
480
499
  });
481
500
  });
482
501
  const capabilities = Effect.succeed(LedgerCapabilities.make({ durability: "durable-cloudflare" }));
483
- const admit = Effect.fnUntraced(function* (request) {
502
+ const admit = Effect.fnUntraced(function* (request, options) {
484
503
  const operation = "ledger admit";
485
- const validated = yield* Schema.decodeEffect(Schema.toType(AdmissionRequest))(request).pipe(Effect.mapError(internalFailure(operation)));
504
+ const validated = yield* decodeAdmissionRequestType(request).pipe(Effect.mapError(internalFailure(operation)));
486
505
  const inputJson = yield* encodePersistedJsonText(validated.inputPayload).pipe(Effect.mapError(internalFailure(operation)));
487
506
  yield* journal.checkValueBound(operation, inputJson).pipe(Effect.mapError(internalFailure(operation)));
488
507
  const workerAdmissionJson = validated.workerAdmission === void 0 ? null : yield* Schema.encodeEffect(Schema.fromJsonString(WorkerAdmission))(validated.workerAdmission).pipe(Effect.mapError(internalFailure(operation)));
@@ -547,10 +566,10 @@ const makeServices = Effect.fnUntraced(function* () {
547
566
  SELECT worker_admission_json FROM effect_agent_submissions
548
567
  WHERE thread_id=${validated.threadId} ORDER BY queue_sequence LIMIT 1
549
568
  `.pipe(Effect.mapError(sqlFailure(operation)));
550
- const first = yield* Schema.decodeUnknownEffect(Schema.Array(Schema.Struct({ worker_admission_json: Schema.NullOr(BoundedStoredText) })))(firstRows).pipe(Effect.mapError(internalFailure(operation)));
569
+ const first = yield* decodeFirstWorkerAdmissions(firstRows).pipe(Effect.mapError(internalFailure(operation)));
551
570
  if (first[0] !== void 0) {
552
571
  const previous = first[0].worker_admission_json === null ? void 0 : yield* Schema.decodeEffect(Schema.fromJsonString(WorkerAdmission))(first[0].worker_admission_json).pipe(Effect.mapError(internalFailure(operation)));
553
- if (!Schema.toEquivalence(Schema.optional(WorkerAdmission.fields.origin))(previous?.origin, validated.workerAdmission?.origin)) return yield* AdmissionPolicyError.make({
572
+ if (!equivalentWorkerOrigin(previous?.origin, validated.workerAdmission?.origin)) return yield* AdmissionPolicyError.make({
554
573
  reason: "refused",
555
574
  code: "worker-origin-conflict"
556
575
  });
@@ -570,9 +589,10 @@ const makeServices = Effect.fnUntraced(function* () {
570
589
  FROM effect_agent_submissions
571
590
  WHERE thread_id = ${validated.threadId}
572
591
  `.pipe(Effect.mapError(sqlFailure(operation)));
573
- const decodedMax = yield* decodeRows(Schema.Array(MaxQueueSequenceRow), "effect_agent_submissions", validated.threadId, maxRows).pipe(Effect.mapError(internalFailure(operation)));
592
+ const decodedMax = yield* decodeRows(MaxQueueSequenceRows, "effect_agent_submissions", validated.threadId, maxRows).pipe(Effect.mapError(internalFailure(operation)));
574
593
  const queueSequence = yield* decodeQueueSequence((decodedMax[0]?.max_queue_sequence ?? 0) + 1).pipe(Effect.mapError(internalFailure(operation)));
575
594
  const now = yield* currentInstant;
595
+ const ready = options?.readyIfInitialized === true && validated.workerAdmission === void 0 && (yield* journal.getThread(validated.threadId).pipe(Effect.mapError(internalFailure(operation)))).some((thread) => thread.tail_sequence > 0);
576
596
  yield* sql`
577
597
  INSERT INTO effect_agent_submissions (
578
598
  submission_id,
@@ -588,6 +608,7 @@ const makeServices = Effect.fnUntraced(function* () {
588
608
  receipt_id,
589
609
  state,
590
610
  created_at,
611
+ ready_at,
591
612
  parent_submission_id,
592
613
  parent_tool_call_id,
593
614
  admission_group,
@@ -606,8 +627,9 @@ const makeServices = Effect.fnUntraced(function* () {
606
627
  ${inputJson},
607
628
  ${validated.inputDigest},
608
629
  ${mintedReceiptId},
609
- 'admitted',
630
+ ${ready ? "ready" : "admitted"},
610
631
  ${now.iso},
632
+ ${ready ? now.iso : null},
611
633
  ${validated.parentLinkage?.parentSubmissionId ?? null},
612
634
  ${validated.parentLinkage?.parentToolCallId ?? null},
613
635
  ${validated.admissionGroup ?? null},
@@ -619,6 +641,11 @@ const makeServices = Effect.fnUntraced(function* () {
619
641
  if (queueSequence === 1) {
620
642
  if ((yield* journal.getThread(validated.threadId).pipe(Effect.mapError(internalFailure(operation)))).length === 0) yield* journal.work.initialize(validated.threadId).pipe(Effect.mapError(internalFailure(operation)));
621
643
  }
644
+ submissionViews.seedMatching(JSON.stringify([
645
+ "joining-suffix",
646
+ validated.threadId,
647
+ queueSequence
648
+ ]), (row) => row.thread_id === validated.threadId && row.queue_sequence > queueSequence, [], 0);
622
649
  rows.aborts.seed("submission_id", mintedSubmissionId, []);
623
650
  rows.submissions.seed("joined_host_submission_id", mintedSubmissionId, []);
624
651
  rows.approvals.seed("submission_id", mintedSubmissionId, []);
@@ -626,13 +653,18 @@ const makeServices = Effect.fnUntraced(function* () {
626
653
  rows.childReservations.seed("parent_submission_id", mintedSubmissionId, []);
627
654
  rows.childSettlements.seed("parent_submission_id", mintedSubmissionId, []);
628
655
  yield* recordProgress("submission", operation);
629
- return yield* decodeAdmissionResult({
656
+ const admitted = yield* decodeAdmissionResult({
630
657
  submissionId: mintedSubmissionId,
631
658
  receiptId: mintedReceiptId,
632
659
  queueSequence,
633
- state: "admitted",
660
+ state: ready ? "ready" : "admitted",
634
661
  replayed: false
635
662
  }).pipe(Effect.mapError(internalFailure(operation)));
663
+ if (ready && lifecycle !== void 0) yield* retainLifecycle(yield* requireSubmission(operation, mintedSubmissionId), {
664
+ _tag: "SubmissionReady",
665
+ submissionId: admitted.submissionId
666
+ });
667
+ return admitted;
636
668
  }));
637
669
  yield* hitFailpoint("ledger:admit:after", operation);
638
670
  return result;
@@ -682,7 +714,7 @@ const makeServices = Effect.fnUntraced(function* () {
682
714
  }, state.read);
683
715
  const lookup = Effect.fnUntraced(function* (request) {
684
716
  const operation = "ledger lookup";
685
- const validated = yield* Schema.decodeEffect(Schema.toType(SubmissionLookup))(request).pipe(Effect.mapError(internalFailure(operation)));
717
+ const validated = yield* decodeSubmissionLookupType(request).pipe(Effect.mapError(internalFailure(operation)));
686
718
  if (validated._tag === "SubmissionLookupById") {
687
719
  const row = yield* readSubmission(operation, validated.submissionId);
688
720
  if (Option.isNone(row)) return Option.none();
@@ -705,12 +737,23 @@ const makeServices = Effect.fnUntraced(function* () {
705
737
  });
706
738
  const selectHead = Effect.fn("DoSubmissionLedger.selectHead")(function* (request) {
707
739
  const operation = "ledger select head";
708
- const validated = yield* Schema.decodeEffect(Schema.toType(ClaimRequest))(request).pipe(Effect.mapError(internalFailure(operation)));
740
+ const validated = yield* decodeClaimRequestType(request).pipe(Effect.mapError(internalFailure(operation)));
709
741
  const attemptId = `attempt-${yield* mintUuid(operation)}`;
710
742
  yield* hitFailpoint("ledger:claim:before", operation);
711
743
  const claimed = yield* owner.withMutation(Effect.gen(function* () {
712
744
  if (owner.hasOwner(validated.threadId)) return Option.none();
713
- const headRows = yield* sql`
745
+ const active = yield* activeNonterminal;
746
+ const heads = [];
747
+ const limit = validated.handoff === void 0 ? 1 : validated.handoff.deferredSubmissionIds.length + 1;
748
+ if (active.length <= 128) {
749
+ const candidates = active.filter((row) => row.thread_id === validated.threadId).sort((left, right) => left.queue_sequence - right.queue_sequence);
750
+ for (const candidate of candidates) {
751
+ if (candidate.state === "unknown" && Option.isNone(yield* readAbortIntent(operation, candidate.submission_id))) continue;
752
+ heads.push(yield* requireSubmission(operation, candidate.submission_id));
753
+ if (heads.length === limit) break;
754
+ }
755
+ } else {
756
+ const headRows = yield* sql`
714
757
  SELECT ${submissionColumns}
715
758
  FROM effect_agent_submissions
716
759
  WHERE thread_id = ${validated.threadId}
@@ -724,7 +767,8 @@ const makeServices = Effect.fnUntraced(function* () {
724
767
  ORDER BY queue_sequence ASC
725
768
  LIMIT ${validated.handoff === void 0 ? 1 : validated.handoff.deferredSubmissionIds.length + 1}
726
769
  `.pipe(Effect.mapError(sqlFailure(operation)));
727
- const heads = yield* decodeSubmissionRows(operation, validated.threadId, headRows);
770
+ heads.push(...yield* decodeSubmissionRows(operation, validated.threadId, headRows));
771
+ }
728
772
  if (heads.length === 0) return Option.none();
729
773
  let head = heads[0];
730
774
  if (validated.handoff !== void 0) {
@@ -751,7 +795,7 @@ const makeServices = Effect.fnUntraced(function* () {
751
795
  });
752
796
  const markInputApplied = Effect.fnUntraced(function* (request) {
753
797
  const operation = "ledger mark input applied";
754
- const validated = yield* Schema.decodeEffect(Schema.toType(MarkInputAppliedRequest))(request).pipe(Effect.mapError(internalFailure(operation)));
798
+ const validated = yield* decodeMarkInputAppliedRequestType(request).pipe(Effect.mapError(internalFailure(operation)));
755
799
  yield* hitFailpoint("ledger:mark-input-applied:before", operation);
756
800
  yield* inWriteTransaction(operation, Effect.gen(function* () {
757
801
  const submission = yield* requireSubmission(operation, validated.submissionId);
@@ -896,7 +940,7 @@ const makeServices = Effect.fnUntraced(function* () {
896
940
  });
897
941
  const finalizeSettlement = Effect.fn("DoSubmissionLedger.finalizeSettlement")(function* (request) {
898
942
  const operation = "ledger finalize settlement";
899
- const validated = yield* Schema.decodeEffect(Schema.toType(SettlementFinalization))(request).pipe(Effect.mapError(internalFailure(operation)));
943
+ const validated = yield* decodeSettlementFinalizationType(request).pipe(Effect.mapError(internalFailure(operation)));
900
944
  yield* hitFailpoint("ledger:finalize-settlement:before", operation);
901
945
  const replay = yield* state.read(Effect.gen(function* () {
902
946
  const submission = yield* readSubmission(operation, validated.submissionId);
@@ -1056,9 +1100,9 @@ const makeServices = Effect.fnUntraced(function* () {
1056
1100
  });
1057
1101
  const claimJoining = Effect.fnUntraced(function* (request) {
1058
1102
  const operation = "ledger claim joining";
1059
- const validated = yield* Schema.decodeEffect(Schema.toType(ClaimJoiningRequest))(request).pipe(Effect.mapError(internalFailure(operation)));
1103
+ const validated = yield* decodeClaimJoiningRequestType(request).pipe(Effect.mapError(internalFailure(operation)));
1060
1104
  yield* hitFailpoint("ledger:claim-joining:before", operation);
1061
- const claims = yield* inWriteTransaction(operation, Effect.gen(function* () {
1105
+ const claims = yield* owner.withMutation(Effect.gen(function* () {
1062
1106
  const host = yield* requireSubmission(operation, validated.hostSubmissionId);
1063
1107
  if (host.thread_id !== validated.threadId) return yield* LedgerError.make({
1064
1108
  operation,
@@ -1066,36 +1110,42 @@ const makeServices = Effect.fnUntraced(function* () {
1066
1110
  });
1067
1111
  yield* requireOwner(operation, host);
1068
1112
  if ((yield* cached(rows.workerStops.by("thread_id", validated.threadId), operation)).length > 0) return [];
1069
- const laterRows = yield* sql`
1070
- SELECT ${submissionColumns}
1071
- FROM effect_agent_submissions
1072
- WHERE thread_id = ${validated.threadId}
1073
- AND queue_sequence > ${host.queue_sequence}
1074
- ORDER BY queue_sequence ASC
1075
- `.pipe(Effect.mapError(sqlFailure(operation)));
1076
- const later = yield* decodeSubmissionRows(operation, validated.threadId, laterRows);
1077
- const claimed = [];
1078
- for (const row of later) {
1079
- if (claimed.length >= validated.maxCount) break;
1080
- if ((row.state === "joining" || row.state === "joined") && row.joined_host_submission_id === validated.hostSubmissionId) continue;
1081
- if (row.state === "settled" && row.settled_outcome === "aborted") continue;
1082
- if (row.state !== "ready") break;
1083
- const canonical = yield* readCanonicalSettlement(operation, row);
1084
- if (canonical?.settlement.outcome === "aborted") continue;
1085
- if (canonical !== void 0) break;
1086
- yield* sql`
1113
+ const later = yield* submissionViews.matching(JSON.stringify([
1114
+ "joining-suffix",
1115
+ validated.threadId,
1116
+ host.queue_sequence
1117
+ ]), (row) => row.thread_id === validated.threadId && row.queue_sequence > host.queue_sequence, sql`
1118
+ SELECT ${submissionColumns}
1119
+ FROM effect_agent_submissions
1120
+ WHERE thread_id = ${validated.threadId}
1121
+ AND queue_sequence > ${host.queue_sequence}
1122
+ ORDER BY queue_sequence ASC
1123
+ `, 0).pipe(Effect.mapError((error) => error._tag === "SqlError" ? sqlFailure(operation)(error) : internalFailure(operation)(error)));
1124
+ if (later.length === 0) return [];
1125
+ return yield* inWriteTransaction(operation, Effect.gen(function* () {
1126
+ const claimed = [];
1127
+ for (const row of later) {
1128
+ if (claimed.length >= validated.maxCount) break;
1129
+ if ((row.state === "joining" || row.state === "joined") && row.joined_host_submission_id === validated.hostSubmissionId) continue;
1130
+ if (row.state === "settled" && row.settled_outcome === "aborted") continue;
1131
+ if (row.state !== "ready") break;
1132
+ const canonical = yield* readCanonicalSettlement(operation, row);
1133
+ if (canonical?.settlement.outcome === "aborted") continue;
1134
+ if (canonical !== void 0) break;
1135
+ yield* sql`
1087
1136
  UPDATE effect_agent_submissions
1088
1137
  SET state = 'joining', joined_host_submission_id = ${validated.hostSubmissionId}
1089
1138
  WHERE submission_id = ${row.submission_id}
1090
1139
  RETURNING *, ${definitionJson(sql)} AS agent_digests_json`.pipe(rows.submissions.write, Effect.mapError(internalFailure(operation)));
1091
- const inputPayload = yield* parseStoredJsonText(row.input_json).pipe(Effect.mapError((error) => corruptionFailure(operation, "effect_agent_submissions", row.submission_id, error.message)));
1092
- claimed.push(yield* decodeJoiningClaim({
1093
- submissionId: row.submission_id,
1094
- queueSequence: row.queue_sequence,
1095
- inputPayload
1096
- }).pipe(Effect.mapError(internalFailure(operation))));
1097
- }
1098
- return claimed;
1140
+ const inputPayload = yield* parseStoredJsonText(row.input_json).pipe(Effect.mapError((error) => corruptionFailure(operation, "effect_agent_submissions", row.submission_id, error.message)));
1141
+ claimed.push(yield* decodeJoiningClaim({
1142
+ submissionId: row.submission_id,
1143
+ queueSequence: row.queue_sequence,
1144
+ inputPayload
1145
+ }).pipe(Effect.mapError(internalFailure(operation))));
1146
+ }
1147
+ return claimed;
1148
+ }));
1099
1149
  }));
1100
1150
  yield* hitFailpoint("ledger:claim-joining:after", operation);
1101
1151
  return claims;
@@ -1665,20 +1715,21 @@ const makeServices = Effect.fnUntraced(function* () {
1665
1715
  ORDER BY thread_id ASC, queue_sequence ASC
1666
1716
  LIMIT ${SCAN_PAGE_SIZE}
1667
1717
  `).pipe(Effect.mapError(sqlFailure(operation)));
1668
- const decoded = yield* decodeRows(Schema.Array(SubmissionWorkItem), "effect_agent_submissions", "nonterminal_scan", rows, "SubmissionWorkItem").pipe(Effect.mapError(internalFailure(operation)));
1718
+ const decoded = yield* decodeRows(SubmissionWorkItems, "effect_agent_submissions", "nonterminal_scan", rows, "SubmissionWorkItem").pipe(Effect.mapError(internalFailure(operation)));
1669
1719
  const last = decoded[decoded.length - 1];
1670
1720
  return [decoded, last === void 0 || decoded.length < SCAN_PAGE_SIZE ? Option.none() : Option.some({
1671
1721
  threadId: last.threadId,
1672
1722
  queueSequence: last.queueSequence
1673
1723
  })];
1674
1724
  });
1675
- const scanNonterminal = Stream.unwrap(state.read(Effect.gen(function* () {
1676
- const active = yield* cached(workRows.matching("nonterminal", (row) => row.state !== "settled", sql`SELECT submission_id, thread_id, queue_sequence, principal, idempotency_key,
1677
- deployment_id, receipt_id, state
1678
- FROM effect_agent_submissions WHERE state <> 'settled' LIMIT 129`, 128), "ledger scan nonterminal");
1679
- if (active.length > 128) return Stream.paginate(void 0, scanPage);
1725
+ const activeNonterminal = cached(workRows.matching("nonterminal", (row) => row.state !== "settled", sql`SELECT submission_id, thread_id, queue_sequence, principal, idempotency_key,
1726
+ deployment_id, receipt_id, state
1727
+ FROM effect_agent_submissions WHERE state <> 'settled' LIMIT 129`, 128), "ledger scan nonterminal");
1728
+ const boundedNonterminal = state.read(Effect.gen(function* () {
1729
+ const active = yield* activeNonterminal;
1730
+ if (active.length > 128) return void 0;
1680
1731
  const sorted = [...active].sort((left, right) => left.thread_id < right.thread_id ? -1 : left.thread_id > right.thread_id ? 1 : left.queue_sequence - right.queue_sequence);
1681
- const work = yield* Schema.decodeEffect(Schema.Array(SubmissionWorkItem))(sorted.map((row) => ({
1732
+ return yield* decodeSubmissionWorkItems(sorted.map((row) => ({
1682
1733
  submissionId: row.submission_id,
1683
1734
  threadId: row.thread_id,
1684
1735
  queueSequence: row.queue_sequence,
@@ -1688,11 +1739,13 @@ const makeServices = Effect.fnUntraced(function* () {
1688
1739
  receiptId: row.receipt_id,
1689
1740
  state: row.state
1690
1741
  }))).pipe(Effect.mapError(internalFailure("ledger scan nonterminal")));
1691
- return Stream.fromIterable(work);
1692
- })));
1742
+ }));
1743
+ const pagedNonterminal = Stream.paginate(void 0, scanPage);
1744
+ const scanNonterminal = Stream.unwrap(Effect.map(boundedNonterminal, (work) => work === void 0 ? pagedNonterminal : Stream.fromIterable(work)));
1745
+ const listNonterminal = Effect.filterOrElse(boundedNonterminal, (work) => work !== void 0, () => Stream.runCollect(pagedNonterminal));
1693
1746
  const readAbortIntentForSubmission = Effect.fnUntraced(function* (request) {
1694
1747
  const operation = "ledger read abort intent";
1695
- const validated = yield* Schema.decodeEffect(Schema.toType(AbortIntentRequest))(request).pipe(Effect.mapError(internalFailure(operation)));
1748
+ const validated = yield* decodeAbortIntentRequestType(request).pipe(Effect.mapError(internalFailure(operation)));
1696
1749
  return yield* state.read(Effect.gen(function* () {
1697
1750
  const submission = yield* requireSubmission(operation, validated.submissionId);
1698
1751
  const intent = yield* readAbortIntent(operation, validated.submissionId);
@@ -1701,7 +1754,7 @@ const makeServices = Effect.fnUntraced(function* () {
1701
1754
  });
1702
1755
  const loadRecoverySnapshot = Effect.fnUntraced(function* (request) {
1703
1756
  const operation = "ledger load recovery snapshot";
1704
- const validated = yield* Schema.decodeEffect(Schema.toType(RecoverySnapshotRequest))(request).pipe(Effect.mapError(internalFailure(operation)));
1757
+ const validated = yield* decodeRecoverySnapshotRequestType(request).pipe(Effect.mapError(internalFailure(operation)));
1705
1758
  return yield* state.read(Effect.gen(function* () {
1706
1759
  const submissionRow = yield* requireSubmission(operation, validated.submissionId);
1707
1760
  const submission = yield* decodeSubmissionSnapshot(operation, submissionRow);
@@ -1808,6 +1861,7 @@ const makeServices = Effect.fnUntraced(function* () {
1808
1861
  beginChildBudgetRelease,
1809
1862
  releaseChildBudget,
1810
1863
  scanNonterminal,
1864
+ listNonterminal,
1811
1865
  loadRecoverySnapshot,
1812
1866
  readAbortIntent: readAbortIntentForSubmission
1813
1867
  })).pipe(Context.add(StorageOwner, owner), Context.add(SettlementPublisher, { publish }));