@yielded/agent-storage-cloudflare 0.1.0-beta.174 → 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 (37) 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/{DoStorageVersion-NKnQU3eR.d.mts → DoStorageVersion-Mc7CXMdN.d.mts} +2 -2
  7. package/dist/DoStorageVersion.d.mts +1 -1
  8. package/dist/DoStorageVersion.mjs +2 -2
  9. package/dist/DoSubmissionLedger.mjs +116 -65
  10. package/dist/DoSubmissionLedger.mjs.map +1 -1
  11. package/dist/{DoThreadStore-DyzOZDXK.mjs → DoThreadStore-CgIZQUNR.mjs} +24 -19
  12. package/dist/DoThreadStore-CgIZQUNR.mjs.map +1 -0
  13. package/dist/DoThreadStore.mjs +1 -1
  14. package/dist/PortProtocol.d.mts +7063 -7063
  15. package/dist/PortRouting.mjs +6 -1
  16. package/dist/PortRouting.mjs.map +1 -1
  17. package/dist/{do-journal-ZMAzzENZ.mjs → do-journal-7P3DUBz0.mjs} +131 -43
  18. package/dist/do-journal-7P3DUBz0.mjs.map +1 -0
  19. package/dist/index.d.mts +1 -1
  20. package/dist/index.mjs +1 -1
  21. package/dist/{migrations-C3N9GN6A.mjs → migrations-CAO_akhD.mjs} +45 -22
  22. package/dist/migrations-CAO_akhD.mjs.map +1 -0
  23. package/dist/{owned-state-DcFh0YNo.mjs → owned-state-B4QhezMp.mjs} +2 -1
  24. package/dist/{owned-state-DcFh0YNo.mjs.map → owned-state-B4QhezMp.mjs.map} +1 -1
  25. package/package.json +1 -1
  26. package/src/DoStorageFailpoint.ts +4 -0
  27. package/src/DoSubmissionLedger.ts +262 -149
  28. package/src/DoThreadStore.ts +18 -44
  29. package/src/PortRouting.ts +10 -2
  30. package/src/internal/do-journal.ts +286 -66
  31. package/src/internal/migrations.ts +52 -10
  32. package/src/internal/owned-state.ts +9 -1
  33. package/src/internal/prompt-checkpoint.ts +6 -3
  34. package/src/internal/storage-span.ts +14 -10
  35. package/dist/DoThreadStore-DyzOZDXK.mjs.map +0 -1
  36. package/dist/do-journal-ZMAzzENZ.mjs.map +0 -1
  37. package/dist/migrations-C3N9GN6A.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-DcFh0YNo.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-ZMAzzENZ.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"}
@@ -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-DcFh0YNo.mjs";
6
- import { i as initializeDoJournal, r as decodeRows } from "./do-journal-ZMAzzENZ.mjs";
7
- import { l as prepareCanonicalAppend, o as storageConfigLayer, s as storageFailpointLayer } from "./DoThreadStore-DyzOZDXK.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
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";
@@ -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]);
@@ -373,11 +393,7 @@ const makeServices = Effect.fnUntraced(function* () {
373
393
  const found = yield* sql`SELECT ${recordBatchId(sql)} AS batch_id, record_id, ${canonicalRecordJson(sql)} AS record_json
374
394
  FROM effect_agent_canonical_records WHERE thread_id = ${submission.thread_id}
375
395
  AND record_id = ${JSON.stringify(recordId)}`.pipe(Effect.mapError(sqlFailure(operation)));
376
- const decoded = yield* decodeRows(Schema.Array(Schema.Struct({
377
- batch_id: Schema.fromJsonString(BoundedIdentifier),
378
- record_id: Schema.fromJsonString(BoundedIdentifier),
379
- record_json: BoundedStoredText
380
- })), "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)));
381
397
  if (decoded.length === 0) return void 0;
382
398
  const row = decoded[0];
383
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.");
@@ -410,7 +426,7 @@ const makeServices = Effect.fnUntraced(function* () {
410
426
  const childRow = yield* readSubmission(operation, childSubmissionId);
411
427
  return Option.isSome(childRow) && (yield* readCanonicalSettlement(operation, childRow.value)) !== void 0;
412
428
  });
413
- 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)));
414
430
  const readChildReservation = Effect.fnUntraced(function* (operation, reservationId) {
415
431
  const rows = yield* sql`
416
432
  SELECT ${sql.literal(CHILD_RESERVATION_COLUMNS)}
@@ -483,9 +499,9 @@ const makeServices = Effect.fnUntraced(function* () {
483
499
  });
484
500
  });
485
501
  const capabilities = Effect.succeed(LedgerCapabilities.make({ durability: "durable-cloudflare" }));
486
- const admit = Effect.fnUntraced(function* (request) {
502
+ const admit = Effect.fnUntraced(function* (request, options) {
487
503
  const operation = "ledger admit";
488
- 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)));
489
505
  const inputJson = yield* encodePersistedJsonText(validated.inputPayload).pipe(Effect.mapError(internalFailure(operation)));
490
506
  yield* journal.checkValueBound(operation, inputJson).pipe(Effect.mapError(internalFailure(operation)));
491
507
  const workerAdmissionJson = validated.workerAdmission === void 0 ? null : yield* Schema.encodeEffect(Schema.fromJsonString(WorkerAdmission))(validated.workerAdmission).pipe(Effect.mapError(internalFailure(operation)));
@@ -550,10 +566,10 @@ const makeServices = Effect.fnUntraced(function* () {
550
566
  SELECT worker_admission_json FROM effect_agent_submissions
551
567
  WHERE thread_id=${validated.threadId} ORDER BY queue_sequence LIMIT 1
552
568
  `.pipe(Effect.mapError(sqlFailure(operation)));
553
- 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)));
554
570
  if (first[0] !== void 0) {
555
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)));
556
- 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({
557
573
  reason: "refused",
558
574
  code: "worker-origin-conflict"
559
575
  });
@@ -573,9 +589,10 @@ const makeServices = Effect.fnUntraced(function* () {
573
589
  FROM effect_agent_submissions
574
590
  WHERE thread_id = ${validated.threadId}
575
591
  `.pipe(Effect.mapError(sqlFailure(operation)));
576
- 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)));
577
593
  const queueSequence = yield* decodeQueueSequence((decodedMax[0]?.max_queue_sequence ?? 0) + 1).pipe(Effect.mapError(internalFailure(operation)));
578
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);
579
596
  yield* sql`
580
597
  INSERT INTO effect_agent_submissions (
581
598
  submission_id,
@@ -591,6 +608,7 @@ const makeServices = Effect.fnUntraced(function* () {
591
608
  receipt_id,
592
609
  state,
593
610
  created_at,
611
+ ready_at,
594
612
  parent_submission_id,
595
613
  parent_tool_call_id,
596
614
  admission_group,
@@ -609,8 +627,9 @@ const makeServices = Effect.fnUntraced(function* () {
609
627
  ${inputJson},
610
628
  ${validated.inputDigest},
611
629
  ${mintedReceiptId},
612
- 'admitted',
630
+ ${ready ? "ready" : "admitted"},
613
631
  ${now.iso},
632
+ ${ready ? now.iso : null},
614
633
  ${validated.parentLinkage?.parentSubmissionId ?? null},
615
634
  ${validated.parentLinkage?.parentToolCallId ?? null},
616
635
  ${validated.admissionGroup ?? null},
@@ -622,6 +641,11 @@ const makeServices = Effect.fnUntraced(function* () {
622
641
  if (queueSequence === 1) {
623
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)));
624
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);
625
649
  rows.aborts.seed("submission_id", mintedSubmissionId, []);
626
650
  rows.submissions.seed("joined_host_submission_id", mintedSubmissionId, []);
627
651
  rows.approvals.seed("submission_id", mintedSubmissionId, []);
@@ -629,13 +653,18 @@ const makeServices = Effect.fnUntraced(function* () {
629
653
  rows.childReservations.seed("parent_submission_id", mintedSubmissionId, []);
630
654
  rows.childSettlements.seed("parent_submission_id", mintedSubmissionId, []);
631
655
  yield* recordProgress("submission", operation);
632
- return yield* decodeAdmissionResult({
656
+ const admitted = yield* decodeAdmissionResult({
633
657
  submissionId: mintedSubmissionId,
634
658
  receiptId: mintedReceiptId,
635
659
  queueSequence,
636
- state: "admitted",
660
+ state: ready ? "ready" : "admitted",
637
661
  replayed: false
638
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;
639
668
  }));
640
669
  yield* hitFailpoint("ledger:admit:after", operation);
641
670
  return result;
@@ -685,7 +714,7 @@ const makeServices = Effect.fnUntraced(function* () {
685
714
  }, state.read);
686
715
  const lookup = Effect.fnUntraced(function* (request) {
687
716
  const operation = "ledger lookup";
688
- 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)));
689
718
  if (validated._tag === "SubmissionLookupById") {
690
719
  const row = yield* readSubmission(operation, validated.submissionId);
691
720
  if (Option.isNone(row)) return Option.none();
@@ -708,12 +737,23 @@ const makeServices = Effect.fnUntraced(function* () {
708
737
  });
709
738
  const selectHead = Effect.fn("DoSubmissionLedger.selectHead")(function* (request) {
710
739
  const operation = "ledger select head";
711
- 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)));
712
741
  const attemptId = `attempt-${yield* mintUuid(operation)}`;
713
742
  yield* hitFailpoint("ledger:claim:before", operation);
714
743
  const claimed = yield* owner.withMutation(Effect.gen(function* () {
715
744
  if (owner.hasOwner(validated.threadId)) return Option.none();
716
- 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`
717
757
  SELECT ${submissionColumns}
718
758
  FROM effect_agent_submissions
719
759
  WHERE thread_id = ${validated.threadId}
@@ -727,7 +767,8 @@ const makeServices = Effect.fnUntraced(function* () {
727
767
  ORDER BY queue_sequence ASC
728
768
  LIMIT ${validated.handoff === void 0 ? 1 : validated.handoff.deferredSubmissionIds.length + 1}
729
769
  `.pipe(Effect.mapError(sqlFailure(operation)));
730
- const heads = yield* decodeSubmissionRows(operation, validated.threadId, headRows);
770
+ heads.push(...yield* decodeSubmissionRows(operation, validated.threadId, headRows));
771
+ }
731
772
  if (heads.length === 0) return Option.none();
732
773
  let head = heads[0];
733
774
  if (validated.handoff !== void 0) {
@@ -754,7 +795,7 @@ const makeServices = Effect.fnUntraced(function* () {
754
795
  });
755
796
  const markInputApplied = Effect.fnUntraced(function* (request) {
756
797
  const operation = "ledger mark input applied";
757
- 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)));
758
799
  yield* hitFailpoint("ledger:mark-input-applied:before", operation);
759
800
  yield* inWriteTransaction(operation, Effect.gen(function* () {
760
801
  const submission = yield* requireSubmission(operation, validated.submissionId);
@@ -899,7 +940,7 @@ const makeServices = Effect.fnUntraced(function* () {
899
940
  });
900
941
  const finalizeSettlement = Effect.fn("DoSubmissionLedger.finalizeSettlement")(function* (request) {
901
942
  const operation = "ledger finalize settlement";
902
- 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)));
903
944
  yield* hitFailpoint("ledger:finalize-settlement:before", operation);
904
945
  const replay = yield* state.read(Effect.gen(function* () {
905
946
  const submission = yield* readSubmission(operation, validated.submissionId);
@@ -1059,9 +1100,9 @@ const makeServices = Effect.fnUntraced(function* () {
1059
1100
  });
1060
1101
  const claimJoining = Effect.fnUntraced(function* (request) {
1061
1102
  const operation = "ledger claim joining";
1062
- 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)));
1063
1104
  yield* hitFailpoint("ledger:claim-joining:before", operation);
1064
- const claims = yield* inWriteTransaction(operation, Effect.gen(function* () {
1105
+ const claims = yield* owner.withMutation(Effect.gen(function* () {
1065
1106
  const host = yield* requireSubmission(operation, validated.hostSubmissionId);
1066
1107
  if (host.thread_id !== validated.threadId) return yield* LedgerError.make({
1067
1108
  operation,
@@ -1069,36 +1110,42 @@ const makeServices = Effect.fnUntraced(function* () {
1069
1110
  });
1070
1111
  yield* requireOwner(operation, host);
1071
1112
  if ((yield* cached(rows.workerStops.by("thread_id", validated.threadId), operation)).length > 0) return [];
1072
- const laterRows = yield* sql`
1073
- SELECT ${submissionColumns}
1074
- FROM effect_agent_submissions
1075
- WHERE thread_id = ${validated.threadId}
1076
- AND queue_sequence > ${host.queue_sequence}
1077
- ORDER BY queue_sequence ASC
1078
- `.pipe(Effect.mapError(sqlFailure(operation)));
1079
- const later = yield* decodeSubmissionRows(operation, validated.threadId, laterRows);
1080
- const claimed = [];
1081
- for (const row of later) {
1082
- if (claimed.length >= validated.maxCount) break;
1083
- if ((row.state === "joining" || row.state === "joined") && row.joined_host_submission_id === validated.hostSubmissionId) continue;
1084
- if (row.state === "settled" && row.settled_outcome === "aborted") continue;
1085
- if (row.state !== "ready") break;
1086
- const canonical = yield* readCanonicalSettlement(operation, row);
1087
- if (canonical?.settlement.outcome === "aborted") continue;
1088
- if (canonical !== void 0) break;
1089
- 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`
1090
1136
  UPDATE effect_agent_submissions
1091
1137
  SET state = 'joining', joined_host_submission_id = ${validated.hostSubmissionId}
1092
1138
  WHERE submission_id = ${row.submission_id}
1093
1139
  RETURNING *, ${definitionJson(sql)} AS agent_digests_json`.pipe(rows.submissions.write, Effect.mapError(internalFailure(operation)));
1094
- const inputPayload = yield* parseStoredJsonText(row.input_json).pipe(Effect.mapError((error) => corruptionFailure(operation, "effect_agent_submissions", row.submission_id, error.message)));
1095
- claimed.push(yield* decodeJoiningClaim({
1096
- submissionId: row.submission_id,
1097
- queueSequence: row.queue_sequence,
1098
- inputPayload
1099
- }).pipe(Effect.mapError(internalFailure(operation))));
1100
- }
1101
- 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
+ }));
1102
1149
  }));
1103
1150
  yield* hitFailpoint("ledger:claim-joining:after", operation);
1104
1151
  return claims;
@@ -1668,20 +1715,21 @@ const makeServices = Effect.fnUntraced(function* () {
1668
1715
  ORDER BY thread_id ASC, queue_sequence ASC
1669
1716
  LIMIT ${SCAN_PAGE_SIZE}
1670
1717
  `).pipe(Effect.mapError(sqlFailure(operation)));
1671
- 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)));
1672
1719
  const last = decoded[decoded.length - 1];
1673
1720
  return [decoded, last === void 0 || decoded.length < SCAN_PAGE_SIZE ? Option.none() : Option.some({
1674
1721
  threadId: last.threadId,
1675
1722
  queueSequence: last.queueSequence
1676
1723
  })];
1677
1724
  });
1678
- const scanNonterminal = Stream.unwrap(state.read(Effect.gen(function* () {
1679
- const active = yield* cached(workRows.matching("nonterminal", (row) => row.state !== "settled", sql`SELECT submission_id, thread_id, queue_sequence, principal, idempotency_key,
1680
- deployment_id, receipt_id, state
1681
- FROM effect_agent_submissions WHERE state <> 'settled' LIMIT 129`, 128), "ledger scan nonterminal");
1682
- 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;
1683
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);
1684
- const work = yield* Schema.decodeEffect(Schema.Array(SubmissionWorkItem))(sorted.map((row) => ({
1732
+ return yield* decodeSubmissionWorkItems(sorted.map((row) => ({
1685
1733
  submissionId: row.submission_id,
1686
1734
  threadId: row.thread_id,
1687
1735
  queueSequence: row.queue_sequence,
@@ -1691,11 +1739,13 @@ const makeServices = Effect.fnUntraced(function* () {
1691
1739
  receiptId: row.receipt_id,
1692
1740
  state: row.state
1693
1741
  }))).pipe(Effect.mapError(internalFailure("ledger scan nonterminal")));
1694
- return Stream.fromIterable(work);
1695
- })));
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));
1696
1746
  const readAbortIntentForSubmission = Effect.fnUntraced(function* (request) {
1697
1747
  const operation = "ledger read abort intent";
1698
- 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)));
1699
1749
  return yield* state.read(Effect.gen(function* () {
1700
1750
  const submission = yield* requireSubmission(operation, validated.submissionId);
1701
1751
  const intent = yield* readAbortIntent(operation, validated.submissionId);
@@ -1704,7 +1754,7 @@ const makeServices = Effect.fnUntraced(function* () {
1704
1754
  });
1705
1755
  const loadRecoverySnapshot = Effect.fnUntraced(function* (request) {
1706
1756
  const operation = "ledger load recovery snapshot";
1707
- 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)));
1708
1758
  return yield* state.read(Effect.gen(function* () {
1709
1759
  const submissionRow = yield* requireSubmission(operation, validated.submissionId);
1710
1760
  const submission = yield* decodeSubmissionSnapshot(operation, submissionRow);
@@ -1811,6 +1861,7 @@ const makeServices = Effect.fnUntraced(function* () {
1811
1861
  beginChildBudgetRelease,
1812
1862
  releaseChildBudget,
1813
1863
  scanNonterminal,
1864
+ listNonterminal,
1814
1865
  loadRecoverySnapshot,
1815
1866
  readAbortIntent: readAbortIntentForSubmission
1816
1867
  })).pipe(Context.add(StorageOwner, owner), Context.add(SettlementPublisher, { publish }));