@sekiban/dcb-runtime 0.2.0 → 0.2.1

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/README.md +5 -1
  2. package/dist/allocator/AllocatorDurableObject.js +25 -2
  3. package/dist/bootstrap/BootstrapCoordinatorDurableObject.d.ts +2 -0
  4. package/dist/bootstrap/BootstrapCoordinatorDurableObject.js +64 -1
  5. package/dist/bootstrap/types.d.ts +6 -0
  6. package/dist/cloudflare.d.ts +3 -0
  7. package/dist/cloudflare.js +1493 -451
  8. package/dist/commit/CommitWorker.d.ts +19 -0
  9. package/dist/commit/CommitWorker.js +176 -27
  10. package/dist/completeness/IncidentLifecycle.d.ts +75 -0
  11. package/dist/completeness/IncidentLifecycle.js +503 -0
  12. package/dist/completeness/types.d.ts +67 -0
  13. package/dist/cosmos.d.ts +34 -4
  14. package/dist/cosmos.js +214 -49
  15. package/dist/downstream/OutboxDrain.d.ts +4 -1
  16. package/dist/downstream/OutboxDrain.js +24 -2
  17. package/dist/generated/cosmos-layout.d.ts +87 -0
  18. package/dist/generated/cosmos-layout.js +99 -0
  19. package/dist/http/IncidentMaintenance.d.ts +8 -0
  20. package/dist/http/IncidentMaintenance.js +145 -0
  21. package/dist/index.d.ts +11 -0
  22. package/dist/index.js +1548 -451
  23. package/dist/read/SerializedReadWorker.d.ts +3 -0
  24. package/dist/read/SerializedReadWorker.js +3 -3
  25. package/dist/shard/ShardRotation.d.ts +48 -0
  26. package/dist/shard/ShardRotation.js +120 -0
  27. package/dist/store/CosmosEventStore.js +56 -46
  28. package/dist/store/PostgresEventStore.d.ts +20 -0
  29. package/dist/store/PostgresEventStore.js +53 -0
  30. package/dist/store/provider.d.ts +4 -0
  31. package/dist/tag/TagDurableObject.js +66 -14
  32. package/dist/tag/TagSqlSchema.d.ts +6 -1
  33. package/dist/tag/TagSqlSchema.js +15 -0
  34. package/dist/tag/types.d.ts +9 -0
  35. package/dist/trace/CommitTrace.d.ts +3 -3
  36. package/dist/trace/CommitTraceVerifier.js +1 -1
  37. package/package.json +6 -15
package/dist/index.js CHANGED
@@ -942,15 +942,15 @@ function encodeOrderOrdinal(value) {
942
942
  function decodeOrderOrdinal(value) {
943
943
  try {
944
944
  return assertSortableUniqueId(value).ticks;
945
- } catch (error10) {
946
- const detail = error10 instanceof Error ? error10.message : "invalid SortableUniqueId";
947
- throw new OrderClockReadError(detail, { cause: error10 });
945
+ } catch (error11) {
946
+ const detail = error11 instanceof Error ? error11.message : "invalid SortableUniqueId";
947
+ throw new OrderClockReadError(detail, { cause: error11 });
948
948
  }
949
949
  }
950
- function asOrderClockError(error10) {
951
- if (error10 instanceof OrderClockReadError) return error10;
952
- const detail = error10 instanceof Error ? error10.message : "SortableUniqueId allocation failed";
953
- return new OrderClockReadError(detail, { cause: error10 });
950
+ function asOrderClockError(error11) {
951
+ if (error11 instanceof OrderClockReadError) return error11;
952
+ const detail = error11 instanceof Error ? error11.message : "SortableUniqueId allocation failed";
953
+ return new OrderClockReadError(detail, { cause: error11 });
954
954
  }
955
955
  function allocateOrderRange(watermark, count, clockTick, options = {}) {
956
956
  if (!Number.isSafeInteger(count) || count <= 0) {
@@ -979,9 +979,9 @@ function allocateOrderRange(watermark, count, clockTick, options = {}) {
979
979
  watermark: suids.at(-1),
980
980
  suids: Object.freeze(suids)
981
981
  });
982
- } catch (error10) {
983
- if (error10 instanceof SortableUniqueIdError) throw error10;
984
- throw asOrderClockError(error10);
982
+ } catch (error11) {
983
+ if (error11 instanceof SortableUniqueIdError) throw error11;
984
+ throw asOrderClockError(error11);
985
985
  }
986
986
  }
987
987
  function diagnosticAllocatedAt(ticks) {
@@ -999,7 +999,7 @@ function diagnosticAllocatedAt(ticks) {
999
999
  var commit_trace_manifest_default = {
1000
1000
  schemaVersion: 2,
1001
1001
  name: "commit-trace-manifest",
1002
- description: "Authority for the sdt.commit span manifests. means/19 links to RENDERED-VIEWS.md; it does not duplicate these tables.",
1002
+ description: "Repository-owned authority for the sdt.commit span manifests. The generated views are kept in RENDERED-VIEWS.md; the manifest does not duplicate those tables.",
1003
1003
  remoteInvocationUniverse: [
1004
1004
  "S16"
1005
1005
  ],
@@ -3412,9 +3412,9 @@ var commit_trace_manifest_default = {
3412
3412
 
3413
3413
  // src/trace/AttributionRatio.ts
3414
3414
  function failure(code, message) {
3415
- const error10 = new Error(`${code}:${message}`);
3416
- error10.name = "CommitTraceAttributionError";
3417
- throw error10;
3415
+ const error11 = new Error(`${code}:${message}`);
3416
+ error11.name = "CommitTraceAttributionError";
3417
+ throw error11;
3418
3418
  }
3419
3419
  function clip(interval, root) {
3420
3420
  const start = Math.max(interval[0], root[0]);
@@ -3731,8 +3731,8 @@ var CommitTrace = class {
3731
3731
  unattributed,
3732
3732
  attributionGatePassed: unattributed.unattributedRatio <= 0.05
3733
3733
  });
3734
- } catch (error10) {
3735
- this.noteObservationFailure(error10);
3734
+ } catch (error11) {
3735
+ this.noteObservationFailure(error11);
3736
3736
  return Object.freeze({
3737
3737
  ...base,
3738
3738
  runtimeVerification: this.observationVerification()
@@ -3799,9 +3799,9 @@ var CommitTrace = class {
3799
3799
  throw new Error(`Commit trace root ${rowId} is not active`);
3800
3800
  }
3801
3801
  attributes = this.attributesFor(row, options);
3802
- } catch (error10) {
3803
- if (!this.isFailOpen()) throw error10;
3804
- this.noteObservationFailure(error10);
3802
+ } catch (error11) {
3803
+ if (!this.isFailOpen()) throw error11;
3804
+ this.noteObservationFailure(error11);
3805
3805
  return callback(disabledChild());
3806
3806
  }
3807
3807
  const execute = async (native2) => {
@@ -3927,8 +3927,8 @@ var CommitTrace = class {
3927
3927
  for (const [key, value] of Object.entries(attributes)) {
3928
3928
  try {
3929
3929
  native.setAttribute(key, value);
3930
- } catch (error10) {
3931
- this.noteObservationFailure(error10);
3930
+ } catch (error11) {
3931
+ this.noteObservationFailure(error11);
3932
3932
  }
3933
3933
  }
3934
3934
  }
@@ -3945,8 +3945,8 @@ var CommitTrace = class {
3945
3945
  now() {
3946
3946
  try {
3947
3947
  return this.clock().now();
3948
- } catch (error10) {
3949
- this.noteObservationFailure(error10);
3948
+ } catch (error11) {
3949
+ this.noteObservationFailure(error11);
3950
3950
  return Date.now();
3951
3951
  }
3952
3952
  }
@@ -3954,8 +3954,8 @@ var CommitTrace = class {
3954
3954
  let beforeVerification;
3955
3955
  try {
3956
3956
  beforeVerification = this.snapshot();
3957
- } catch (error10) {
3958
- this.noteObservationFailure(error10);
3957
+ } catch (error11) {
3958
+ this.noteObservationFailure(error11);
3959
3959
  return;
3960
3960
  }
3961
3961
  if (this.options.runtimeVerifier !== void 0) {
@@ -3966,15 +3966,15 @@ var CommitTrace = class {
3966
3966
  this.options.runtimeVerifier.verify(beforeVerification);
3967
3967
  this.runtimeVerification = Object.freeze({ passed: true });
3968
3968
  }
3969
- } catch (error10) {
3970
- const code = typeof error10 === "object" && error10 !== null && "code" in error10 && typeof error10.code === "string" ? error10.code : "runtime-verifier-error";
3969
+ } catch (error11) {
3970
+ const code = typeof error11 === "object" && error11 !== null && "code" in error11 && typeof error11.code === "string" ? error11.code : "runtime-verifier-error";
3971
3971
  this.runtimeVerification = Object.freeze({ passed: false, code });
3972
3972
  }
3973
3973
  }
3974
3974
  try {
3975
3975
  this.options.sink?.record(this.snapshot());
3976
- } catch (error10) {
3977
- this.noteObservationFailure(error10);
3976
+ } catch (error11) {
3977
+ this.noteObservationFailure(error11);
3978
3978
  }
3979
3979
  }
3980
3980
  /**
@@ -3986,8 +3986,8 @@ var CommitTrace = class {
3986
3986
  async scheduleDetachedObservation() {
3987
3987
  try {
3988
3988
  await this.options.scheduleDetachedObservation?.();
3989
- } catch (error10) {
3990
- this.noteObservationFailure(error10);
3989
+ } catch (error11) {
3990
+ this.noteObservationFailure(error11);
3991
3991
  }
3992
3992
  }
3993
3993
  isFailOpen() {
@@ -3996,9 +3996,9 @@ var CommitTrace = class {
3996
3996
  observationVerification() {
3997
3997
  return Object.freeze({ passed: false, code: this.observationFailureCode ?? "trace-observation-error" });
3998
3998
  }
3999
- noteObservationFailure(error10) {
3999
+ noteObservationFailure(error11) {
4000
4000
  if (this.observationFailureCode !== void 0) return;
4001
- this.observationFailureCode = typeof error10 === "object" && error10 !== null && "code" in error10 && typeof error10.code === "string" ? error10.code : "trace-observation-error";
4001
+ this.observationFailureCode = typeof error11 === "object" && error11 !== null && "code" in error11 && typeof error11.code === "string" ? error11.code : "trace-observation-error";
4002
4002
  this.runtimeVerification = this.observationVerification();
4003
4003
  }
4004
4004
  /**
@@ -4019,9 +4019,9 @@ var CommitTrace = class {
4019
4019
  return callback(void 0);
4020
4020
  }
4021
4021
  return await result2;
4022
- } catch (error10) {
4023
- if (callbackStarted) throw error10;
4024
- this.noteObservationFailure(error10);
4022
+ } catch (error11) {
4023
+ if (callbackStarted) throw error11;
4024
+ this.noteObservationFailure(error11);
4025
4025
  return callback(void 0);
4026
4026
  }
4027
4027
  }
@@ -4119,8 +4119,8 @@ async function enterNativeSpanFailOpen(nativeTracing, name, callback) {
4119
4119
  const result2 = nativeTracing.enterSpan(name, wrapped);
4120
4120
  if (!callbackStarted) return callback(void 0);
4121
4121
  return await result2;
4122
- } catch (error10) {
4123
- if (callbackStarted) throw error10;
4122
+ } catch (error11) {
4123
+ if (callbackStarted) throw error11;
4124
4124
  return callback(void 0);
4125
4125
  }
4126
4126
  }
@@ -4152,9 +4152,9 @@ async function enterNativeCommitSpan(nativeTracing, name, input, callback) {
4152
4152
  if (response3 !== void 0 && input.face !== "reconcile-root") setNativeAttribute(span, "http.status", response3.status);
4153
4153
  }
4154
4154
  return result2;
4155
- } catch (error10) {
4155
+ } catch (error11) {
4156
4156
  setNativeAttribute(span, "outcome", "exception");
4157
- throw error10;
4157
+ throw error11;
4158
4158
  }
4159
4159
  });
4160
4160
  }
@@ -4193,9 +4193,9 @@ async function enterNativeActorHandleSpan(nativeTracing, input, resolveIdentity,
4193
4193
  if (response3 !== void 0) setNativeAttribute(span, "http.status", response3.status);
4194
4194
  }
4195
4195
  return result2;
4196
- } catch (error10) {
4196
+ } catch (error11) {
4197
4197
  if (identity2 !== void 0) setNativeAttribute(span, "outcome", "exception");
4198
- throw error10;
4198
+ throw error11;
4199
4199
  } finally {
4200
4200
  input.observation?.finish();
4201
4201
  }
@@ -4260,9 +4260,9 @@ async function enterNativeReconcileRootSpan(nativeTracing, resolveIdentity, call
4260
4260
  const result2 = await callback(identity2, facts);
4261
4261
  finish("success");
4262
4262
  return result2;
4263
- } catch (error10) {
4263
+ } catch (error11) {
4264
4264
  finish("exception");
4265
- throw error10;
4265
+ throw error11;
4266
4266
  }
4267
4267
  });
4268
4268
  }
@@ -4373,6 +4373,8 @@ var ATTEMPT_KEY_PREFIX2 = "attempt:";
4373
4373
  var ROLLBACK_WARNING_WINDOW_MS = 1000n;
4374
4374
  var AllocationTransactionFault = class extends Error {
4375
4375
  };
4376
+ var ImportSeedRequiredError = class extends Error {
4377
+ };
4376
4378
  function json(body, status = 200) {
4377
4379
  return new Response(JSON.stringify(body), {
4378
4380
  status,
@@ -4412,7 +4414,17 @@ function seedFrom(value) {
4412
4414
  } catch {
4413
4415
  return { error: "highWatermark must be an allocator SUID" };
4414
4416
  }
4415
- return { value: { importId: value.importId, leaseEpoch: value.leaseEpoch, highWatermark: value.highWatermark } };
4417
+ let storeMaximum;
4418
+ if (value.storeMaximum !== void 0) {
4419
+ if (!isNonEmptyString2(value.storeMaximum)) return { error: "storeMaximum must be an allocator SUID" };
4420
+ try {
4421
+ decodeSuid(value.storeMaximum);
4422
+ } catch {
4423
+ return { error: "storeMaximum must be an allocator SUID" };
4424
+ }
4425
+ storeMaximum = value.storeMaximum;
4426
+ }
4427
+ return { value: { importId: value.importId, leaseEpoch: value.leaseEpoch, highWatermark: value.highWatermark, ...storeMaximum !== void 0 ? { storeMaximum } : {} } };
4416
4428
  }
4417
4429
  function newAllocatorLineageId() {
4418
4430
  return crypto.randomUUID();
@@ -4467,7 +4479,8 @@ function allocateFrom(value) {
4467
4479
  faultInjection,
4468
4480
  ...serviceId !== void 0 ? { serviceId } : {},
4469
4481
  ...bootstrapCommandId !== void 0 ? { bootstrapCommandId } : {},
4470
- ...bootstrapEpoch !== void 0 ? { bootstrapEpoch } : {}
4482
+ ...bootstrapEpoch !== void 0 ? { bootstrapEpoch } : {},
4483
+ ...value.requiresImportSeed === true ? { requiresImportSeed: true } : {}
4471
4484
  }
4472
4485
  };
4473
4486
  }
@@ -4852,11 +4865,12 @@ var AllocatorDurableObject = class {
4852
4865
  };
4853
4866
  }
4854
4867
  const state = persistedState === void 0 ? currentState(lineage) : { ...persistedState, allocatorLineageId: lineage, schemaVersion: 5, bootstrapSeed: persistedState.bootstrapSeed ?? null, lastRollbackWarningFingerprint: persistedState.lastRollbackWarningFingerprint ?? null };
4868
+ if (input.requiresImportSeed === true && state.bootstrapSeed === null) throw new ImportSeedRequiredError();
4855
4869
  let clockTick;
4856
4870
  try {
4857
4871
  clockTick = this.orderClock.tick();
4858
- } catch (error10) {
4859
- throw error10 instanceof OrderClockReadError ? error10 : new OrderClockReadError("Order clock failed before allocation write", { cause: error10 });
4872
+ } catch (error11) {
4873
+ throw error11 instanceof OrderClockReadError ? error11 : new OrderClockReadError("Order clock failed before allocation write", { cause: error11 });
4860
4874
  }
4861
4875
  const range = allocateOrderRange(state.allocatedWatermark, input.candidates.length, clockTick);
4862
4876
  const rollback = range.observedTicks !== null && range.physicalTicks < range.observedTicks;
@@ -4930,6 +4944,9 @@ var AllocatorDurableObject = class {
4930
4944
  }
4931
4945
  return json(result2.vector, result2.created ? 201 : 200);
4932
4946
  } catch (failure3) {
4947
+ if (failure3 instanceof ImportSeedRequiredError) {
4948
+ return error(409, "allocator_seed_required", "commit before import seed");
4949
+ }
4933
4950
  if (failure3 instanceof AllocationTransactionFault) {
4934
4951
  return error(
4935
4952
  503,
@@ -4970,7 +4987,10 @@ var AllocatorDurableObject = class {
4970
4987
  return { status: 409, body: { code: "allocator_seed_rejected", error: "allocator already seeded" } };
4971
4988
  }
4972
4989
  if (state.allocatedWatermark !== null) return { status: 409, body: { code: "allocator_seed_rejected", error: "allocator already allocating" } };
4973
- const updated = { ...state, allocatedWatermark: input.highWatermark, bootstrapSeed: input };
4990
+ if (input.storeMaximum !== void 0 && input.highWatermark < input.storeMaximum) {
4991
+ return { status: 409, body: { code: "allocator_seed_below_store_max", error: "seed below store maximum" } };
4992
+ }
4993
+ const updated = { ...state, allocatedWatermark: input.highWatermark, bootstrapSeed: { importId: input.importId, leaseEpoch: input.leaseEpoch, highWatermark: input.highWatermark } };
4974
4994
  await txn.put(STATE_KEY, updated);
4975
4995
  return { status: 201, body: updated };
4976
4996
  });
@@ -4995,7 +5015,7 @@ var isPlainRecord = (value) => {
4995
5015
  return prototype === Object.prototype || prototype === null;
4996
5016
  };
4997
5017
  function assertJsonValue(value, boundary = "value") {
4998
- const active = /* @__PURE__ */ new WeakSet();
5018
+ const active2 = /* @__PURE__ */ new WeakSet();
4999
5019
  const visit = (candidate, path) => {
5000
5020
  if (candidate === null || typeof candidate === "string" || typeof candidate === "boolean") {
5001
5021
  return candidate;
@@ -5007,10 +5027,10 @@ function assertJsonValue(value, boundary = "value") {
5007
5027
  if (typeof candidate !== "object") {
5008
5028
  throw new JsonValidationError(`Value at ${path} is not JSON serializable`, boundary, path);
5009
5029
  }
5010
- if (active.has(candidate)) {
5030
+ if (active2.has(candidate)) {
5011
5031
  throw new JsonValidationError(`Cyclic JSON value at ${path}`, boundary, path);
5012
5032
  }
5013
- active.add(candidate);
5033
+ active2.add(candidate);
5014
5034
  try {
5015
5035
  if (Array.isArray(candidate)) {
5016
5036
  return candidate.map((item, index) => visit(item, `${path}[${index}]`));
@@ -5024,7 +5044,7 @@ function assertJsonValue(value, boundary = "value") {
5024
5044
  }
5025
5045
  return result2;
5026
5046
  } finally {
5027
- active.delete(candidate);
5047
+ active2.delete(candidate);
5028
5048
  }
5029
5049
  };
5030
5050
  return visit(value, "$");
@@ -5119,16 +5139,16 @@ function createUuidV7(nowMs = Date.now()) {
5119
5139
  if (typeof globalThis.crypto?.getRandomValues !== "function") {
5120
5140
  throw new Error("crypto.getRandomValues is required for UUIDv7");
5121
5141
  }
5122
- const bytes = new Uint8Array(16);
5123
- globalThis.crypto.getRandomValues(bytes);
5142
+ const bytes2 = new Uint8Array(16);
5143
+ globalThis.crypto.getRandomValues(bytes2);
5124
5144
  let time = BigInt(nowMs);
5125
5145
  for (let index = 5; index >= 0; index -= 1) {
5126
- bytes[index] = Number(time & 0xffn);
5146
+ bytes2[index] = Number(time & 0xffn);
5127
5147
  time >>= 8n;
5128
5148
  }
5129
- bytes[6] = bytes[6] & 15 | 112;
5130
- bytes[8] = bytes[8] & 63 | 128;
5131
- const hex = [...bytes].map((value) => value.toString(16).padStart(2, "0")).join("");
5149
+ bytes2[6] = bytes2[6] & 15 | 112;
5150
+ bytes2[8] = bytes2[8] & 63 | 128;
5151
+ const hex = [...bytes2].map((value) => value.toString(16).padStart(2, "0")).join("");
5132
5152
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
5133
5153
  }
5134
5154
  function isRfc4122Uuid(value) {
@@ -5244,7 +5264,7 @@ var epoch = (value) => typeof value === "number" && Number.isSafeInteger(value)
5244
5264
  var response = (body, status = 200) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json; charset=utf-8" } });
5245
5265
  var reject = (code, message, status = 409) => response({ code, error: message }, status);
5246
5266
  function empty(serviceId) {
5247
- return { schemaVersion: 1, status: "EMPTY", importId: null, targetServiceId: serviceId, allocatorLineageId: null, source: null, digest: null, manifest: null, progress: {}, leaseEpoch: 0, leaseUntil: null, failure: null, readyAt: null, normalInFlight: 0, normalCommands: {}, releasedCommands: {}, verifiedImportId: null, verifiedLeaseEpoch: null, storeCompletion: null };
5267
+ return { schemaVersion: 1, status: "EMPTY", importId: null, targetServiceId: serviceId, allocatorLineageId: null, source: null, digest: null, manifest: null, progress: {}, leaseEpoch: 0, leaseUntil: null, failure: null, readyAt: null, normalInFlight: 0, normalCommands: {}, releasedCommands: {}, writePermits: {}, verifiedImportId: null, verifiedLeaseEpoch: null, storeCompletion: null };
5248
5268
  }
5249
5269
  function expired(control) {
5250
5270
  return control.leaseUntil !== null && control.leaseUntil <= Date.now();
@@ -5255,12 +5275,22 @@ function commands(control) {
5255
5275
  function released(control) {
5256
5276
  return { ...control.releasedCommands ?? {} };
5257
5277
  }
5278
+ function permits(control) {
5279
+ return { ...control.writePermits ?? {} };
5280
+ }
5258
5281
  function fault(body, point) {
5259
5282
  return object(body) && body.faultAt === point;
5260
5283
  }
5261
5284
  function encodedBytes(value) {
5262
5285
  return new TextEncoder().encode(JSON.stringify(value)).byteLength;
5263
5286
  }
5287
+ async function readBody(request) {
5288
+ try {
5289
+ return await request.json();
5290
+ } catch {
5291
+ return void 0;
5292
+ }
5293
+ }
5264
5294
  var BootstrapCoordinatorDurableObject = class {
5265
5295
  constructor(ctx, env, nativeTracing = noOpNativeTracing) {
5266
5296
  this.ctx = ctx;
@@ -5282,6 +5312,8 @@ var BootstrapCoordinatorDurableObject = class {
5282
5312
  if (request.method === "POST" && url.pathname === "/command/admit") return this.traceCommand(request, serviceId, activation, observation, "admit");
5283
5313
  if (request.method === "POST" && url.pathname === "/command/finalize") return this.traceCommand(request, serviceId, activation, observation, "finalize");
5284
5314
  if (request.method === "POST" && url.pathname === "/command/release") return this.traceCommand(request, serviceId, activation, observation, "release");
5315
+ if (request.method === "POST" && url.pathname === "/command/permit") return this.permit(serviceId, await readBody(request));
5316
+ if (request.method === "POST" && url.pathname === "/command/permit-release") return this.permitRelease(serviceId, await readBody(request));
5285
5317
  let body;
5286
5318
  try {
5287
5319
  body = await request.json();
@@ -5338,6 +5370,7 @@ var BootstrapCoordinatorDurableObject = class {
5338
5370
  const control = await txn.get(CONTROL) ?? empty(serviceId);
5339
5371
  if (control.status === "READY") return { error: "bootstrap_ready_permanent" };
5340
5372
  if (control.status !== "EMPTY") return control.importId === importId && control.digest === dump.manifest.contentDigest ? { control } : { error: "bootstrap_plan_conflict" };
5373
+ if (Object.keys(permits(control)).length !== 0) return { error: "bootstrap_write_permit_active" };
5341
5374
  if (control.normalInFlight !== 0 || Object.keys(commands(control)).length !== 0) return { error: "bootstrap_normal_command_in_flight" };
5342
5375
  const next = { ...control, status: "PLANNED", importId, allocatorLineageId: dump.manifest.target.allocatorLineageId, source: dump.manifest.source, digest: dump.manifest.contentDigest, manifest: dump.manifest, leaseEpoch: control.leaseEpoch + 1, leaseUntil: Date.now() + 3e4, failure: null, progress: {}, verifiedImportId: null, verifiedLeaseEpoch: null, storeCompletion: null };
5343
5376
  await txn.put(CONTROL, next);
@@ -5350,17 +5383,17 @@ var BootstrapCoordinatorDurableObject = class {
5350
5383
  chunks(events) {
5351
5384
  const chunks = [];
5352
5385
  let current = [];
5353
- let bytes = 0;
5386
+ let bytes2 = 0;
5354
5387
  for (const event of events) {
5355
5388
  const eventBytes = encodedBytes(event);
5356
5389
  if (eventBytes > MAX_CHUNK_BYTES) throw new Error("bootstrap event exceeds encoded chunk bound");
5357
- if (current.length === MAX_CHUNK_EVENTS || bytes + eventBytes > MAX_CHUNK_BYTES) {
5390
+ if (current.length === MAX_CHUNK_EVENTS || bytes2 + eventBytes > MAX_CHUNK_BYTES) {
5358
5391
  chunks.push(current);
5359
5392
  current = [];
5360
- bytes = 0;
5393
+ bytes2 = 0;
5361
5394
  }
5362
5395
  current.push(event);
5363
- bytes += eventBytes;
5396
+ bytes2 += eventBytes;
5364
5397
  }
5365
5398
  if (current.length > 0) chunks.push(current);
5366
5399
  return chunks;
@@ -5506,6 +5539,45 @@ var BootstrapCoordinatorDurableObject = class {
5506
5539
  const control = await this.control(serviceId);
5507
5540
  return control.status === "EMPTY" || control.status === "READY" ? response({ admitted: true, leaseEpoch: control.leaseEpoch, route: body.route }) : reject("bootstrap_route_rejected", `${body.route} is unavailable during bootstrap`);
5508
5541
  }
5542
+ async permit(serviceId, body) {
5543
+ if (!object(body) || !string(body.commandId) || !string(body.digest)) return reject("bootstrap_permit_invalid", "commandId and digest are required", 400);
5544
+ const commandId = body.commandId;
5545
+ const digest2 = body.digest;
5546
+ const result2 = await this.ctx.storage.transaction(async (txn) => {
5547
+ const control = await txn.get(CONTROL) ?? empty(serviceId);
5548
+ const active2 = permits(control);
5549
+ if (active2[commandId] !== void 0) {
5550
+ return active2[commandId] === digest2 ? { control } : { digestMismatch: true };
5551
+ }
5552
+ if (control.status !== "EMPTY" && control.status !== "READY") return { rejected: true };
5553
+ const updated = { ...control, writePermits: { ...active2, [commandId]: digest2 } };
5554
+ await txn.put(CONTROL, updated);
5555
+ return { control: updated };
5556
+ });
5557
+ if ("digestMismatch" in result2) return reject("bootstrap_permit_digest_mismatch", "bootstrap permit digest does not match the held permit");
5558
+ if ("rejected" in result2) return reject("bootstrap_command_rejected", "bootstrap epoch rejects normal durable mutation");
5559
+ return response({ leaseEpoch: result2.control.leaseEpoch, admitted: true });
5560
+ }
5561
+ async permitRelease(serviceId, body) {
5562
+ if (!object(body) || !string(body.commandId)) return reject("bootstrap_permit_invalid", "commandId is required", 400);
5563
+ const commandId = body.commandId;
5564
+ const digest2 = string(body.digest) ? body.digest : void 0;
5565
+ const result2 = await this.ctx.storage.transaction(async (txn) => {
5566
+ const control = await txn.get(CONTROL) ?? empty(serviceId);
5567
+ const active2 = permits(control);
5568
+ if (active2[commandId] !== void 0 && digest2 !== void 0 && active2[commandId] !== digest2) {
5569
+ return { digestMismatch: true };
5570
+ }
5571
+ if (active2[commandId] === void 0) return { control };
5572
+ const next = { ...active2 };
5573
+ delete next[commandId];
5574
+ const updated = { ...control, writePermits: next };
5575
+ await txn.put(CONTROL, updated);
5576
+ return { control: updated };
5577
+ });
5578
+ if ("digestMismatch" in result2) return reject("bootstrap_permit_digest_mismatch", "bootstrap permit digest does not match the held permit");
5579
+ return response({ leaseEpoch: result2.control.leaseEpoch, admitted: true });
5580
+ }
5509
5581
  async command(serviceId, body, action, observation) {
5510
5582
  if (!object(body) || !string(body.commandId)) return reject("bootstrap_command_invalid", "commandId is required", 400);
5511
5583
  const commandId = body.commandId;
@@ -5571,13 +5643,13 @@ function byteCompare(left, right) {
5571
5643
  }
5572
5644
  function concat(parts) {
5573
5645
  const length = parts.reduce((total, part) => total + part.byteLength, 0);
5574
- const bytes = new Uint8Array(length);
5646
+ const bytes2 = new Uint8Array(length);
5575
5647
  let offset = 0;
5576
5648
  for (const part of parts) {
5577
- bytes.set(part, offset);
5649
+ bytes2.set(part, offset);
5578
5650
  offset += part.byteLength;
5579
5651
  }
5580
- return bytes;
5652
+ return bytes2;
5581
5653
  }
5582
5654
  function lengthPrefix(length) {
5583
5655
  if (!Number.isSafeInteger(length) || length < 0 || length > 4294967295) {
@@ -5606,8 +5678,8 @@ function requiredUtf8(input, name) {
5606
5678
  function tagSetBytes(tags) {
5607
5679
  const canonical2 = canonicalDeclaredTagSet(tags);
5608
5680
  return concat(canonical2.map((tag) => {
5609
- const bytes = utf8(tag);
5610
- return concat([lengthPrefix(bytes.byteLength), bytes]);
5681
+ const bytes2 = utf8(tag);
5682
+ return concat([lengthPrefix(bytes2.byteLength), bytes2]);
5611
5683
  }));
5612
5684
  }
5613
5685
  function canonicalDeclaredTagSet(tags) {
@@ -5677,16 +5749,16 @@ function eventDigestBytes(input) {
5677
5749
  ]);
5678
5750
  }
5679
5751
  async function eventDigestHex(input) {
5680
- const bytes = eventDigestBytes(input);
5681
- const source = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
5682
- const digest = await crypto.subtle.digest("SHA-256", source);
5683
- return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
5752
+ const bytes2 = eventDigestBytes(input);
5753
+ const source = bytes2.buffer.slice(bytes2.byteOffset, bytes2.byteOffset + bytes2.byteLength);
5754
+ const digest2 = await crypto.subtle.digest("SHA-256", source);
5755
+ return [...new Uint8Array(digest2)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
5684
5756
  }
5685
5757
 
5686
5758
  // src/bootstrap/BootstrapStoreAdapter.ts
5687
- function arrayBufferBase64(bytes) {
5759
+ function arrayBufferBase64(bytes2) {
5688
5760
  let binary = "";
5689
- for (const byte of bytes) binary += String.fromCharCode(byte);
5761
+ for (const byte of bytes2) binary += String.fromCharCode(byte);
5690
5762
  return btoa(binary);
5691
5763
  }
5692
5764
  var BootstrapIdentityConflictError = class extends Error {
@@ -6797,6 +6869,22 @@ var COMMIT_TEST_FAULTS = [
6797
6869
  var INITIAL_OWNER_EPOCH = 0;
6798
6870
  var MAX_WRITE_ATTEMPTS = 2;
6799
6871
  var OUTCOME_UNDETERMINED_ERROR = "Commit outcome is undetermined; reread tag heads and event/query state before retrying because blind retry may create duplicate events.";
6872
+ function commitPermitDigest(allTags, candidates) {
6873
+ const normalized = JSON.stringify({
6874
+ tags: [...allTags].sort(),
6875
+ events: candidates.map((candidate) => ({
6876
+ eventId: candidate.eventId,
6877
+ payload: candidate.payload,
6878
+ tags: [...candidate.tags].sort()
6879
+ })).sort((left, right) => left.eventId < right.eventId ? -1 : left.eventId > right.eventId ? 1 : 0)
6880
+ });
6881
+ let hash = 2166136261;
6882
+ for (let index = 0; index < normalized.length; index += 1) {
6883
+ hash ^= normalized.charCodeAt(index);
6884
+ hash = Math.imul(hash, 16777619) >>> 0;
6885
+ }
6886
+ return `fnv1a32:${hash.toString(16).padStart(8, "0")}`;
6887
+ }
6800
6888
  var GLOBAL_ADMISSION_HEADER = "x-sdt-global-admission";
6801
6889
  var runtimeCommitTraceVerifier = {
6802
6890
  verify(snapshot) {
@@ -6850,19 +6938,19 @@ var CommitPayloadAdmissionError = class extends Error {
6850
6938
  code;
6851
6939
  };
6852
6940
  function decodeBase64Utf8Json(value) {
6853
- let bytes;
6941
+ let bytes2;
6854
6942
  try {
6855
6943
  const binary = atob(value);
6856
- bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
6944
+ bytes2 = Uint8Array.from(binary, (character) => character.charCodeAt(0));
6857
6945
  } catch {
6858
6946
  throw new CommitPayloadAdmissionError("invalid_payload_utf8", "Payload base64 could not be decoded");
6859
6947
  }
6860
- if (bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) {
6948
+ if (bytes2[0] === 239 && bytes2[1] === 187 && bytes2[2] === 191) {
6861
6949
  throw new CommitPayloadAdmissionError("invalid_payload_utf8", "Payload must not start with a UTF-8 BOM");
6862
6950
  }
6863
6951
  let text;
6864
6952
  try {
6865
- text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
6953
+ text = new TextDecoder("utf-8", { fatal: true }).decode(bytes2);
6866
6954
  } catch {
6867
6955
  throw new CommitPayloadAdmissionError("invalid_payload_utf8", "Payload must be valid UTF-8 JSON text");
6868
6956
  }
@@ -6908,9 +6996,9 @@ function assertExactMemberPaths(actual, registered, path = "$") {
6908
6996
  }
6909
6997
  }
6910
6998
  function encodeBase64Utf8(value) {
6911
- const bytes = new TextEncoder().encode(value);
6999
+ const bytes2 = new TextEncoder().encode(value);
6912
7000
  let binary = "";
6913
- for (const byte of bytes) binary += String.fromCharCode(byte);
7001
+ for (const byte of bytes2) binary += String.fromCharCode(byte);
6914
7002
  return btoa(binary);
6915
7003
  }
6916
7004
  function faultFromRequest(request) {
@@ -7169,25 +7257,43 @@ var CommitWorker = class {
7169
7257
  return responseWithAttempt(error3(409, "bootstrap_command_rejected", "Bootstrap admission could not be released"), attemptId, fault2 !== void 0);
7170
7258
  }
7171
7259
  await this.retiredJournalMilestone("S04", traceState?.scope);
7260
+ const permitDigest = commitPermitDigest(input.allTags, candidates);
7261
+ let permitHeld = false;
7262
+ const releasePermit = async () => {
7263
+ if (!permitHeld) return;
7264
+ permitHeld = false;
7265
+ await this.bootstrapPermitRelease(attemptId, permitDigest);
7266
+ };
7267
+ const permit = await this.bootstrapPermitAcquire(attemptId, permitDigest);
7268
+ if (!permit.ok) {
7269
+ if (permit.code === "bootstrap_permit_digest_mismatch") {
7270
+ return responseWithAttempt(error3(409, "bootstrap_permit_digest_mismatch", "Bootstrap write permit digest does not match"), attemptId, fault2 !== void 0);
7271
+ }
7272
+ return responseWithAttempt(error3(409, "bootstrap_command_rejected", "Bootstrap is importing; commit is unavailable"), attemptId, fault2 !== void 0);
7273
+ }
7274
+ permitHeld = this.env.BOOTSTRAP !== void 0;
7172
7275
  const reservations = await this.acquireReservations(input, attemptId, fault2, traceState?.scope);
7173
7276
  await this.retiredJournalMilestone("S05a", traceState?.scope, 0);
7174
7277
  if (reservations.failure !== void 0) {
7175
- return this.finishReservationFailure(
7278
+ const failure3 = await this.finishReservationFailure(
7176
7279
  [...reservations.successes.keys()],
7177
7280
  attemptId,
7178
7281
  reservations.failure,
7179
7282
  fault2,
7180
7283
  traceState?.scope
7181
7284
  );
7285
+ if (failure3.resolved) await releasePermit();
7286
+ return failure3.response;
7182
7287
  }
7183
7288
  if (fault2 === "after-reservations-before-allocation") {
7184
- await this.cancelReservations([...reservations.successes.keys()], attemptId, fault2, traceState?.scope);
7289
+ const cleanup = await this.cancelReservations([...reservations.successes.keys()], attemptId, fault2, traceState?.scope);
7290
+ if (cleanup.failedTags.length === 0) await releasePermit();
7185
7291
  return this.noApplicationOutcome(attemptId, true);
7186
7292
  }
7187
7293
  await this.hooks.beforeBootstrapAllocation?.();
7188
7294
  const allocation = await this.allocate(candidates, attemptId, fault2, bootstrapEpoch, traceState?.scope);
7189
7295
  if (allocation === void 0) {
7190
- return this.finishReservationFailure(
7296
+ const failure3 = await this.finishReservationFailure(
7191
7297
  [...reservations.successes.keys()],
7192
7298
  attemptId,
7193
7299
  {
@@ -7198,10 +7304,13 @@ var CommitWorker = class {
7198
7304
  fault2,
7199
7305
  traceState?.scope
7200
7306
  );
7307
+ if (failure3.resolved) await releasePermit();
7308
+ return failure3.response;
7201
7309
  }
7202
7310
  const allocatedCandidates = this.withAllocatedSuids(candidates, allocation);
7203
7311
  if (allocatedCandidates === void 0) {
7204
- await this.cancelReservations([...reservations.successes.keys()], attemptId, fault2, traceState?.scope);
7312
+ const cleanup = await this.cancelReservations([...reservations.successes.keys()], attemptId, fault2, traceState?.scope);
7313
+ if (cleanup.failedTags.length === 0) await releasePermit();
7205
7314
  return this.noApplicationOutcome(attemptId, fault2 !== void 0);
7206
7315
  }
7207
7316
  for (const candidate of allocatedCandidates) {
@@ -7216,15 +7325,18 @@ var CommitWorker = class {
7216
7325
  }
7217
7326
  await this.retiredJournalMilestone("S05b", traceState?.scope, 1);
7218
7327
  if (fault2 === "journal-cas-after-allocator") {
7219
- await this.cancelReservations(input.allTags, attemptId, fault2, traceState?.scope);
7328
+ const cleanup = await this.cancelReservations(input.allTags, attemptId, fault2, traceState?.scope);
7329
+ if (cleanup.failedTags.length === 0) await releasePermit();
7220
7330
  return this.noApplicationOutcome(attemptId, true);
7221
7331
  }
7222
7332
  await this.retiredJournalMilestone("S05c", traceState?.scope, 2);
7223
7333
  await this.hooks.beforeBootstrapFinalization?.();
7224
7334
  if (await this.bootstrapCommand("finalize", attemptId, bootstrapEpoch, traceState?.scope, "S10") === void 0) {
7225
- await this.cancelReservations(input.allTags, attemptId, fault2, traceState?.scope);
7335
+ const cleanup = await this.cancelReservations(input.allTags, attemptId, fault2, traceState?.scope);
7336
+ if (cleanup.failedTags.length === 0) await releasePermit();
7226
7337
  return responseWithAttempt(error3(409, "bootstrap_command_rejected", "Bootstrap fencing epoch changed before commit write"), attemptId, fault2 !== void 0);
7227
7338
  }
7339
+ await this.hooks.beforeAuthoritativeAppend?.();
7228
7340
  const writes = await this.appendAllTags(
7229
7341
  input,
7230
7342
  allocatedCandidates,
@@ -7240,6 +7352,7 @@ var CommitWorker = class {
7240
7352
  return this.noApplicationOutcome(attemptId, true);
7241
7353
  }
7242
7354
  if (writes.committedTags.size === 0 && writes.registrationUnavailableTags.length === writes.pendingTags.length) {
7355
+ await releasePermit();
7243
7356
  return responseWithAttempt(
7244
7357
  error3(
7245
7358
  503,
@@ -7251,20 +7364,25 @@ var CommitWorker = class {
7251
7364
  fault2 !== void 0
7252
7365
  );
7253
7366
  }
7367
+ await releasePermit();
7254
7368
  return this.partialWriteOutcome(input, allocatedCandidates, writes, attemptId, fault2 !== void 0);
7255
7369
  }
7370
+ await this.hooks.afterAppendBeforeResponse?.();
7256
7371
  await this.retiredJournalMilestone("S05d", traceState?.scope, 3);
7257
7372
  if (fault2 === "sealing-after-cas") {
7373
+ await releasePermit();
7258
7374
  return this.noApplicationOutcome(attemptId, true);
7259
7375
  }
7260
7376
  try {
7261
- const success = await this.successResponse(input, allocatedCandidates, attemptId, startedAt, fault2, traceState?.scope);
7377
+ const success = await this.successResponse(input, allocatedCandidates, attemptId, startedAt, fault2, traceState?.scope, writes);
7378
+ await releasePermit();
7262
7379
  return responseWithAttempt(
7263
7380
  withGlobalAdmission(json4(success, 200), writes.globalAdmission),
7264
7381
  attemptId,
7265
7382
  fault2 !== void 0
7266
7383
  );
7267
7384
  } catch {
7385
+ await releasePermit();
7268
7386
  return responseWithAttempt(
7269
7387
  error3(500, "internal_error", "Committed records could not be read while preparing the response"),
7270
7388
  attemptId,
@@ -7311,6 +7429,51 @@ var CommitWorker = class {
7311
7429
  const result2 = traceScope === void 0 || rowId === void 0 ? await invoke() : await traceScope.span(rowId, {}, invoke);
7312
7430
  return result2.leaseEpoch;
7313
7431
  }
7432
+ /**
7433
+ * SDT-G36 bootstrap write permit. Deliberately untraced: it must not add
7434
+ * `sdt.commit/v2` rows or new trace identities. Only a bootstrap barrier,
7435
+ * never commit-outcome authority. No JOURNAL, no alarm, no lease expiry.
7436
+ */
7437
+ bootstrapStub() {
7438
+ if (this.env.BOOTSTRAP === void 0) return void 0;
7439
+ return this.env.BOOTSTRAP.get(scopeIdFor(this.env.BOOTSTRAP, {
7440
+ serviceId: this.serviceId,
7441
+ doClass: "bootstrap",
7442
+ identity: "coordinator"
7443
+ }));
7444
+ }
7445
+ async bootstrapPermitAcquire(commandId, digest2) {
7446
+ const stub = this.bootstrapStub();
7447
+ if (stub === void 0) return { ok: true };
7448
+ try {
7449
+ const url = new URL(`https://commit-worker.internal/command/permit`);
7450
+ url.searchParams.set("__serviceId", this.serviceId);
7451
+ const response3 = await stub.fetch(new Request(url, {
7452
+ method: "POST",
7453
+ headers: { "content-type": "application/json" },
7454
+ body: JSON.stringify({ commandId, digest: digest2 })
7455
+ }));
7456
+ if (response3.ok) return { ok: true };
7457
+ const body = await response3.clone().json().catch(() => void 0);
7458
+ return { ok: false, code: typeof body?.code === "string" ? body.code : void 0 };
7459
+ } catch {
7460
+ return { ok: false };
7461
+ }
7462
+ }
7463
+ async bootstrapPermitRelease(commandId, digest2) {
7464
+ const stub = this.bootstrapStub();
7465
+ if (stub === void 0) return;
7466
+ try {
7467
+ const url = new URL(`https://commit-worker.internal/command/permit-release`);
7468
+ url.searchParams.set("__serviceId", this.serviceId);
7469
+ await stub.fetch(new Request(url, {
7470
+ method: "POST",
7471
+ headers: { "content-type": "application/json" },
7472
+ body: JSON.stringify({ commandId, digest: digest2 })
7473
+ }));
7474
+ } catch {
7475
+ }
7476
+ }
7314
7477
  async postJson(stub, path, body, traceScope, rowId, traceOptions = {}) {
7315
7478
  const invoke = async () => {
7316
7479
  const response3 = await stub.fetch(
@@ -7456,6 +7619,7 @@ var CommitWorker = class {
7456
7619
  let pending = [...input.allTags];
7457
7620
  const committedTags = /* @__PURE__ */ new Set();
7458
7621
  const lastFailureCodeByTag = /* @__PURE__ */ new Map();
7622
+ const tagWriteFacts = /* @__PURE__ */ new Map();
7459
7623
  let globalAdmission = "admitted";
7460
7624
  for (let attempt = 0; attempt < MAX_WRITE_ATTEMPTS && pending.length > 0; attempt += 1) {
7461
7625
  const append = (stageScope) => Promise.allSettled(
@@ -7482,12 +7646,26 @@ var CommitWorker = class {
7482
7646
  retryIndex: attempt,
7483
7647
  attemptId
7484
7648
  });
7485
- const body = response3.status === 503 ? await response3.clone().json().catch(() => void 0) : void 0;
7649
+ const success = response3.status >= 200 && response3.status < 300;
7650
+ let appendVersion;
7651
+ let appendUpdatedAt;
7652
+ let code;
7653
+ try {
7654
+ const parsed = await response3.clone().json();
7655
+ if (isObject5(parsed)) {
7656
+ if (typeof parsed.version === "number" && Number.isSafeInteger(parsed.version)) appendVersion = parsed.version;
7657
+ if (typeof parsed.updatedAt === "string" && parsed.updatedAt.length > 0) appendUpdatedAt = parsed.updatedAt;
7658
+ if (typeof parsed.code === "string") code = parsed.code;
7659
+ }
7660
+ } catch {
7661
+ }
7486
7662
  return {
7487
7663
  tag,
7488
- success: response3.status >= 200 && response3.status < 300,
7664
+ success,
7489
7665
  globalAdmission: readGlobalAdmission(response3),
7490
- code: isObject5(body) && typeof body.code === "string" ? body.code : void 0
7666
+ code,
7667
+ appendVersion,
7668
+ appendUpdatedAt
7491
7669
  };
7492
7670
  })
7493
7671
  );
@@ -7499,6 +7677,9 @@ var CommitWorker = class {
7499
7677
  committedTags.add(tag);
7500
7678
  lastFailureCodeByTag.delete(tag);
7501
7679
  globalAdmission = mergeGlobalAdmission(globalAdmission, result2.value.globalAdmission);
7680
+ if (result2.value.appendVersion !== void 0 && result2.value.appendUpdatedAt !== void 0) {
7681
+ tagWriteFacts.set(tag, { version: result2.value.appendVersion, updatedAt: result2.value.appendUpdatedAt });
7682
+ }
7502
7683
  } else {
7503
7684
  lastFailureCodeByTag.set(
7504
7685
  tag,
@@ -7515,7 +7696,8 @@ var CommitWorker = class {
7515
7696
  registrationUnavailableTags: pending.filter(
7516
7697
  (tag) => lastFailureCodeByTag.get(tag) === "partition_registration_unavailable"
7517
7698
  ),
7518
- globalAdmission
7699
+ globalAdmission,
7700
+ tagWriteFacts
7519
7701
  };
7520
7702
  }
7521
7703
  /**
@@ -7548,10 +7730,13 @@ var CommitWorker = class {
7548
7730
  if (traceScope !== void 0) {
7549
7731
  await traceScope.span("S17", {}, async () => void 0);
7550
7732
  }
7551
- await this.cancelReservations(tags, attemptId, fault2, traceScope);
7733
+ const cleanup = await this.cancelReservations(tags, attemptId, fault2, traceScope);
7552
7734
  await this.retiredJournalMilestone("S05e", traceScope, 4);
7553
7735
  const response3 = failure3.outcome === "REFUSED" ? error3(400, "consistency_conflict", "serialized commit was refused by a consistency reservation") : failure3.failureCause === "reservation-timeout" ? error3(504, "timeout", "serialized commit timed out") : error3(500, "internal_error", "serialized commit failed before writing requested records");
7554
- return responseWithAttempt(response3, attemptId, fault2 !== void 0);
7736
+ return {
7737
+ response: responseWithAttempt(response3, attemptId, fault2 !== void 0),
7738
+ resolved: cleanup.failedTags.length === 0
7739
+ };
7555
7740
  }
7556
7741
  /**
7557
7742
  * Persist the local partial-write fact for each tag whose append did not
@@ -7588,22 +7773,25 @@ var CommitWorker = class {
7588
7773
  }
7589
7774
  }, 500), attemptId, exposeAttempt);
7590
7775
  }
7591
- async successResponse(input, candidates, attemptId, startedAt, fault2, traceScope) {
7592
- const readStates = (stageScope) => Promise.all(input.allTags.map(async (tag, memberIndex) => {
7776
+ async successResponse(input, candidates, attemptId, startedAt, fault2, traceScope, writes) {
7777
+ const assemble = async (stageScope) => {
7593
7778
  if (fault2 === "tag-state-unavailable") {
7594
7779
  throw new Error("Test fault made the committed tag state unavailable");
7595
7780
  }
7596
- const response3 = await this.tagRequest(tag, "/head-facts", void 0, stageScope?.fork(), stageScope === void 0 ? void 0 : "S14", { memberIndex, attemptId });
7597
- if (response3.status !== 200) {
7598
- throw new Error("Committed tag state was unavailable while preparing the response");
7599
- }
7600
- const body = await response3.json();
7601
- if (typeof body.version !== "number" || typeof body.updatedAt !== "string" || typeof body.head !== "string") {
7602
- throw new Error("Committed tag state was malformed while preparing the response");
7781
+ const results = [];
7782
+ for (const [memberIndex, tag] of input.allTags.entries()) {
7783
+ const read = () => {
7784
+ const fact = writes?.tagWriteFacts.get(tag);
7785
+ if (fact === void 0) {
7786
+ throw new Error("Committed tag state was unavailable while preparing the response");
7787
+ }
7788
+ return { tag, version: fact.version, writtenAt: fact.updatedAt };
7789
+ };
7790
+ results.push(stageScope === void 0 ? read() : await stageScope.fork().span("S14", { tag, memberIndex, attemptId }, async () => read()));
7603
7791
  }
7604
- return { tag, version: body.version, writtenAt: body.updatedAt };
7605
- }));
7606
- const tagWriteResults = traceScope === void 0 ? await readStates() : await traceScope.span("S13", {}, async (stage) => readStates(stage));
7792
+ return results;
7793
+ };
7794
+ const tagWriteResults = traceScope === void 0 ? await assemble() : await traceScope.span("S13", {}, async (stage) => assemble(stage));
7607
7795
  return {
7608
7796
  writtenEvents: candidates.map((candidate) => ({
7609
7797
  payload: encodeBase64Utf8(candidate.payload),
@@ -7817,15 +8005,15 @@ function observePostAdmission(observer, message, source, input) {
7817
8005
  observedAt: Date.now()
7818
8006
  });
7819
8007
  }
7820
- function errorText(error10) {
7821
- if (error10 instanceof Error && error10.message.length > 0) return error10.message;
7822
- return String(error10);
8008
+ function errorText(error11) {
8009
+ if (error11 instanceof Error && error11.message.length > 0) return error11.message;
8010
+ return String(error11);
7823
8011
  }
7824
8012
  function deliveryCorrelationId(message, source, supplied) {
7825
8013
  return supplied ?? `${source}:${message.serviceId}:${message.eventId}:${message.attemptId}`;
7826
8014
  }
7827
- function defaultFailureClass(error10) {
7828
- const candidate = error10;
8015
+ function defaultFailureClass(error11) {
8016
+ const candidate = error11;
7829
8017
  if (candidate.failureClass === "duplicate-race") return "duplicate-race";
7830
8018
  if (candidate.failureClass === "nonretryable-definition-poison") return "nonretryable-definition-poison";
7831
8019
  if (candidate.failureClass === "retryable-transient") return "retryable-transient";
@@ -7884,8 +8072,8 @@ async function applyViewHandlers(views, message, storedEvent, arrivedAt, source,
7884
8072
  result: { id: view.id, status, durationMs: Math.max(0, performance.now() - viewStartedAt) },
7885
8073
  failure: void 0
7886
8074
  };
7887
- } catch (error10) {
7888
- const failureClass = view.classifyError?.(error10) ?? defaultFailureClass(error10);
8075
+ } catch (error11) {
8076
+ const failureClass = view.classifyError?.(error11) ?? defaultFailureClass(error11);
7889
8077
  observePostAdmission(observer, message, source, {
7890
8078
  stage: "unsafe-view-apply",
7891
8079
  boundary: "end",
@@ -7897,10 +8085,10 @@ async function applyViewHandlers(views, message, storedEvent, arrivedAt, source,
7897
8085
  id: view.id,
7898
8086
  status: "failed",
7899
8087
  failureClass,
7900
- error: errorText(error10),
8088
+ error: errorText(error11),
7901
8089
  durationMs: Math.max(0, performance.now() - viewStartedAt)
7902
8090
  },
7903
- failure: { phase: "view", class: failureClass, viewId: view.id, error: errorText(error10) }
8091
+ failure: { phase: "view", class: failureClass, viewId: view.id, error: errorText(error11) }
7904
8092
  };
7905
8093
  }
7906
8094
  }));
@@ -7930,15 +8118,15 @@ async function processDeliveryCore(message, source, env, options = {}) {
7930
8118
  // settled; this is the durable post-batch observation boundary.
7931
8119
  observedAt: Date.now()
7932
8120
  });
7933
- } catch (error10) {
7934
- const failures2 = [{ phase: "recordDelivery", class: "retryable-transient", error: errorText(error10) }];
8121
+ } catch (error11) {
8122
+ const failures2 = [{ phase: "recordDelivery", class: "retryable-transient", error: errorText(error11) }];
7935
8123
  return result(source, message, "stored", arrivedAt, false, [], failures2, options.correlationId, startedAt);
7936
8124
  }
7937
8125
  if (outcome.outcome !== "stored") {
7938
8126
  try {
7939
8127
  await store.projectDeliveryIncidents?.(message.serviceId);
7940
- } catch (error10) {
7941
- const failures2 = [{ phase: "detector", class: "retryable-transient", error: errorText(error10) }];
8128
+ } catch (error11) {
8129
+ const failures2 = [{ phase: "detector", class: "retryable-transient", error: errorText(error11) }];
7942
8130
  return result(source, message, outcome.outcome, arrivedAt, false, [], failures2, options.correlationId, startedAt);
7943
8131
  }
7944
8132
  return result(source, message, outcome.outcome, arrivedAt, false, [], [], options.correlationId, startedAt);
@@ -7967,20 +8155,20 @@ async function processDeliveryCore(message, source, env, options = {}) {
7967
8155
  boundary: "end",
7968
8156
  outcome: "available"
7969
8157
  });
7970
- } catch (error10) {
8158
+ } catch (error11) {
7971
8159
  observePostAdmission(options.durableHopObserver, message, source, {
7972
8160
  stage: "post-record-delivery-global-receipt-readback",
7973
8161
  boundary: "end",
7974
8162
  outcome: "error"
7975
8163
  });
7976
- failures.push({ phase: "recordDelivery", class: "retryable-transient", error: errorText(error10) });
8164
+ failures.push({ phase: "recordDelivery", class: "retryable-transient", error: errorText(error11) });
7977
8165
  return result(source, message, "stored", arrivedAt, false, [], failures, options.correlationId, startedAt);
7978
8166
  }
7979
8167
  if (options.afterGlobalReceipt !== void 0) {
7980
8168
  try {
7981
8169
  await options.afterGlobalReceipt({ message, receipt, arrivedAt, source });
7982
- } catch (error10) {
7983
- failures.push({ phase: "drain", class: "retryable-transient", error: errorText(error10) });
8170
+ } catch (error11) {
8171
+ failures.push({ phase: "drain", class: "retryable-transient", error: errorText(error11) });
7984
8172
  }
7985
8173
  }
7986
8174
  }
@@ -7997,8 +8185,8 @@ async function processDeliveryCore(message, source, env, options = {}) {
7997
8185
  if (options.beforeViews !== void 0) {
7998
8186
  try {
7999
8187
  await options.beforeViews({ message, event: storedEvent, arrivedAt, source });
8000
- } catch (error10) {
8001
- failures.push({ phase: "completeness", class: "retryable-transient", error: errorText(error10) });
8188
+ } catch (error11) {
8189
+ failures.push({ phase: "completeness", class: "retryable-transient", error: errorText(error11) });
8002
8190
  return result(source, message, "stored", arrivedAt, false, viewResults, failures, options.correlationId, startedAt);
8003
8191
  }
8004
8192
  }
@@ -8018,14 +8206,14 @@ async function processDeliveryCore(message, source, env, options = {}) {
8018
8206
  boundary: "end",
8019
8207
  outcome: "applied"
8020
8208
  });
8021
- } catch (error10) {
8209
+ } catch (error11) {
8022
8210
  observePostAdmission(options.durableHopObserver, message, source, {
8023
8211
  stage: "detector",
8024
8212
  boundary: "end",
8025
8213
  outcome: "error"
8026
8214
  });
8027
8215
  try {
8028
- await options.onDetectorFailure?.({ message, arrivedAt, source, error: error10 });
8216
+ await options.onDetectorFailure?.({ message, arrivedAt, source, error: error11 });
8029
8217
  } catch (healthError) {
8030
8218
  failures.push({
8031
8219
  phase: "detector",
@@ -8033,7 +8221,7 @@ async function processDeliveryCore(message, source, env, options = {}) {
8033
8221
  error: `detector_health_record_failed:${errorText(healthError)}`
8034
8222
  });
8035
8223
  }
8036
- failures.push({ phase: "detector", class: "retryable-transient", error: errorText(error10) });
8224
+ failures.push({ phase: "detector", class: "retryable-transient", error: errorText(error11) });
8037
8225
  return result(source, message, "stored", arrivedAt, false, [], failures, options.correlationId, startedAt);
8038
8226
  }
8039
8227
  const views = gatedViews;
@@ -8050,16 +8238,16 @@ async function processDeliveryCore(message, source, env, options = {}) {
8050
8238
  if (options.onStored !== void 0) {
8051
8239
  try {
8052
8240
  await options.onStored({ message, event: storedEvent, arrivedAt, source });
8053
- } catch (error10) {
8054
- failures.push({ phase: "view", class: "retryable-transient", viewId: "legacy-onStored", error: errorText(error10) });
8241
+ } catch (error11) {
8242
+ failures.push({ phase: "view", class: "retryable-transient", viewId: "legacy-onStored", error: errorText(error11) });
8055
8243
  }
8056
8244
  }
8057
8245
  const preliminary = result(source, message, "stored", arrivedAt, detectorApplied, viewResults, failures, options.correlationId, startedAt);
8058
8246
  if (options.afterDelivery !== void 0 && failures.every((failure3) => failure3.class === "duplicate-race")) {
8059
8247
  try {
8060
8248
  await options.afterDelivery({ message, event: storedEvent, arrivedAt, source, result: preliminary });
8061
- } catch (error10) {
8062
- failures.push({ phase: "drain", class: "retryable-transient", error: errorText(error10) });
8249
+ } catch (error11) {
8250
+ failures.push({ phase: "drain", class: "retryable-transient", error: errorText(error11) });
8063
8251
  }
8064
8252
  }
8065
8253
  return result(source, message, "stored", arrivedAt, detectorApplied, viewResults, failures, options.correlationId, startedAt);
@@ -8081,8 +8269,8 @@ function asNumber(value, name) {
8081
8269
  if (!Number.isSafeInteger(number) || number < 0) throw new Error(`G44 ${name} must be a non-negative safe integer`);
8082
8270
  return number;
8083
8271
  }
8084
- function errorText2(error10) {
8085
- return error10 instanceof Error && error10.message.length > 0 ? error10.message : String(error10);
8272
+ function errorText2(error11) {
8273
+ return error11 instanceof Error && error11.message.length > 0 ? error11.message : String(error11);
8086
8274
  }
8087
8275
  function settledFrontierFromCursor(cursorJson) {
8088
8276
  const cursor = settledCursorFromJson(cursorJson);
@@ -8186,8 +8374,8 @@ var GlobalCompletenessReconciler = class {
8186
8374
  let snapshots;
8187
8375
  try {
8188
8376
  snapshots = await this.snapshotPartitions(serviceId);
8189
- } catch (error10) {
8190
- const message = errorText2(error10);
8377
+ } catch (error11) {
8378
+ const message = errorText2(error11);
8191
8379
  await this.appendFinding(serviceId, {
8192
8380
  identity: scannerFailureIdentity(serviceId),
8193
8381
  type: "GLOBAL_ARRAY_SCANNER_FAILURE",
@@ -8229,7 +8417,7 @@ var GlobalCompletenessReconciler = class {
8229
8417
  let joined;
8230
8418
  try {
8231
8419
  joined = this.options.globalReceiptMatcher === void 0 ? await this.globalReceiptMatches(snapshot.serviceId, snapshot.tag, obligation) : await this.options.globalReceiptMatcher(snapshot.serviceId, snapshot.tag, obligation);
8232
- } catch (error10) {
8420
+ } catch (error11) {
8233
8421
  await this.appendFinding(snapshot.serviceId, {
8234
8422
  identity: `GLOBAL_RECEIPT_UNAVAILABLE|${snapshot.serviceId}|${snapshot.tag}|${obligation.obligationSequence}|${obligation.eventId}|${obligation.eventDigest}`,
8235
8423
  type: "GLOBAL_ARRAY_RECEIPT_UNAVAILABLE",
@@ -8238,7 +8426,7 @@ var GlobalCompletenessReconciler = class {
8238
8426
  eventId: obligation.eventId,
8239
8427
  eventDigest: obligation.eventDigest
8240
8428
  }, nowMs).catch(() => void 0);
8241
- throw error10;
8429
+ throw error11;
8242
8430
  }
8243
8431
  if (!joined) {
8244
8432
  await this.appendObligationFinding(snapshot.serviceId, snapshot.tag, obligation, nowMs);
@@ -8257,8 +8445,8 @@ var GlobalCompletenessReconciler = class {
8257
8445
  if (afterSequence !== snapshot.upperBoundSequence) {
8258
8446
  throw new Error(`source_partition_range_incomplete:${snapshot.tag}`);
8259
8447
  }
8260
- } catch (error10) {
8261
- if (errorText2(error10).startsWith("source_")) {
8448
+ } catch (error11) {
8449
+ if (errorText2(error11).startsWith("source_")) {
8262
8450
  await this.appendFinding(snapshot.serviceId, {
8263
8451
  identity: sourceUnavailableIdentity(snapshot.serviceId, snapshot.tag),
8264
8452
  type: "GLOBAL_ARRAY_SOURCE_PARTITION_UNAVAILABLE",
@@ -8268,7 +8456,7 @@ var GlobalCompletenessReconciler = class {
8268
8456
  eventDigest: null
8269
8457
  }, nowMs).catch(() => void 0);
8270
8458
  }
8271
- throw error10;
8459
+ throw error11;
8272
8460
  }
8273
8461
  }
8274
8462
  const endSnapshots = await this.snapshotPartitions(serviceId);
@@ -8287,8 +8475,8 @@ var GlobalCompletenessReconciler = class {
8287
8475
  }
8288
8476
  await this.writeHealth(serviceId, "HEALTHY", JSON.stringify(cursor), nowMs, null, nowMs);
8289
8477
  return { kind: "FULL", partitions: snapshots, scannedObligations: scanned };
8290
- } catch (error10) {
8291
- const message = errorText2(error10);
8478
+ } catch (error11) {
8479
+ const message = errorText2(error11);
8292
8480
  const health = message.startsWith("source_") ? "UNKNOWN" : "FAILED";
8293
8481
  if (health === "FAILED") {
8294
8482
  await this.appendFinding(serviceId, {
@@ -8430,8 +8618,8 @@ var GlobalCompletenessReconciler = class {
8430
8618
  * without applying views. It shares the scanner's single health/finding
8431
8619
  * authority rather than creating a second incident workflow.
8432
8620
  */
8433
- async recordDetectorFailure(serviceId, error10, nowMs) {
8434
- const message = `detector_failure:${errorText2(error10).slice(0, 256)}`;
8621
+ async recordDetectorFailure(serviceId, error11, nowMs) {
8622
+ const message = `detector_failure:${errorText2(error11).slice(0, 256)}`;
8435
8623
  await this.appendFinding(serviceId, {
8436
8624
  identity: `GLOBAL_DETECTOR_FAILURE|${serviceId}`,
8437
8625
  type: "GLOBAL_ARRAY_DETECTOR_FAILURE",
@@ -8570,7 +8758,7 @@ var GlobalCompletenessReconciler = class {
8570
8758
  nowMs
8571
8759
  ).run();
8572
8760
  }
8573
- async writeHealth(serviceId, status, cursor, lastFullScanAt, error10, nowMs) {
8761
+ async writeHealth(serviceId, status, cursor, lastFullScanAt, error11, nowMs) {
8574
8762
  await this.database.prepare(
8575
8763
  `INSERT INTO serialized_dcb_completeness_scanner_health
8576
8764
  (service_id, scanner_version, status, cursor_json, last_full_scan_at, last_error, updated_at)
@@ -8582,7 +8770,7 @@ var GlobalCompletenessReconciler = class {
8582
8770
  last_full_scan_at = COALESCE(excluded.last_full_scan_at, serialized_dcb_completeness_scanner_health.last_full_scan_at),
8583
8771
  last_error = excluded.last_error,
8584
8772
  updated_at = excluded.updated_at`
8585
- ).bind(serviceId, this.scannerVersion, status, cursor, lastFullScanAt, error10, nowMs).run();
8773
+ ).bind(serviceId, this.scannerVersion, status, cursor, lastFullScanAt, error11, nowMs).run();
8586
8774
  }
8587
8775
  };
8588
8776
  function globalReceiptAcknowledgement(message, receivedAt) {
@@ -8674,7 +8862,7 @@ function sourceAcknowledgementOptions(env, options) {
8674
8862
  if (decision.kind !== "SETTLED") {
8675
8863
  throw new Error(`global_completeness_${decision.kind}:${decision.health.status}`);
8676
8864
  }
8677
- } catch (error10) {
8865
+ } catch (error11) {
8678
8866
  if (!completed) {
8679
8867
  observeG60PostAdmission(options.durableHopObserver, {
8680
8868
  stage: "completeness-coverage",
@@ -8689,7 +8877,7 @@ function sourceAcknowledgementOptions(env, options) {
8689
8877
  observedAt: Date.now()
8690
8878
  });
8691
8879
  }
8692
- throw error10;
8880
+ throw error11;
8693
8881
  }
8694
8882
  } : options.beforeViews;
8695
8883
  const observedSourceAcknowledgement = sourceAcknowledgement === void 0 ? void 0 : async (input) => {
@@ -8697,14 +8885,14 @@ function sourceAcknowledgementOptions(env, options) {
8697
8885
  try {
8698
8886
  await sourceAcknowledgement(input);
8699
8887
  observeSourceSubstep(options.durableHopObserver, { ...input, boundary: "end", outcome: "acknowledged" });
8700
- } catch (error10) {
8888
+ } catch (error11) {
8701
8889
  observeSourceSubstep(options.durableHopObserver, { ...input, boundary: "end", outcome: "error" });
8702
- throw error10;
8890
+ throw error11;
8703
8891
  }
8704
8892
  };
8705
- const detectorFailure = hasG44Authority ? async ({ message, arrivedAt, error: error10, source }) => {
8706
- await options.onDetectorFailure?.({ message, arrivedAt, error: error10, source });
8707
- await new GlobalCompletenessReconciler(env.D1, env.TAG).recordDetectorFailure(message.serviceId, error10, arrivedAt);
8893
+ const detectorFailure = hasG44Authority ? async ({ message, arrivedAt, error: error11, source }) => {
8894
+ await options.onDetectorFailure?.({ message, arrivedAt, error: error11, source });
8895
+ await new GlobalCompletenessReconciler(env.D1, env.TAG).recordDetectorFailure(message.serviceId, error11, arrivedAt);
8708
8896
  } : options.onDetectorFailure;
8709
8897
  return {
8710
8898
  ...options,
@@ -8719,9 +8907,9 @@ function sharedStore(env, provider) {
8719
8907
  async function admitBootstrapRoute(env, serviceId, route) {
8720
8908
  if (env.BOOTSTRAP === void 0) {
8721
8909
  if (env.G38_DOORBELL_DELIVERY_ROLE === "receiver") {
8722
- const error10 = new Error(`bootstrap_route_binding_missing:${route}`);
8723
- error10.name = "BootstrapRouteBindingMissingError";
8724
- throw error10;
8910
+ const error11 = new Error(`bootstrap_route_binding_missing:${route}`);
8911
+ error11.name = "BootstrapRouteBindingMissingError";
8912
+ throw error11;
8725
8913
  }
8726
8914
  return;
8727
8915
  }
@@ -8810,10 +8998,10 @@ async function handleDownstreamQueue(batch, env, options = {}) {
8810
8998
  if (outcome.outcome === "stored" && !outcome.failures.some((failure3) => failure3.phase === "recordDelivery")) {
8811
8999
  try {
8812
9000
  options.afterStoredQueueDelivery?.({ message: queued.body, result: outcome });
8813
- } catch (error10) {
9001
+ } catch (error11) {
8814
9002
  console.warn("safe_lane_kick", {
8815
9003
  status: "failed-to-schedule",
8816
- error: error10 instanceof Error ? error10.message : String(error10),
9004
+ error: error11 instanceof Error ? error11.message : String(error11),
8817
9005
  serviceId: queued.body.serviceId,
8818
9006
  eventId: queued.body.eventId,
8819
9007
  attemptId: queued.body.attemptId
@@ -8835,6 +9023,36 @@ async function stabilizeDownstream(env, options = {}, serviceId, serviceIdentity
8835
9023
  });
8836
9024
  }
8837
9025
 
9026
+ // src/scope/ControlRouteScope.ts
9027
+ function response2(status, code, error11) {
9028
+ return new Response(JSON.stringify({ code, error: error11 }), {
9029
+ status,
9030
+ headers: { "content-type": "application/json; charset=utf-8" }
9031
+ });
9032
+ }
9033
+ function scopeIdentityMissingResponse() {
9034
+ return response2(503, "scope.identity_missing", "A deployment service identity is required for this scope");
9035
+ }
9036
+ function enforceControlRouteScope(input) {
9037
+ let actual;
9038
+ try {
9039
+ actual = input.provider.forRequest(input.request, input.requestOptions).serviceId;
9040
+ } catch (caught) {
9041
+ if (caught instanceof ServiceIdentityMissingError) {
9042
+ console.error({ schema: "sdt.scope/v1", code: "scope.identity_missing", route: input.route });
9043
+ return { response: scopeIdentityMissingResponse() };
9044
+ }
9045
+ throw caught;
9046
+ }
9047
+ if (input.pathServiceId !== actual) {
9048
+ console.warn({ schema: "sdt.scope/v1", code: "scope.mismatch", route: input.route });
9049
+ return {
9050
+ response: response2(403, "scope.mismatch", "The path service identity is not authorized for this deployment")
9051
+ };
9052
+ }
9053
+ return { serviceId: actual };
9054
+ }
9055
+
8838
9056
  // src/downstream/OutboxDrain.ts
8839
9057
  function json5(body, status = 200) {
8840
9058
  return new Response(JSON.stringify(body), {
@@ -8931,15 +9149,32 @@ async function handleOutboxDrainRequest(request, env, options = {}) {
8931
9149
  if (!isDrainRequest(body)) {
8932
9150
  return json5({ error: "serviceId and unique non-empty tags are required", code: "invalid_outbox_drain_request" }, 400);
8933
9151
  }
9152
+ const requestedServiceId = body.serviceId;
9153
+ const tags = body.tags;
9154
+ const provider = options.serviceIdentityProvider ?? envServiceIdentity(env);
9155
+ let authority;
9156
+ try {
9157
+ authority = provider.forRequest(request).serviceId;
9158
+ } catch (caught) {
9159
+ if (caught instanceof ServiceIdentityMissingError) return scopeIdentityMissingResponse();
9160
+ throw caught;
9161
+ }
9162
+ if (requestedServiceId !== authority) {
9163
+ console.warn({ schema: "sdt.scope/v1", code: "scope.mismatch", route: "outbox-drain" });
9164
+ return json5({
9165
+ code: "scope.mismatch",
9166
+ error: "The request service identity is not authorized for this deployment"
9167
+ }, 403);
9168
+ }
8934
9169
  try {
8935
9170
  const results = [];
8936
- for (const tag of body.tags) {
8937
- results.push(await drainTagOutbox({ serviceId: body.serviceId, tag }, env, systemPipelineClock, options));
9171
+ for (const tag of tags) {
9172
+ results.push(await drainTagOutbox({ serviceId: authority, tag }, env, systemPipelineClock, options));
8938
9173
  }
8939
9174
  return json5({ results });
8940
- } catch (error10) {
9175
+ } catch (error11) {
8941
9176
  return json5({
8942
- error: error10 instanceof Error ? error10.message : "Outbox drain failed",
9177
+ error: error11 instanceof Error ? error11.message : "Outbox drain failed",
8943
9178
  code: "outbox_drain_failed"
8944
9179
  }, 503);
8945
9180
  }
@@ -9384,9 +9619,9 @@ function isNonEmptyString7(value) {
9384
9619
  return typeof value === "string" && value.length > 0;
9385
9620
  }
9386
9621
  function base64Json(value) {
9387
- const bytes = new TextEncoder().encode(JSON.stringify(value));
9622
+ const bytes2 = new TextEncoder().encode(JSON.stringify(value));
9388
9623
  let binary = "";
9389
- for (const byte of bytes) {
9624
+ for (const byte of bytes2) {
9390
9625
  binary += String.fromCharCode(byte);
9391
9626
  }
9392
9627
  return btoa(binary);
@@ -9564,9 +9799,9 @@ function decodeStoredJson(value) {
9564
9799
  }
9565
9800
  }
9566
9801
  function jsonBytes(value) {
9567
- const bytes = new TextEncoder().encode(JSON.stringify(value));
9802
+ const bytes2 = new TextEncoder().encode(JSON.stringify(value));
9568
9803
  let binary = "";
9569
- for (const byte of bytes) binary += String.fromCharCode(byte);
9804
+ for (const byte of bytes2) binary += String.fromCharCode(byte);
9570
9805
  return btoa(binary);
9571
9806
  }
9572
9807
  function isRuntimeBridgedProjector(definition) {
@@ -9639,9 +9874,9 @@ function isRuntimeCommandLike(value) {
9639
9874
  return typeof candidate.id === "string" && candidate.id.length > 0 && typeof candidate.name === "string" && typeof candidate.parseInput === "function" && typeof candidate.execute === "function" && typeof candidate.handle === "function";
9640
9875
  }
9641
9876
  function encodeJsonPayload(value) {
9642
- const bytes = new TextEncoder().encode(JSON.stringify(value));
9877
+ const bytes2 = new TextEncoder().encode(JSON.stringify(value));
9643
9878
  let binary = "";
9644
- for (const byte of bytes) binary += String.fromCharCode(byte);
9879
+ for (const byte of bytes2) binary += String.fromCharCode(byte);
9645
9880
  return btoa(binary);
9646
9881
  }
9647
9882
  function candidateToV1Envelope(candidate) {
@@ -9825,8 +10060,8 @@ function stateFromCheckpoint(projector, checkpoint) {
9825
10060
  if (checkpoint === void 0) return projector.initialState();
9826
10061
  try {
9827
10062
  return projector.deserializeState(checkpoint.stateJson);
9828
- } catch (error10) {
9829
- throw new ProjectionCheckpointCorruption(error10);
10063
+ } catch (error11) {
10064
+ throw new ProjectionCheckpointCorruption(error11);
9830
10065
  }
9831
10066
  }
9832
10067
  function projectionEventFromStored(event) {
@@ -10050,8 +10285,8 @@ async function admitBootstrapRoute2(env, serviceId) {
10050
10285
  })).fetch(new Request(url, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ route: "projection-rebuild" }) }));
10051
10286
  if (!admitted.ok) throw new Error("bootstrap_route_rejected:projection-rebuild");
10052
10287
  }
10053
- function boundedErrorReason(error10) {
10054
- const value = error10 instanceof Error ? error10.message : String(error10);
10288
+ function boundedErrorReason(error11) {
10289
+ const value = error11 instanceof Error ? error11.message : String(error11);
10055
10290
  return value.length > 256 ? `${value.slice(0, 253)}...` : value;
10056
10291
  }
10057
10292
  async function notifyObserver(observer, callback, input) {
@@ -10064,7 +10299,7 @@ async function notifyObserver(observer, callback, input) {
10064
10299
  } catch {
10065
10300
  }
10066
10301
  }
10067
- async function notifyOutcomes(observer, serviceId, projectorIds, attemptedAt, results, maximumSuid, env, error10) {
10302
+ async function notifyOutcomes(observer, serviceId, projectorIds, attemptedAt, results, maximumSuid, env, error11) {
10068
10303
  if (observer?.onOutcome === void 0) return;
10069
10304
  const byProjector = /* @__PURE__ */ new Map();
10070
10305
  for (const result2 of results) {
@@ -10077,9 +10312,9 @@ async function notifyOutcomes(observer, serviceId, projectorIds, attemptedAt, re
10077
10312
  let outcome = "invoked-but-no-work";
10078
10313
  let reason = null;
10079
10314
  let advancedSourceEvents = 0;
10080
- if (error10 !== void 0) {
10315
+ if (error11 !== void 0) {
10081
10316
  outcome = "invoked-and-threw";
10082
- reason = boundedErrorReason(error10);
10317
+ reason = boundedErrorReason(error11);
10083
10318
  } else {
10084
10319
  advancedSourceEvents = projectorResults.reduce((total, result2) => total + result2.advancedSourceEvents, 0);
10085
10320
  if (advancedSourceEvents > 0) {
@@ -10181,9 +10416,9 @@ async function pollLiveProjections(env, options = {}) {
10181
10416
  const results = await runtime.pollRegistered(serviceId, attemptedAt, options.maximumSuid);
10182
10417
  await notifyOutcomes(options.observer, serviceId, projectorIds, attemptedAt, results, options.maximumSuid, env);
10183
10418
  return results;
10184
- } catch (error10) {
10185
- await notifyOutcomes(options.observer, serviceId, projectorIds, attemptedAt, [], options.maximumSuid, env, error10);
10186
- throw error10;
10419
+ } catch (error11) {
10420
+ await notifyOutcomes(options.observer, serviceId, projectorIds, attemptedAt, [], options.maximumSuid, env, error11);
10421
+ throw error11;
10187
10422
  }
10188
10423
  }
10189
10424
  async function handleProjectionLag(request, env, registry = DEPLOYED_PROJECTOR_REGISTRY, storeProvider, serviceIdentityProvider) {
@@ -10421,15 +10656,15 @@ function integer(row, key) {
10421
10656
  function operationId() {
10422
10657
  return `mv-unsafe-${crypto.randomUUID()}`;
10423
10658
  }
10424
- function errorFrom(error10) {
10425
- const value = String(error10);
10659
+ function errorFrom(error11) {
10660
+ const value = String(error11);
10426
10661
  if (value.includes("mv_unsafe_receipts") && (value.includes("UNIQUE") || value.includes("constraint"))) {
10427
- return new UnsafeWindowMaterializedViewError("UNSAFE_DUPLICATE_RACE", false, "Concurrent unsafe receipt was committed by another delivery", { cause: error10 });
10662
+ return new UnsafeWindowMaterializedViewError("UNSAFE_DUPLICATE_RACE", false, "Concurrent unsafe receipt was committed by another delivery", { cause: error11 });
10428
10663
  }
10429
- if (value.includes("unsafe_row_cas")) return new UnsafeWindowMaterializedViewError("UNSAFE_ROW_CAS_MISMATCH", true, "Unsafe row version changed before atomic apply", { cause: error10 });
10430
- if (value.includes("unsafe_suid_contradiction")) return new UnsafeWindowMaterializedViewError("UNSAFE_SUID_CONTRADICTION", false, "Unsafe same-SUID payload contradiction", { cause: error10 });
10431
- if (value.includes("unsafe_safe_ahead")) return new UnsafeWindowMaterializedViewError("UNSAFE_SAFE_AHEAD", false, "Safe head already covers unsafe event", { cause: error10 });
10432
- if (value.includes("unsafe_behind_frontier")) return new UnsafeWindowMaterializedViewError("UNSAFE_BEHIND_FRONTIER", false, "Unsafe reads are fail-closed pending rebuild", { cause: error10 });
10664
+ if (value.includes("unsafe_row_cas")) return new UnsafeWindowMaterializedViewError("UNSAFE_ROW_CAS_MISMATCH", true, "Unsafe row version changed before atomic apply", { cause: error11 });
10665
+ if (value.includes("unsafe_suid_contradiction")) return new UnsafeWindowMaterializedViewError("UNSAFE_SUID_CONTRADICTION", false, "Unsafe same-SUID payload contradiction", { cause: error11 });
10666
+ if (value.includes("unsafe_safe_ahead")) return new UnsafeWindowMaterializedViewError("UNSAFE_SAFE_AHEAD", false, "Safe head already covers unsafe event", { cause: error11 });
10667
+ if (value.includes("unsafe_behind_frontier")) return new UnsafeWindowMaterializedViewError("UNSAFE_BEHIND_FRONTIER", false, "Unsafe reads are fail-closed pending rebuild", { cause: error11 });
10433
10668
  return void 0;
10434
10669
  }
10435
10670
  var UnsafeWindowMaterializedViewStore = class {
@@ -10562,8 +10797,8 @@ var UnsafeWindowMaterializedViewStore = class {
10562
10797
  await this.options.beforeApplyBatch?.(input, statements);
10563
10798
  try {
10564
10799
  await this.database.batch(statements);
10565
- } catch (error10) {
10566
- const text = String(error10);
10800
+ } catch (error11) {
10801
+ const text = String(error11);
10567
10802
  const guardFailure = text.includes("mv_atomic_guards") || text.includes("checkpoint_match") || text.includes("mv_unsafe_receipts") && (text.includes("UNIQUE") || text.includes("constraint"));
10568
10803
  if (guardFailure) {
10569
10804
  const receipt = await this.database.prepare(
@@ -10571,16 +10806,16 @@ var UnsafeWindowMaterializedViewStore = class {
10571
10806
  ).bind(input.serviceId, input.viewId, input.eventId).first();
10572
10807
  if (receipt !== null && receipt !== void 0) {
10573
10808
  if (string2(receipt, "suid") !== input.suid) {
10574
- throw new UnsafeWindowMaterializedViewError("UNSAFE_SUID_CONTRADICTION", false, "Duplicate event identity has a contradictory SUID", { cause: error10 });
10809
+ throw new UnsafeWindowMaterializedViewError("UNSAFE_SUID_CONTRADICTION", false, "Duplicate event identity has a contradictory SUID", { cause: error11 });
10575
10810
  }
10576
10811
  if (this.options.beforeApplyBatch !== void 0) {
10577
- throw new UnsafeWindowMaterializedViewError("UNSAFE_DUPLICATE_RACE", false, "Concurrent unsafe receipt was committed by another delivery", { cause: error10 });
10812
+ throw new UnsafeWindowMaterializedViewError("UNSAFE_DUPLICATE_RACE", false, "Concurrent unsafe receipt was committed by another delivery", { cause: error11 });
10578
10813
  }
10579
10814
  return { outcome: "no-change", duplicate: true };
10580
10815
  }
10581
10816
  return this.apply(input, true);
10582
10817
  }
10583
- throw error10;
10818
+ throw error11;
10584
10819
  }
10585
10820
  const result2 = { outcome: "applied", duplicate: false };
10586
10821
  await this.options.afterApplyBatch?.(input, result2);
@@ -10713,13 +10948,13 @@ var UnsafeWindowMaterializedViewStore = class {
10713
10948
  await this.options.beforeApplyBatch?.(input, statements);
10714
10949
  try {
10715
10950
  await this.database.batch(statements);
10716
- } catch (error10) {
10717
- if (sameSuidContradiction) throw new UnsafeWindowMaterializedViewError("UNSAFE_SUID_CONTRADICTION", false, "Unsafe same-SUID payload contradiction", { cause: error10 });
10718
- if (rowCasMismatch) throw new UnsafeWindowMaterializedViewError("UNSAFE_ROW_CAS_MISMATCH", true, "Unsafe row version changed before atomic apply", { cause: error10 });
10719
- if (safeAhead) throw new UnsafeWindowMaterializedViewError("UNSAFE_SAFE_AHEAD", false, "Safe head already covers unsafe event", { cause: error10 });
10720
- const typed = errorFrom(error10);
10951
+ } catch (error11) {
10952
+ if (sameSuidContradiction) throw new UnsafeWindowMaterializedViewError("UNSAFE_SUID_CONTRADICTION", false, "Unsafe same-SUID payload contradiction", { cause: error11 });
10953
+ if (rowCasMismatch) throw new UnsafeWindowMaterializedViewError("UNSAFE_ROW_CAS_MISMATCH", true, "Unsafe row version changed before atomic apply", { cause: error11 });
10954
+ if (safeAhead) throw new UnsafeWindowMaterializedViewError("UNSAFE_SAFE_AHEAD", false, "Safe head already covers unsafe event", { cause: error11 });
10955
+ const typed = errorFrom(error11);
10721
10956
  if (typed !== void 0) throw typed;
10722
- throw error10;
10957
+ throw error11;
10723
10958
  }
10724
10959
  const result2 = { outcome, duplicate: false };
10725
10960
  await this.options.afterApplyBatch?.(input, result2);
@@ -10786,8 +11021,8 @@ var UnsafeWindowMaterializedViewStore = class {
10786
11021
  this.database.prepare(`UPDATE mv_unsafe_kicks SET lease_owner = ?, lease_until = ?, dirty = 0 WHERE service_id = ? AND view_id = ?`).bind(owner, nowMs + leaseMs, serviceId, viewId),
10787
11022
  this.database.prepare("DELETE FROM mv_atomic_guards WHERE operation_id = ?").bind(operation)
10788
11023
  ]);
10789
- } catch (error10) {
10790
- throw new UnsafeWindowMaterializedViewError("UNSAFE_KICK_LEASE_HELD", true, "Unsafe kick is held by another lease owner", { cause: error10 });
11024
+ } catch (error11) {
11025
+ throw new UnsafeWindowMaterializedViewError("UNSAFE_KICK_LEASE_HELD", true, "Unsafe kick is held by another lease owner", { cause: error11 });
10791
11026
  }
10792
11027
  const row = await this.database.prepare(`SELECT target_suid, dirty FROM mv_unsafe_kicks WHERE service_id = ? AND view_id = ?`).bind(serviceId, viewId).first();
10793
11028
  return row === null || row === void 0 ? void 0 : { targetSuid: string2(row, "target_suid"), dirty: integer(row, "dirty") === 1 };
@@ -10861,9 +11096,9 @@ var UnsafeWindowMaterializedViewStore = class {
10861
11096
  try {
10862
11097
  await this.database.batch(statements);
10863
11098
  return true;
10864
- } catch (error10) {
10865
- if (String(error10).includes("mv_atomic_guards") || String(error10).includes("checkpoint_match")) return false;
10866
- throw error10;
11099
+ } catch (error11) {
11100
+ if (String(error11).includes("mv_atomic_guards") || String(error11).includes("checkpoint_match")) return false;
11101
+ throw error11;
10867
11102
  }
10868
11103
  }
10869
11104
  /**
@@ -11029,12 +11264,12 @@ function indexValue(row, type) {
11029
11264
  function operationId2() {
11030
11265
  return `mv-${crypto.randomUUID()}`;
11031
11266
  }
11032
- function isCasFailure(error10) {
11033
- const message = String(error10);
11267
+ function isCasFailure(error11) {
11268
+ const message = String(error11);
11034
11269
  return message.includes("mv_atomic_guards.checkpoint_match") || message.includes("MV_CAS_MISMATCH");
11035
11270
  }
11036
- function isPatchFailure(error10) {
11037
- return String(error10).includes("CHECK constraint failed: checkpoint_match");
11271
+ function isPatchFailure(error11) {
11272
+ return String(error11).includes("CHECK constraint failed: checkpoint_match");
11038
11273
  }
11039
11274
  var D1MaterializedViewStore = class {
11040
11275
  constructor(database) {
@@ -11070,8 +11305,8 @@ var D1MaterializedViewStore = class {
11070
11305
  VALUES (?, ?, ?, ?)`
11071
11306
  ).bind(input.serviceId, input.viewId, generation, input.updatedAt)
11072
11307
  ]);
11073
- } catch (error10) {
11074
- throw new MaterializedViewStoreError("create-active", "MV_INSTANCE_EXISTS", `Active materialized view already exists: ${String(error10)}`, { cause: error10 });
11308
+ } catch (error11) {
11309
+ throw new MaterializedViewStoreError("create-active", "MV_INSTANCE_EXISTS", `Active materialized view already exists: ${String(error11)}`, { cause: error11 });
11075
11310
  }
11076
11311
  return this.readInstance(input.serviceId, input.viewId, generation);
11077
11312
  }
@@ -11092,8 +11327,8 @@ var D1MaterializedViewStore = class {
11092
11327
  input.definitionVersion,
11093
11328
  input.updatedAt
11094
11329
  ).run();
11095
- } catch (error10) {
11096
- throw new MaterializedViewStoreError("create-candidate", "MV_INSTANCE_EXISTS", `Candidate generation already exists: ${String(error10)}`, { cause: error10 });
11330
+ } catch (error11) {
11331
+ throw new MaterializedViewStoreError("create-candidate", "MV_INSTANCE_EXISTS", `Candidate generation already exists: ${String(error11)}`, { cause: error11 });
11097
11332
  }
11098
11333
  return this.readInstance(input.serviceId, input.viewId, input.generation);
11099
11334
  }
@@ -11231,10 +11466,10 @@ var D1MaterializedViewStore = class {
11231
11466
  */
11232
11467
  async readListPage(serviceId, viewId, options = {}) {
11233
11468
  this.ready("initialize");
11234
- const active = await this.readActive(serviceId, viewId);
11235
- if (active === void 0) return { rows: [], totalCount: 0, readHead: "" };
11236
- const selected = options.generation ?? active.generation;
11237
- const selectedInstance = selected === active.generation ? active : await this.readInstance(serviceId, viewId, selected);
11469
+ const active2 = await this.readActive(serviceId, viewId);
11470
+ if (active2 === void 0) return { rows: [], totalCount: 0, readHead: "" };
11471
+ const selected = options.generation ?? active2.generation;
11472
+ const selectedInstance = selected === active2.generation ? active2 : await this.readInstance(serviceId, viewId, selected);
11238
11473
  if (selectedInstance === void 0) {
11239
11474
  throw new MaterializedViewStoreError("initialize", "MV_INSTANCE_MISSING", "Requested materialized-view generation is unavailable");
11240
11475
  }
@@ -11751,10 +11986,10 @@ var D1MaterializedViewStore = class {
11751
11986
  ).bind(operation, `${operation}:%`));
11752
11987
  try {
11753
11988
  await this.database.batch(statements);
11754
- } catch (error10) {
11755
- if (isPatchFailure(error10)) throw new MaterializedViewPatchError();
11756
- if (isCasFailure(error10)) throw new MaterializedViewCasError();
11757
- throw new MaterializedViewStoreError("apply", "MV_STORE_OPERATION_FAILED", `Materialized-view atomic apply failed: ${String(error10)}`, { cause: error10 });
11989
+ } catch (error11) {
11990
+ if (isPatchFailure(error11)) throw new MaterializedViewPatchError();
11991
+ if (isCasFailure(error11)) throw new MaterializedViewCasError();
11992
+ throw new MaterializedViewStoreError("apply", "MV_STORE_OPERATION_FAILED", `Materialized-view atomic apply failed: ${String(error11)}`, { cause: error11 });
11758
11993
  }
11759
11994
  const instance = await this.readInstance(input.serviceId, input.viewId, input.generation);
11760
11995
  if (instance === void 0) throw new MaterializedViewStoreError("apply", "MV_INSTANCE_MISSING", "Materialized-view instance disappeared after apply");
@@ -11859,13 +12094,13 @@ var D1MaterializedViewStore = class {
11859
12094
  ];
11860
12095
  try {
11861
12096
  await this.database.batch(statements);
11862
- } catch (error10) {
11863
- if (isCasFailure(error10)) throw new MaterializedViewPromotionCasError();
11864
- throw new MaterializedViewStoreError("promote", "MV_STORE_OPERATION_FAILED", `Materialized-view promotion failed: ${String(error10)}`, { cause: error10 });
12097
+ } catch (error11) {
12098
+ if (isCasFailure(error11)) throw new MaterializedViewPromotionCasError();
12099
+ throw new MaterializedViewStoreError("promote", "MV_STORE_OPERATION_FAILED", `Materialized-view promotion failed: ${String(error11)}`, { cause: error11 });
11865
12100
  }
11866
- const active = await this.readActive(input.serviceId, input.viewId);
11867
- if (active === void 0) throw new MaterializedViewStoreError("promote", "MV_INSTANCE_MISSING", "Active generation disappeared after promotion");
11868
- return active;
12101
+ const active2 = await this.readActive(input.serviceId, input.viewId);
12102
+ if (active2 === void 0) throw new MaterializedViewStoreError("promote", "MV_INSTANCE_MISSING", "Active generation disappeared after promotion");
12103
+ return active2;
11869
12104
  }
11870
12105
  /** Short aliases make the port convenient for runtime composition and tests. */
11871
12106
  apply = this.applyMutationsAndAdvanceCheckpoint.bind(this);
@@ -11874,8 +12109,8 @@ var D1MaterializedViewStore = class {
11874
12109
  let value;
11875
12110
  try {
11876
12111
  value = assertJsonValue(JSON.parse(asString2(row.value_json, "value_json")), "state-persistence");
11877
- } catch (error10) {
11878
- throw new MaterializedViewStoreError("initialize", "MV_VALUE_INVALID", `Materialized-view row JSON was invalid: ${String(error10)}`, { cause: error10 });
12112
+ } catch (error11) {
12113
+ throw new MaterializedViewStoreError("initialize", "MV_VALUE_INVALID", `Materialized-view row JSON was invalid: ${String(error11)}`, { cause: error11 });
11879
12114
  }
11880
12115
  return {
11881
12116
  serviceId: asString2(row.service_id, "service_id"),
@@ -12522,10 +12757,10 @@ var SerializedReadWorker = class {
12522
12757
  });
12523
12758
  }
12524
12759
  async ensureWindowDeterminate() {
12525
- if (this.storeProvider === void 0 || this.storeProvider.isConfigured?.(this.env) === false) {
12526
- return;
12527
- }
12528
12760
  try {
12761
+ if (this.storeProvider === void 0 || this.storeProvider.isConfigured?.(this.env) === false) {
12762
+ return;
12763
+ }
12529
12764
  const store = this.storeProvider.create(this.env);
12530
12765
  await store.initialize();
12531
12766
  const nowMs = Date.now();
@@ -12566,13 +12801,683 @@ async function handleSerializedRead(request, env, registry = DEPLOYED_PROJECTOR_
12566
12801
  }), registry, storeProvider).handle(request);
12567
12802
  }
12568
12803
 
12804
+ // src/completeness/IncidentLifecycle.ts
12805
+ var MAX_IDENTITY_BYTES = 256;
12806
+ var MAX_LONG_TEXT_BYTES = 2048;
12807
+ var SHA256_DIGEST = /^sha256:[0-9a-f]{64}$/;
12808
+ var IncidentLifecycleError = class extends Error {
12809
+ code;
12810
+ status;
12811
+ constructor(code, status, message) {
12812
+ super(message);
12813
+ this.name = "IncidentLifecycleError";
12814
+ this.code = code;
12815
+ this.status = status;
12816
+ }
12817
+ };
12818
+ function isObject11(value) {
12819
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12820
+ }
12821
+ function hasOnlyKeys(value, keys) {
12822
+ const allowed = new Set(keys);
12823
+ return Object.keys(value).every((key) => allowed.has(key));
12824
+ }
12825
+ function bytes(value) {
12826
+ return new TextEncoder().encode(value).byteLength;
12827
+ }
12828
+ function boundedString(value, name, maximum, required = true) {
12829
+ if (typeof value !== "string") {
12830
+ throw new IncidentLifecycleError("incident_invalid_request", 400, `${name} must be a string`);
12831
+ }
12832
+ const normalized = value.trim();
12833
+ if (required && normalized.length === 0) {
12834
+ throw new IncidentLifecycleError("incident_invalid_request", 400, `${name} must be non-empty`);
12835
+ }
12836
+ if (bytes(normalized) > maximum) {
12837
+ throw new IncidentLifecycleError("incident_invalid_request", 400, `${name} is too long`);
12838
+ }
12839
+ return normalized.length === 0 ? null : normalized;
12840
+ }
12841
+ function normalizeIncidentIdentity(value) {
12842
+ const identity2 = boundedString(value, "incidentIdentity", MAX_IDENTITY_BYTES);
12843
+ if (identity2 === null) {
12844
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "incidentIdentity must be non-empty");
12845
+ }
12846
+ return identity2;
12847
+ }
12848
+ function safeInteger(value, name) {
12849
+ if (typeof value !== "number" || !Number.isSafeInteger(value)) {
12850
+ throw new IncidentLifecycleError("incident_invalid_request", 400, `${name} must be a safe integer`);
12851
+ }
12852
+ return value;
12853
+ }
12854
+ function normalizeCorrection(value) {
12855
+ if (!isObject11(value) || !hasOnlyKeys(value, ["kind", "reference", "digest"])) {
12856
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "correction has unknown or missing keys");
12857
+ }
12858
+ if (value.kind !== "event" && value.kind !== "receipt") {
12859
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "correction.kind must be event or receipt");
12860
+ }
12861
+ const reference = boundedString(value.reference, "correction.reference", MAX_LONG_TEXT_BYTES);
12862
+ const digest2 = boundedString(value.digest, "correction.digest", MAX_IDENTITY_BYTES);
12863
+ if (reference === null || digest2 === null || !SHA256_DIGEST.test(digest2)) {
12864
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "correction.digest must be lowercase sha256");
12865
+ }
12866
+ return { kind: value.kind, reference, digest: digest2 };
12867
+ }
12868
+ function normalizeRequest(value) {
12869
+ if (!isObject11(value) || !hasOnlyKeys(value, ["action", "incidentIdentity", "transitionKey", "expectedVersion", "reason", "ownerId", "deadlineAt", "correction", "resolution"])) {
12870
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "transition has unknown keys");
12871
+ }
12872
+ const action = value.action;
12873
+ if (typeof action !== "string" || !["ACKNOWLEDGE", "UPDATE_ASSIGNMENT", "RECORD_CORRECTION", "CLOSE", "REOPEN"].includes(action)) {
12874
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "transition action is invalid");
12875
+ }
12876
+ const actionKeys = action === "RECORD_CORRECTION" ? ["action", "incidentIdentity", "transitionKey", "expectedVersion", "reason", "correction"] : action === "CLOSE" ? ["action", "incidentIdentity", "transitionKey", "expectedVersion", "reason", "resolution"] : ["action", "incidentIdentity", "transitionKey", "expectedVersion", "reason", "ownerId", "deadlineAt"];
12877
+ if (!hasOnlyKeys(value, actionKeys)) {
12878
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "transition has keys not valid for its action");
12879
+ }
12880
+ const base = {
12881
+ incidentIdentity: normalizeIncidentIdentity(value.incidentIdentity),
12882
+ transitionKey: boundedString(value.transitionKey, "transitionKey", MAX_IDENTITY_BYTES),
12883
+ expectedVersion: safeInteger(value.expectedVersion, "expectedVersion"),
12884
+ reason: boundedString(value.reason, "reason", MAX_LONG_TEXT_BYTES)
12885
+ };
12886
+ if (base.expectedVersion < 0) {
12887
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "expectedVersion must not be negative");
12888
+ }
12889
+ if (action === "ACKNOWLEDGE" || action === "UPDATE_ASSIGNMENT" || action === "REOPEN") {
12890
+ const ownerId = boundedString(value.ownerId, "ownerId", MAX_IDENTITY_BYTES);
12891
+ const deadlineAt = safeInteger(value.deadlineAt, "deadlineAt");
12892
+ if (ownerId === null) throw new IncidentLifecycleError("incident_invalid_request", 400, "ownerId must be non-empty");
12893
+ return { ...base, action, ownerId, deadlineAt };
12894
+ }
12895
+ if (action === "RECORD_CORRECTION") {
12896
+ return { ...base, action, correction: normalizeCorrection(value.correction) };
12897
+ }
12898
+ if (!isObject11(value.resolution) || !hasOnlyKeys(value.resolution, ["kind", "explanation"])) {
12899
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "resolution has unknown or missing keys");
12900
+ }
12901
+ if (value.resolution.kind === "CORRECTED") {
12902
+ if (value.resolution.explanation !== void 0) {
12903
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "CORRECTED resolution has unknown keys");
12904
+ }
12905
+ return { ...base, action, resolution: { kind: "CORRECTED" } };
12906
+ }
12907
+ if (value.resolution.kind === "ACCEPTED_AS_IS") {
12908
+ const explanation = boundedString(value.resolution.explanation, "resolution.explanation", MAX_LONG_TEXT_BYTES);
12909
+ if (explanation === null) throw new IncidentLifecycleError("incident_invalid_request", 400, "resolution.explanation is required");
12910
+ return { ...base, action, resolution: { kind: "ACCEPTED_AS_IS", explanation } };
12911
+ }
12912
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "resolution.kind is invalid");
12913
+ }
12914
+ function canonicalize(value) {
12915
+ if (Array.isArray(value)) return value.map(canonicalize);
12916
+ if (!isObject11(value)) return value;
12917
+ return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalize(value[key])]));
12918
+ }
12919
+ async function digestFor(request, actorId) {
12920
+ const envelope = canonicalize({ action: request, actor: actorId });
12921
+ const encoded = new TextEncoder().encode(JSON.stringify(envelope));
12922
+ const digest2 = await crypto.subtle.digest("SHA-256", encoded);
12923
+ return `sha256:${Array.from(new Uint8Array(digest2), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
12924
+ }
12925
+ function projectionFromRow(row, finding2) {
12926
+ if (row === null) {
12927
+ return {
12928
+ serviceId: finding2.service_id,
12929
+ incidentIdentity: finding2.incident_identity,
12930
+ lifecycleState: "OPEN",
12931
+ ownerId: null,
12932
+ deadlineAt: null,
12933
+ correction: null,
12934
+ closeResolution: null,
12935
+ closeReason: null,
12936
+ version: 0,
12937
+ lastTransitionKey: "",
12938
+ updatedAt: finding2.last_observed_at
12939
+ };
12940
+ }
12941
+ return {
12942
+ serviceId: row.service_id,
12943
+ incidentIdentity: row.incident_identity,
12944
+ lifecycleState: row.lifecycle_state,
12945
+ ownerId: row.owner_id,
12946
+ deadlineAt: row.deadline_at,
12947
+ correction: row.correction_kind === null ? null : {
12948
+ kind: row.correction_kind,
12949
+ reference: row.correction_reference,
12950
+ digest: row.correction_digest
12951
+ },
12952
+ closeResolution: row.close_resolution,
12953
+ closeReason: row.close_reason,
12954
+ version: row.version,
12955
+ lastTransitionKey: row.last_transition_key,
12956
+ updatedAt: row.updated_at
12957
+ };
12958
+ }
12959
+ function findingFromRow(row) {
12960
+ return {
12961
+ serviceId: row.service_id,
12962
+ incidentIdentity: row.incident_identity,
12963
+ incidentType: row.incident_type,
12964
+ partitionTag: row.partition_tag,
12965
+ obligationSequence: row.obligation_sequence,
12966
+ eventId: row.event_id,
12967
+ eventDigest: row.event_digest,
12968
+ state: row.finding_state,
12969
+ firstObservedAt: row.first_observed_at,
12970
+ lastObservedAt: row.last_observed_at
12971
+ };
12972
+ }
12973
+ function transitionFromRow(row) {
12974
+ const before = projectionFromAudit(row, "before");
12975
+ const after = projectionFromAudit(row, "after");
12976
+ return {
12977
+ transitionId: row.transition_id,
12978
+ serviceId: row.service_id,
12979
+ incidentIdentity: row.incident_identity,
12980
+ transitionKey: row.transition_key,
12981
+ requestDigest: row.request_digest,
12982
+ action: row.action,
12983
+ fromState: row.from_state,
12984
+ toState: row.to_state,
12985
+ fromVersion: row.from_version,
12986
+ toVersion: row.to_version,
12987
+ actorId: row.actor_id,
12988
+ before,
12989
+ after,
12990
+ reason: row.reason,
12991
+ occurredAt: row.occurred_at
12992
+ };
12993
+ }
12994
+ function projectionFromAudit(row, prefix) {
12995
+ const state = prefix === "before" ? row.from_state : row.to_state;
12996
+ const version = prefix === "before" ? row.from_version : row.to_version;
12997
+ const ownerId = row[`${prefix}_owner_id`];
12998
+ const correctionKind = row[`${prefix}_correction_kind`];
12999
+ return {
13000
+ serviceId: row.service_id,
13001
+ incidentIdentity: row.incident_identity,
13002
+ lifecycleState: state,
13003
+ ownerId,
13004
+ deadlineAt: row[`${prefix}_deadline_at`],
13005
+ correction: correctionKind === null ? null : {
13006
+ kind: correctionKind,
13007
+ reference: row[`${prefix}_correction_reference`],
13008
+ digest: row[`${prefix}_correction_digest`]
13009
+ },
13010
+ closeResolution: row[`${prefix}_close_resolution`],
13011
+ closeReason: row[`${prefix}_close_reason`],
13012
+ version,
13013
+ lastTransitionKey: prefix === "after" ? row.transition_key : "",
13014
+ updatedAt: row.occurred_at
13015
+ };
13016
+ }
13017
+ function active(state) {
13018
+ return state !== "CLOSED";
13019
+ }
13020
+ function compareItems(left, right) {
13021
+ if (left.overdue !== right.overdue) return left.overdue ? -1 : 1;
13022
+ if (left.unowned !== right.unowned) return left.unowned ? -1 : 1;
13023
+ if (left.finding.lastObservedAt !== right.finding.lastObservedAt) return right.finding.lastObservedAt - left.finding.lastObservedAt;
13024
+ return left.finding.incidentIdentity < right.finding.incidentIdentity ? -1 : left.finding.incidentIdentity > right.finding.incidentIdentity ? 1 : 0;
13025
+ }
13026
+ var IncidentLifecycle = class {
13027
+ constructor(database, now2 = () => Date.now()) {
13028
+ this.database = database;
13029
+ this.now = now2;
13030
+ }
13031
+ database;
13032
+ now;
13033
+ static parseTransition(value) {
13034
+ return normalizeRequest(value);
13035
+ }
13036
+ async finding(serviceId, incidentIdentity) {
13037
+ const row = await this.database.prepare(
13038
+ `SELECT service_id, incident_identity, incident_type, partition_tag,
13039
+ obligation_sequence, event_id, event_digest, state AS finding_state,
13040
+ first_observed_at, last_observed_at
13041
+ FROM serialized_dcb_completeness_findings
13042
+ WHERE service_id = ? AND incident_identity = ?`
13043
+ ).bind(serviceId, incidentIdentity).first();
13044
+ if (row === null || row === void 0) {
13045
+ throw new IncidentLifecycleError("incident_not_found", 404, "The completeness incident was not found");
13046
+ }
13047
+ return row;
13048
+ }
13049
+ async lifecycle(serviceId, incidentIdentity) {
13050
+ const row = await this.database.prepare(
13051
+ `SELECT service_id, incident_identity, lifecycle_state, owner_id, deadline_at,
13052
+ correction_kind, correction_reference, correction_digest,
13053
+ close_resolution, close_reason, version, last_transition_key, updated_at
13054
+ FROM serialized_dcb_incident_lifecycles
13055
+ WHERE service_id = ? AND incident_identity = ?`
13056
+ ).bind(serviceId, incidentIdentity).first();
13057
+ return row === void 0 ? null : row;
13058
+ }
13059
+ async transitions(serviceId, incidentIdentity) {
13060
+ const result2 = await this.database.prepare(
13061
+ `SELECT * FROM serialized_dcb_incident_transitions
13062
+ WHERE service_id = ? AND incident_identity = ?
13063
+ ORDER BY transition_id ASC`
13064
+ ).bind(serviceId, incidentIdentity).all();
13065
+ return result2.results.map(transitionFromRow);
13066
+ }
13067
+ async closeTime(serviceId, incidentIdentity) {
13068
+ const row = await this.database.prepare(
13069
+ `SELECT occurred_at FROM serialized_dcb_incident_transitions
13070
+ WHERE service_id = ? AND incident_identity = ? AND to_state = 'CLOSED'
13071
+ ORDER BY transition_id DESC LIMIT 1`
13072
+ ).bind(serviceId, incidentIdentity).first();
13073
+ return row?.occurred_at ?? null;
13074
+ }
13075
+ async item(finding2, row, at) {
13076
+ const lifecycle = projectionFromRow(row, finding2);
13077
+ const closeTime = lifecycle.lifecycleState === "OPEN" && row === null ? null : await this.closeTime(finding2.service_id, finding2.incident_identity);
13078
+ const observedAfterClose = closeTime !== null && finding2.last_observed_at > closeTime;
13079
+ const overdue = active(lifecycle.lifecycleState) && lifecycle.deadlineAt !== null && lifecycle.deadlineAt < at;
13080
+ return {
13081
+ finding: findingFromRow(finding2),
13082
+ lifecycle,
13083
+ overdue,
13084
+ unowned: lifecycle.ownerId === null,
13085
+ observedAfterClose
13086
+ };
13087
+ }
13088
+ async list(serviceId, filters = {}, at = this.now()) {
13089
+ const rows = await this.database.prepare(
13090
+ `SELECT service_id, incident_identity, incident_type, partition_tag,
13091
+ obligation_sequence, event_id, event_digest, state AS finding_state,
13092
+ first_observed_at, last_observed_at
13093
+ FROM serialized_dcb_completeness_findings
13094
+ WHERE service_id = ?`
13095
+ ).bind(serviceId).all();
13096
+ const items = [];
13097
+ for (const finding2 of rows.results) {
13098
+ const item = await this.item(finding2, await this.lifecycle(serviceId, finding2.incident_identity), at);
13099
+ if (filters.state !== void 0 && item.lifecycle.lifecycleState !== filters.state) continue;
13100
+ if (filters.owner !== void 0 && item.lifecycle.ownerId !== filters.owner) continue;
13101
+ if (filters.unowned === true && !item.unowned) continue;
13102
+ if (filters.overdue === true && !item.overdue) continue;
13103
+ if (filters.observedAfterClose === true && !item.observedAfterClose) continue;
13104
+ items.push(item);
13105
+ }
13106
+ items.sort(compareItems);
13107
+ const byState = {
13108
+ OPEN: 0,
13109
+ ACKNOWLEDGED: 0,
13110
+ CORRECTION_RECORDED: 0,
13111
+ CLOSED: 0,
13112
+ REOPENED: 0
13113
+ };
13114
+ for (const item of items) byState[item.lifecycle.lifecycleState] += 1;
13115
+ return {
13116
+ items,
13117
+ summary: {
13118
+ total: items.length,
13119
+ byState,
13120
+ unowned: items.filter((item) => item.unowned).length,
13121
+ overdue: items.filter((item) => item.overdue).length,
13122
+ observedAfterClose: items.filter((item) => item.observedAfterClose).length
13123
+ }
13124
+ };
13125
+ }
13126
+ async detail(serviceId, incidentIdentity, at = this.now()) {
13127
+ const finding2 = await this.finding(serviceId, incidentIdentity);
13128
+ const lifecycle = await this.lifecycle(serviceId, incidentIdentity);
13129
+ const item = await this.item(finding2, lifecycle, at);
13130
+ return {
13131
+ finding: item.finding,
13132
+ lifecycle: item.lifecycle,
13133
+ flags: { overdue: item.overdue, unowned: item.unowned, observedAfterClose: item.observedAfterClose },
13134
+ transitions: await this.transitions(serviceId, incidentIdentity)
13135
+ };
13136
+ }
13137
+ async transition(serviceId, value, actor) {
13138
+ const request = normalizeRequest(value);
13139
+ let actorId;
13140
+ try {
13141
+ actorId = boundedString(actor, "x-sdt-maintainer", MAX_IDENTITY_BYTES);
13142
+ } catch (caught) {
13143
+ if (caught instanceof IncidentLifecycleError && caught.code === "incident_invalid_request") {
13144
+ throw new IncidentLifecycleError("incident_invalid_actor", 400, caught.message);
13145
+ }
13146
+ throw caught;
13147
+ }
13148
+ if (actorId === null) throw new IncidentLifecycleError("incident_invalid_actor", 400, "x-sdt-maintainer must be non-empty");
13149
+ const finding2 = await this.finding(serviceId, request.incidentIdentity);
13150
+ const digest2 = await digestFor(request, actorId);
13151
+ const existing = await this.database.prepare(
13152
+ `SELECT * FROM serialized_dcb_incident_transitions
13153
+ WHERE service_id = ? AND incident_identity = ? AND transition_key = ?`
13154
+ ).bind(serviceId, request.incidentIdentity, request.transitionKey).first();
13155
+ if (existing !== null && existing !== void 0) {
13156
+ if (existing.request_digest !== digest2) {
13157
+ throw new IncidentLifecycleError("incident_idempotency_conflict", 409, "The transition key was already used with different content");
13158
+ }
13159
+ return { projection: transitionFromRow(existing).after, transition: transitionFromRow(existing), idempotent: true };
13160
+ }
13161
+ const priorRow = await this.lifecycle(serviceId, request.incidentIdentity);
13162
+ const before = projectionFromRow(priorRow, finding2);
13163
+ if (before.version !== request.expectedVersion) {
13164
+ throw new IncidentLifecycleError("incident_version_conflict", 409, "The incident version is stale");
13165
+ }
13166
+ const at = this.now();
13167
+ const after = this.nextProjection(before, request, at);
13168
+ const newVersion = before.version + 1;
13169
+ const occurredAt = at;
13170
+ const seed = this.database.prepare(
13171
+ `INSERT INTO serialized_dcb_incident_lifecycles
13172
+ (service_id, incident_identity, lifecycle_state, version, last_transition_key, updated_at)
13173
+ VALUES (?, ?, 'OPEN', 0, '', ?)
13174
+ ON CONFLICT (service_id, incident_identity) DO NOTHING`
13175
+ ).bind(serviceId, request.incidentIdentity, occurredAt);
13176
+ const update = this.database.prepare(
13177
+ `UPDATE serialized_dcb_incident_lifecycles
13178
+ SET lifecycle_state = ?, owner_id = ?, deadline_at = ?,
13179
+ correction_kind = ?, correction_reference = ?, correction_digest = ?,
13180
+ close_resolution = ?, close_reason = ?, version = ?,
13181
+ last_transition_key = ?, updated_at = ?
13182
+ WHERE service_id = ? AND incident_identity = ? AND version = ?
13183
+ AND last_transition_key <> ?`
13184
+ ).bind(
13185
+ after.lifecycleState,
13186
+ after.ownerId,
13187
+ after.deadlineAt,
13188
+ after.correction?.kind ?? null,
13189
+ after.correction?.reference ?? null,
13190
+ after.correction?.digest ?? null,
13191
+ after.closeResolution,
13192
+ after.closeReason,
13193
+ newVersion,
13194
+ request.transitionKey,
13195
+ occurredAt,
13196
+ serviceId,
13197
+ request.incidentIdentity,
13198
+ before.version,
13199
+ request.transitionKey
13200
+ );
13201
+ const audit = this.database.prepare(
13202
+ `INSERT INTO serialized_dcb_incident_transitions
13203
+ (service_id, incident_identity, transition_key, request_digest, action,
13204
+ from_state, to_state, from_version, to_version, actor_id,
13205
+ before_owner_id, before_deadline_at, before_correction_kind,
13206
+ before_correction_reference, before_correction_digest, before_close_resolution,
13207
+ before_close_reason, after_owner_id, after_deadline_at, after_correction_kind,
13208
+ after_correction_reference, after_correction_digest, after_close_resolution,
13209
+ after_close_reason, reason, occurred_at)
13210
+ SELECT ?, ?, ?, ?, ?, ?, lifecycle_state, ?, version, ?,
13211
+ ?, ?, ?, ?, ?, ?, ?, owner_id, deadline_at, correction_kind,
13212
+ correction_reference, correction_digest, close_resolution, close_reason, ?, ?
13213
+ FROM serialized_dcb_incident_lifecycles
13214
+ WHERE service_id = ? AND incident_identity = ? AND version = ? AND last_transition_key = ?`
13215
+ ).bind(
13216
+ serviceId,
13217
+ request.incidentIdentity,
13218
+ request.transitionKey,
13219
+ digest2,
13220
+ request.action,
13221
+ before.lifecycleState,
13222
+ before.version,
13223
+ actorId,
13224
+ before.ownerId,
13225
+ before.deadlineAt,
13226
+ before.correction?.kind ?? null,
13227
+ before.correction?.reference ?? null,
13228
+ before.correction?.digest ?? null,
13229
+ before.closeResolution,
13230
+ before.closeReason,
13231
+ request.reason,
13232
+ occurredAt,
13233
+ serviceId,
13234
+ request.incidentIdentity,
13235
+ newVersion,
13236
+ request.transitionKey
13237
+ );
13238
+ await this.database.batch([seed, update, audit]);
13239
+ const inserted = await this.database.prepare(
13240
+ `SELECT * FROM serialized_dcb_incident_transitions
13241
+ WHERE service_id = ? AND incident_identity = ? AND transition_key = ?`
13242
+ ).bind(serviceId, request.incidentIdentity, request.transitionKey).first();
13243
+ if (inserted === null || inserted === void 0) {
13244
+ const competing = await this.database.prepare(
13245
+ `SELECT * FROM serialized_dcb_incident_transitions
13246
+ WHERE service_id = ? AND incident_identity = ? AND transition_key = ?`
13247
+ ).bind(serviceId, request.incidentIdentity, request.transitionKey).first();
13248
+ if (competing !== null && competing !== void 0 && competing.request_digest !== digest2) {
13249
+ throw new IncidentLifecycleError("incident_idempotency_conflict", 409, "The transition key was already used with different content");
13250
+ }
13251
+ if (competing !== null && competing !== void 0) {
13252
+ const transition2 = transitionFromRow(competing);
13253
+ return { projection: transition2.after, transition: transition2, idempotent: true };
13254
+ }
13255
+ throw new IncidentLifecycleError("incident_version_conflict", 409, "The incident version is stale");
13256
+ }
13257
+ const transition = transitionFromRow(inserted);
13258
+ return { projection: transition.after, transition, idempotent: false };
13259
+ }
13260
+ nextProjection(before, request, at) {
13261
+ const laterDeadline = (deadlineAt2) => {
13262
+ if (deadlineAt2 <= at) throw new IncidentLifecycleError("incident_invalid_deadline", 400, "deadlineAt must be in the future");
13263
+ return deadlineAt2;
13264
+ };
13265
+ let lifecycleState;
13266
+ let ownerId = before.ownerId;
13267
+ let deadlineAt = before.deadlineAt;
13268
+ let correction = before.correction;
13269
+ let closeResolution = before.closeResolution;
13270
+ let closeReason = before.closeReason;
13271
+ if (request.action === "ACKNOWLEDGE") {
13272
+ if (before.lifecycleState !== "OPEN" && before.lifecycleState !== "REOPENED") {
13273
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "The incident cannot be acknowledged from its current state");
13274
+ }
13275
+ lifecycleState = "ACKNOWLEDGED";
13276
+ ownerId = request.ownerId;
13277
+ deadlineAt = laterDeadline(request.deadlineAt);
13278
+ correction = null;
13279
+ closeResolution = null;
13280
+ closeReason = null;
13281
+ } else if (request.action === "UPDATE_ASSIGNMENT") {
13282
+ if (before.lifecycleState !== "ACKNOWLEDGED" && before.lifecycleState !== "CORRECTION_RECORDED") {
13283
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "The incident cannot be reassigned from its current state");
13284
+ }
13285
+ lifecycleState = before.lifecycleState;
13286
+ ownerId = request.ownerId;
13287
+ deadlineAt = laterDeadline(request.deadlineAt);
13288
+ } else if (request.action === "RECORD_CORRECTION") {
13289
+ if (before.lifecycleState !== "ACKNOWLEDGED") {
13290
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "The incident must be acknowledged before correction evidence");
13291
+ }
13292
+ lifecycleState = "CORRECTION_RECORDED";
13293
+ correction = request.correction;
13294
+ } else if (request.action === "CLOSE") {
13295
+ if (before.ownerId === null || before.deadlineAt === null) {
13296
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "The incident must have an owner and deadline before closure");
13297
+ }
13298
+ if (request.resolution.kind === "CORRECTED") {
13299
+ if (before.lifecycleState !== "CORRECTION_RECORDED") {
13300
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "A corrected closure requires recorded correction evidence");
13301
+ }
13302
+ lifecycleState = "CLOSED";
13303
+ closeResolution = "CORRECTED";
13304
+ closeReason = request.reason;
13305
+ } else {
13306
+ if (before.lifecycleState !== "ACKNOWLEDGED") {
13307
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "Accepted-as-is closure requires an acknowledged incident");
13308
+ }
13309
+ lifecycleState = "CLOSED";
13310
+ closeResolution = "ACCEPTED_AS_IS";
13311
+ closeReason = request.resolution.explanation;
13312
+ correction = null;
13313
+ }
13314
+ } else {
13315
+ if (before.lifecycleState !== "CLOSED") {
13316
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "Only a closed incident can be reopened");
13317
+ }
13318
+ lifecycleState = "REOPENED";
13319
+ ownerId = request.ownerId;
13320
+ deadlineAt = laterDeadline(request.deadlineAt);
13321
+ correction = null;
13322
+ closeResolution = null;
13323
+ closeReason = null;
13324
+ }
13325
+ return {
13326
+ ...before,
13327
+ lifecycleState,
13328
+ ownerId,
13329
+ deadlineAt,
13330
+ correction,
13331
+ closeResolution,
13332
+ closeReason,
13333
+ version: before.version + 1,
13334
+ lastTransitionKey: request.transitionKey,
13335
+ updatedAt: at
13336
+ };
13337
+ }
13338
+ };
13339
+
13340
+ // src/http/IncidentMaintenance.ts
13341
+ function json10(body, status = 200) {
13342
+ return new Response(JSON.stringify(body), {
13343
+ status,
13344
+ headers: { "content-type": "application/json; charset=utf-8" }
13345
+ });
13346
+ }
13347
+ function error8(status, code, message) {
13348
+ return json10({ error: message, code }, status);
13349
+ }
13350
+ function configuredToken(value) {
13351
+ if (typeof value !== "string") return void 0;
13352
+ const token = value.trim();
13353
+ return token.length === 0 ? void 0 : token;
13354
+ }
13355
+ async function digest(value) {
13356
+ const bytes2 = new TextEncoder().encode(value);
13357
+ return new Uint8Array(await crypto.subtle.digest("SHA-256", bytes2));
13358
+ }
13359
+ function fixedLengthEqual(left, right) {
13360
+ let difference = left.length ^ right.length;
13361
+ const length = Math.max(left.length, right.length);
13362
+ for (let index = 0; index < length; index += 1) {
13363
+ difference |= (left[index] ?? 0) ^ (right[index] ?? 0);
13364
+ }
13365
+ return difference === 0;
13366
+ }
13367
+ async function authenticated(request, token) {
13368
+ const credential = request.headers.get("authorization") ?? "";
13369
+ const suppliedToken = credential.startsWith("Bearer ") ? credential.slice("Bearer ".length) : "";
13370
+ const [expectedDigest, suppliedDigest] = await Promise.all([digest(token), digest(suppliedToken)]);
13371
+ return fixedLengthEqual(expectedDigest, suppliedDigest);
13372
+ }
13373
+ function boolFilter(value, name) {
13374
+ if (value === null) return void 0;
13375
+ if (value === "true") return true;
13376
+ if (value === "false") return false;
13377
+ throw new IncidentLifecycleError("incident_invalid_filter", 400, `${name} must be true or false`);
13378
+ }
13379
+ function parseFilters(url) {
13380
+ const allowed = /* @__PURE__ */ new Set(["state", "owner", "unowned", "overdue", "observedAfterClose"]);
13381
+ let unknown = false;
13382
+ url.searchParams.forEach((_value, key) => {
13383
+ if (!allowed.has(key)) unknown = true;
13384
+ });
13385
+ if (unknown) throw new IncidentLifecycleError("incident_invalid_filter", 400, "Unknown incident list filter");
13386
+ const state = url.searchParams.get("state");
13387
+ if (state !== null && !["OPEN", "ACKNOWLEDGED", "CORRECTION_RECORDED", "CLOSED", "REOPENED"].includes(state)) {
13388
+ throw new IncidentLifecycleError("incident_invalid_filter", 400, "state is invalid");
13389
+ }
13390
+ const owner = url.searchParams.get("owner");
13391
+ if (owner !== null) {
13392
+ const normalizedOwner = owner.trim();
13393
+ if (normalizedOwner.length === 0) {
13394
+ throw new IncidentLifecycleError("incident_invalid_filter", 400, "owner must be non-empty");
13395
+ }
13396
+ if (new TextEncoder().encode(normalizedOwner).byteLength > 256) {
13397
+ throw new IncidentLifecycleError("incident_invalid_filter", 400, "owner is too long");
13398
+ }
13399
+ }
13400
+ const unowned = boolFilter(url.searchParams.get("unowned"), "unowned");
13401
+ const overdue = boolFilter(url.searchParams.get("overdue"), "overdue");
13402
+ const observedAfterClose = boolFilter(url.searchParams.get("observedAfterClose"), "observedAfterClose");
13403
+ return {
13404
+ ...state === null ? {} : { state },
13405
+ ...owner === null ? {} : { owner: owner.trim() },
13406
+ ...unowned === void 0 ? {} : { unowned },
13407
+ ...overdue === void 0 ? {} : { overdue },
13408
+ ...observedAfterClose === void 0 ? {} : { observedAfterClose }
13409
+ };
13410
+ }
13411
+ function incidentIdentityFromPath(pathname) {
13412
+ const encoded = pathname.slice("/maintenance/incidents/".length);
13413
+ if (encoded.length === 0 || encoded.includes("/")) {
13414
+ throw new IncidentLifecycleError("incident_route_not_found", 404, "Incident route not found");
13415
+ }
13416
+ try {
13417
+ return normalizeIncidentIdentity(decodeURIComponent(encoded));
13418
+ } catch {
13419
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "Incident identity must be URI encoded");
13420
+ }
13421
+ }
13422
+ function isIncidentMaintenancePath(pathname) {
13423
+ return pathname === "/maintenance/incidents" || pathname.startsWith("/maintenance/incidents/");
13424
+ }
13425
+ async function handleIncidentMaintenance(request, env, serviceIdentityProvider) {
13426
+ const token = configuredToken(env.INCIDENT_MAINTAINER_TOKEN);
13427
+ if (token === void 0) {
13428
+ return error8(503, "incident_maintenance_unavailable", "Incident maintenance is not configured");
13429
+ }
13430
+ if (!await authenticated(request, token)) {
13431
+ return error8(401, "incident_auth_required", "A valid incident maintenance bearer token is required");
13432
+ }
13433
+ let serviceId;
13434
+ try {
13435
+ serviceId = requestServiceIdentity(request, serviceIdentityProvider, {
13436
+ allowG11Verification: env.G11_VERIFICATION_ENABLED === "true"
13437
+ });
13438
+ } catch {
13439
+ return error8(503, "scope.identity_missing", "A deployment service identity is required for this scope");
13440
+ }
13441
+ if (env.D1 === void 0) {
13442
+ return error8(503, "incident_maintenance_unavailable", "Incident maintenance storage is unavailable");
13443
+ }
13444
+ const lifecycle = new IncidentLifecycle(env.D1);
13445
+ const url = new URL(request.url);
13446
+ try {
13447
+ if (request.method === "GET" && url.pathname === "/maintenance/incidents") {
13448
+ return json10(await lifecycle.list(serviceId, parseFilters(url)));
13449
+ }
13450
+ if (request.method === "GET" && url.pathname.startsWith("/maintenance/incidents/")) {
13451
+ return json10(await lifecycle.detail(serviceId, incidentIdentityFromPath(url.pathname)));
13452
+ }
13453
+ if (request.method === "POST" && url.pathname === "/maintenance/incidents/transitions") {
13454
+ let body;
13455
+ try {
13456
+ body = await request.json();
13457
+ } catch {
13458
+ return error8(400, "incident_invalid_request", "Transition request must be JSON");
13459
+ }
13460
+ const requestValue = IncidentLifecycle.parseTransition(body);
13461
+ const actor = request.headers.get("x-sdt-maintainer");
13462
+ if (actor === null) {
13463
+ return error8(400, "incident_invalid_actor", "x-sdt-maintainer is required");
13464
+ }
13465
+ return json10(await lifecycle.transition(serviceId, requestValue, actor));
13466
+ }
13467
+ return error8(404, "incident_route_not_found", "Incident maintenance route not found");
13468
+ } catch (caught) {
13469
+ if (caught instanceof IncidentLifecycleError) return error8(caught.status, caught.code, caught.message);
13470
+ return error8(500, "incident_maintenance_failed", "Incident maintenance could not complete the request");
13471
+ }
13472
+ }
13473
+
12569
13474
  // src/downstream/Doorbell.ts
12570
13475
  var MAX_SERVICE_BINDING_INVOCATIONS_PER_REQUEST = 32;
12571
- function classifyDirectDoorbellFailure(error10) {
12572
- const structured = typeof error10 === "object" && error10 !== null ? error10 : {};
13476
+ function classifyDirectDoorbellFailure(error11) {
13477
+ const structured = typeof error11 === "object" && error11 !== null ? error11 : {};
12573
13478
  const status = typeof structured.status === "number" ? structured.status : typeof structured.statusCode === "number" ? structured.statusCode : void 0;
12574
13479
  if (status !== void 0 && (status < 200 || status >= 300)) return "non-2xx";
12575
- const value = String(error10).toLowerCase();
13480
+ const value = String(error11).toLowerCase();
12576
13481
  const code = `${String(structured.code ?? "")} ${String(structured.name ?? "")}`.toLowerCase();
12577
13482
  if (value.includes("timeout") || value.includes("deadline") || code.includes("timeout")) return "timeout";
12578
13483
  if (value.includes("cancel") || value.includes("abort") || code.includes("abort")) return "cancel";
@@ -12815,6 +13720,7 @@ var TAG_SQL_SCHEMA_DDL = `
12815
13720
  committed_event_count INTEGER NOT NULL,
12816
13721
  head_suid TEXT NOT NULL,
12817
13722
  reservation_confirmed INTEGER NOT NULL CHECK (reservation_confirmed IN (0, 1)),
13723
+ written_version INTEGER NOT NULL,
12818
13724
  PRIMARY KEY (attempt_id, epoch)
12819
13725
  );
12820
13726
 
@@ -12865,6 +13771,12 @@ var TAG_READ_AFTER_THROUGH_SQL = `
12865
13771
  `;
12866
13772
  function initializeTagSqlSchema(sql) {
12867
13773
  sql.exec(TAG_SQL_SCHEMA_DDL);
13774
+ ensureTagCommitReceiptWrittenVersion(sql);
13775
+ }
13776
+ function ensureTagCommitReceiptWrittenVersion(sql) {
13777
+ const columns = sql.exec("SELECT name FROM pragma_table_info('tag_commit_receipt')").toArray();
13778
+ if (columns.some((column) => column.name === "written_version")) return;
13779
+ sql.exec("ALTER TABLE tag_commit_receipt ADD COLUMN written_version INTEGER");
12868
13780
  }
12869
13781
  function hasTagSqlStorage(storage) {
12870
13782
  return typeof storage.sql?.exec === "function";
@@ -13042,8 +13954,8 @@ function asNumber2(value, name) {
13042
13954
  if (!Number.isSafeInteger(number)) throw new Error(`D1 ${name} was not a safe integer`);
13043
13955
  return number;
13044
13956
  }
13045
- function errorText3(error10) {
13046
- return (error10 instanceof Error ? error10.message : String(error10)).slice(0, 256);
13957
+ function errorText3(error11) {
13958
+ return (error11 instanceof Error ? error11.message : String(error11)).slice(0, 256);
13047
13959
  }
13048
13960
  function sortedUnique2(values) {
13049
13961
  return [...new Set(values)].sort((left, right) => binaryCompare(left, right));
@@ -13230,8 +14142,8 @@ var D1EventStore = class {
13230
14142
  let failure3;
13231
14143
  try {
13232
14144
  result2 = await this.recordDeliveryCore(message, arrivedAt, deliverySource, mutationAttemptId);
13233
- } catch (error10) {
13234
- failure3 = { error: error10 };
14145
+ } catch (error11) {
14146
+ failure3 = { error: error11 };
13235
14147
  }
13236
14148
  const retryReason = failure3 === void 0 ? null : errorText3(failure3.error);
13237
14149
  const suppressDiagnostic = failure3?.error instanceof D1IdentityConflictError && failure3.error.beforeMutation;
@@ -13802,8 +14714,8 @@ var D1EventStore = class {
13802
14714
  if (replay === null || replay === void 0) return finish({ kind: "miss" });
13803
14715
  const event = await this.eventById(serviceId, asString3(replay.event_id, "replay.event_id"));
13804
14716
  return event === void 0 ? finish({ kind: "unknown", reason: "replay-event-row-disappeared" }) : finish({ kind: "replay", event });
13805
- } catch (error10) {
13806
- return finish({ kind: "unknown", reason: errorText3(error10) });
14717
+ } catch (error11) {
14718
+ return finish({ kind: "unknown", reason: errorText3(error11) });
13807
14719
  }
13808
14720
  }
13809
14721
  /**
@@ -14278,8 +15190,8 @@ var D1EventStore = class {
14278
15190
  try {
14279
15191
  try {
14280
15192
  await this.options.beforeG69AdmissionAttempt?.();
14281
- } catch (error10) {
14282
- await appendFailedDiagnostic(errorText3(error10));
15193
+ } catch (error11) {
15194
+ await appendFailedDiagnostic(errorText3(error11));
14283
15195
  return;
14284
15196
  }
14285
15197
  const afterObservedAt = Date.now();
@@ -14353,14 +15265,14 @@ var TagIdentityConflict = class extends Error {
14353
15265
  this.name = "TagIdentityConflict";
14354
15266
  }
14355
15267
  };
14356
- function json10(body, status = 200) {
15268
+ function json11(body, status = 200) {
14357
15269
  return new Response(JSON.stringify(body), {
14358
15270
  status,
14359
15271
  headers: { "content-type": "application/json; charset=utf-8" }
14360
15272
  });
14361
15273
  }
14362
- function error8(status, code, message, retryable = false) {
14363
- return json10(retryable ? { error: message, code, retryable: true } : { error: message, code }, status);
15274
+ function error9(status, code, message, retryable = false) {
15275
+ return json11(retryable ? { error: message, code, retryable: true } : { error: message, code }, status);
14364
15276
  }
14365
15277
  function withGlobalAdmission2(response3, status) {
14366
15278
  response3.headers.set(G65_GLOBAL_ADMISSION_HEADER, status);
@@ -14379,7 +15291,7 @@ function repairRejected(reason, status = 409) {
14379
15291
  body: { code: "repair_operation_rejected", error: reason, reason }
14380
15292
  };
14381
15293
  }
14382
- function isObject11(value) {
15294
+ function isObject12(value) {
14383
15295
  return typeof value === "object" && value !== null && !Array.isArray(value);
14384
15296
  }
14385
15297
  function isNonEmptyString11(value) {
@@ -14424,8 +15336,8 @@ function sqlJson(value, column) {
14424
15336
  throw new Error(`Tag SQL column ${column} is not valid JSON`);
14425
15337
  }
14426
15338
  }
14427
- function copyArrayBuffer(bytes) {
14428
- return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
15339
+ function copyArrayBuffer(bytes2) {
15340
+ return bytes2.buffer.slice(bytes2.byteOffset, bytes2.byteOffset + bytes2.byteLength);
14429
15341
  }
14430
15342
  function arrayBufferBase642(value) {
14431
15343
  let binary = "";
@@ -14436,7 +15348,7 @@ function nowIso() {
14436
15348
  return (/* @__PURE__ */ new Date()).toISOString();
14437
15349
  }
14438
15350
  function epochFrom(value) {
14439
- if (!isObject11(value) || !isNonEmptyString11(value.attemptId) || !isEpoch(value.epoch)) {
15351
+ if (!isObject12(value) || !isNonEmptyString11(value.attemptId) || !isEpoch(value.epoch)) {
14440
15352
  return { error: "attemptId and a non-negative safe-integer epoch are required" };
14441
15353
  }
14442
15354
  return { value: { attemptId: value.attemptId, epoch: value.epoch } };
@@ -14456,7 +15368,7 @@ function consistencyTagsFrom(value) {
14456
15368
  }
14457
15369
  const entries = [];
14458
15370
  for (const rawEntry of value) {
14459
- if (!isObject11(rawEntry) || !isNonEmptyString11(rawEntry.tag)) {
15371
+ if (!isObject12(rawEntry) || !isNonEmptyString11(rawEntry.tag)) {
14460
15372
  return { error: "each consistency tag needs a non-empty tag" };
14461
15373
  }
14462
15374
  if (!("lastSortableUniqueId" in rawEntry)) {
@@ -14484,7 +15396,7 @@ function consistencyTagsFrom(value) {
14484
15396
  }
14485
15397
  function acquireFrom(value, tag) {
14486
15398
  const epoch2 = epochFrom(value);
14487
- if (epoch2.value === void 0 || !isObject11(value)) {
15399
+ if (epoch2.value === void 0 || !isObject12(value)) {
14488
15400
  return { error: epoch2.error ?? "Invalid acquire request" };
14489
15401
  }
14490
15402
  const eventTags = stringArrayFrom(value.eventTags, "eventTags");
@@ -14507,7 +15419,7 @@ function acquireFrom(value, tag) {
14507
15419
  }
14508
15420
  function reservationFrom(value) {
14509
15421
  const epoch2 = epochFrom(value);
14510
- if (epoch2.value === void 0 || !isObject11(value)) {
15422
+ if (epoch2.value === void 0 || !isObject12(value)) {
14511
15423
  return { error: epoch2.error ?? "Invalid reservation request" };
14512
15424
  }
14513
15425
  if (value.reservationToken !== void 0 && !isNonEmptyString11(value.reservationToken)) {
@@ -14526,7 +15438,7 @@ function reservationFrom(value) {
14526
15438
  }
14527
15439
  function appendFrom(value, tag) {
14528
15440
  const reservation = reservationFrom(value);
14529
- if (reservation.value === void 0 || !isObject11(value) || !Array.isArray(value.candidates)) {
15441
+ if (reservation.value === void 0 || !isObject12(value) || !Array.isArray(value.candidates)) {
14530
15442
  return { error: reservation.error ?? "candidates must be an array" };
14531
15443
  }
14532
15444
  if (value.candidates.length === 0) {
@@ -14534,7 +15446,7 @@ function appendFrom(value, tag) {
14534
15446
  }
14535
15447
  const candidates = [];
14536
15448
  for (const rawCandidate of value.candidates) {
14537
- if (!isObject11(rawCandidate) || !isNonEmptyString11(rawCandidate.eventId) || !isNonEmptyString11(rawCandidate.suid) || typeof rawCandidate.payload !== "string") {
15449
+ if (!isObject12(rawCandidate) || !isNonEmptyString11(rawCandidate.eventId) || !isNonEmptyString11(rawCandidate.suid) || typeof rawCandidate.payload !== "string") {
14538
15450
  return { error: "each candidate needs eventId, suid, and payload" };
14539
15451
  }
14540
15452
  const eventTags = stringArrayFrom(rawCandidate.eventTags, "candidate eventTags");
@@ -14548,8 +15460,8 @@ function appendFrom(value, tag) {
14548
15460
  assertSortableUniqueId(rawCandidate.suid);
14549
15461
  if (!isUuidV7(rawCandidate.eventId)) return { error: "candidate eventId must be a UUID v7" };
14550
15462
  JSON.parse(rawCandidate.payload);
14551
- } catch (error10) {
14552
- return { error: error10 instanceof Error ? error10.message : "candidate identity or payload is invalid" };
15463
+ } catch (error11) {
15464
+ return { error: error11 instanceof Error ? error11.message : "candidate identity or payload is invalid" };
14553
15465
  }
14554
15466
  if (rawCandidate.provenance !== "g32") return { error: "candidate provenance must be g32" };
14555
15467
  if (!isNonEmptyString11(rawCandidate.allocatorLineageId)) return { error: "candidate allocatorLineageId is required" };
@@ -14583,10 +15495,10 @@ function appendFrom(value, tag) {
14583
15495
  return { value: { ...reservation.value, candidates: ordered, faultInjection } };
14584
15496
  }
14585
15497
  function bootstrapAppendFrom(value, tag) {
14586
- if (!isObject11(value) || !isNonEmptyString11(value.importId) || !isEpoch(value.leaseEpoch) || !isNonEmptyString11(value.manifestDigest) || !isNonEmptyString11(value.targetServiceId) || !Array.isArray(value.candidates) || value.candidates.length === 0) return { error: "bootstrap identity and candidates are required" };
15498
+ if (!isObject12(value) || !isNonEmptyString11(value.importId) || !isEpoch(value.leaseEpoch) || !isNonEmptyString11(value.manifestDigest) || !isNonEmptyString11(value.targetServiceId) || !Array.isArray(value.candidates) || value.candidates.length === 0) return { error: "bootstrap identity and candidates are required" };
14587
15499
  const candidates = [];
14588
15500
  for (const candidate of value.candidates) {
14589
- if (!isObject11(candidate) || !isNonEmptyString11(candidate.eventId) || !isNonEmptyString11(candidate.suid) || typeof candidate.payload !== "string") return { error: "bootstrap candidate is invalid" };
15501
+ if (!isObject12(candidate) || !isNonEmptyString11(candidate.eventId) || !isNonEmptyString11(candidate.suid) || typeof candidate.payload !== "string") return { error: "bootstrap candidate is invalid" };
14590
15502
  const tags = stringArrayFrom(candidate.eventTags, "bootstrap candidate eventTags");
14591
15503
  if (tags.value === void 0 || !tags.value.includes(tag) || !isNonEmptyString11(candidate.allocatorLineageId)) return { error: "bootstrap candidate must include this tag and lineage" };
14592
15504
  let eventType;
@@ -14596,8 +15508,8 @@ function bootstrapAppendFrom(value, tag) {
14596
15508
  assertSortableUniqueId(candidate.suid);
14597
15509
  if (!isRfc4122Uuid(candidate.eventId)) return { error: "bootstrap candidate eventId must be an RFC 4122 UUID" };
14598
15510
  JSON.parse(candidate.payload);
14599
- } catch (error10) {
14600
- return { error: error10 instanceof Error ? error10.message : "bootstrap candidate identity or payload is invalid" };
15511
+ } catch (error11) {
15512
+ return { error: error11 instanceof Error ? error11.message : "bootstrap candidate identity or payload is invalid" };
14601
15513
  }
14602
15514
  if (candidate.provenance !== "g32") return { error: "bootstrap candidate provenance must be g32" };
14603
15515
  if (!isNonEmptyString11(candidate.timestamp) || !CANONICAL_UTC_TIMESTAMP_PATTERN.test(candidate.timestamp)) return { error: "bootstrap candidate timestamp must be canonical UTC" };
@@ -14609,13 +15521,13 @@ function bootstrapAppendFrom(value, tag) {
14609
15521
  }
14610
15522
  function fenceFrom(value) {
14611
15523
  const epoch2 = epochFrom(value);
14612
- if (epoch2.value === void 0 || !isObject11(value) || !isNonEmptyString11(value.reason)) {
15524
+ if (epoch2.value === void 0 || !isObject12(value) || !isNonEmptyString11(value.reason)) {
14613
15525
  return { error: epoch2.error ?? "reason is required" };
14614
15526
  }
14615
15527
  return { value: { ...epoch2.value, reason: value.reason } };
14616
15528
  }
14617
15529
  function repairScopeItemFrom(value, tag) {
14618
- if (!isObject11(value) || !isNonEmptyString11(value.attemptId) || !isNonEmptyString11(value.eventId) || !isNonEmptyString11(value.suid) || typeof value.payload !== "string" || !isNonEmptyString11(value.allocatorLineageId) || !isNonEmptyString11(value.eventType) || value.provenance !== "g32" || !isNonEmptyString11(value.timestamp)) {
15530
+ if (!isObject12(value) || !isNonEmptyString11(value.attemptId) || !isNonEmptyString11(value.eventId) || !isNonEmptyString11(value.suid) || typeof value.payload !== "string" || !isNonEmptyString11(value.allocatorLineageId) || !isNonEmptyString11(value.eventType) || value.provenance !== "g32" || !isNonEmptyString11(value.timestamp)) {
14619
15531
  return { error: "each repair scope item needs attemptId, eventId, suid, and payload" };
14620
15532
  }
14621
15533
  const eventTags = stringArrayFrom(value.eventTags, "repair eventTags");
@@ -14663,13 +15575,13 @@ function repairScopeFrom(value, tag) {
14663
15575
  return { value: sortRepairScope(scope) };
14664
15576
  }
14665
15577
  function repairLeaseFrom(value) {
14666
- if (!isObject11(value) || !isNonEmptyString11(value.owner) || !isEpoch(value.epoch)) {
15578
+ if (!isObject12(value) || !isNonEmptyString11(value.owner) || !isEpoch(value.epoch)) {
14667
15579
  return { error: "repair owner and non-negative safe-integer epoch are required" };
14668
15580
  }
14669
15581
  return { value: { owner: value.owner, epoch: value.epoch } };
14670
15582
  }
14671
15583
  function repairAcquireFrom(value, tag) {
14672
- if (!isObject11(value) || !isNonEmptyString11(value.owner)) {
15584
+ if (!isObject12(value) || !isNonEmptyString11(value.owner)) {
14673
15585
  return { error: "repair owner is required" };
14674
15586
  }
14675
15587
  const leaseMs = value.leaseMs ?? DEFAULT_REPAIR_LEASE_MS;
@@ -14681,7 +15593,7 @@ function repairAcquireFrom(value, tag) {
14681
15593
  }
14682
15594
  function repairScopeUnionFrom(value, tag) {
14683
15595
  const lease = repairLeaseFrom(value);
14684
- if (lease.value === void 0 || !isObject11(value)) {
15596
+ if (lease.value === void 0 || !isObject12(value)) {
14685
15597
  return { error: lease.error };
14686
15598
  }
14687
15599
  const scope = repairScopeFrom(value.scope, tag);
@@ -14689,7 +15601,7 @@ function repairScopeUnionFrom(value, tag) {
14689
15601
  }
14690
15602
  function repairApplyFrom(value, tag) {
14691
15603
  const lease = repairLeaseFrom(value);
14692
- if (lease.value === void 0 || !isObject11(value)) {
15604
+ if (lease.value === void 0 || !isObject12(value)) {
14693
15605
  return { error: lease.error };
14694
15606
  }
14695
15607
  const item = repairScopeItemFrom(value.item, tag);
@@ -14697,20 +15609,20 @@ function repairApplyFrom(value, tag) {
14697
15609
  }
14698
15610
  function repairAuditFrom(value, tag) {
14699
15611
  const apply = repairApplyFrom(value, tag);
14700
- if (apply.value === void 0 || !isObject11(value) || !isNonEmptyString11(value.actor)) {
15612
+ if (apply.value === void 0 || !isObject12(value) || !isNonEmptyString11(value.actor)) {
14701
15613
  return { error: apply.error ?? "audit actor is required" };
14702
15614
  }
14703
15615
  return { value: { ...apply.value, actor: value.actor } };
14704
15616
  }
14705
15617
  function repairClearFrom(value) {
14706
15618
  const lease = repairLeaseFrom(value);
14707
- if (lease.value === void 0 || !isObject11(value) || !isNonEmptyString11(value.attemptId) || !isNonNegativeInteger4(value.scopeVersion)) {
15619
+ if (lease.value === void 0 || !isObject12(value) || !isNonEmptyString11(value.attemptId) || !isNonNegativeInteger4(value.scopeVersion)) {
14708
15620
  return { error: lease.error ?? "attemptId and scopeVersion are required" };
14709
15621
  }
14710
15622
  return { value: { ...lease.value, attemptId: value.attemptId, scopeVersion: value.scopeVersion } };
14711
15623
  }
14712
15624
  function outboxPendingFrom(value) {
14713
- if (!isObject11(value)) {
15625
+ if (!isObject12(value)) {
14714
15626
  return { error: "outbox pending request must be an object" };
14715
15627
  }
14716
15628
  const nowMs = value.nowMs ?? Date.now();
@@ -14728,22 +15640,22 @@ function outboxPendingFrom(value) {
14728
15640
  return { value: { nowMs, limit, force } };
14729
15641
  }
14730
15642
  function outboxMarkFrom(value) {
14731
- if (!isObject11(value) || !Array.isArray(value.deliveries) || value.deliveries.length === 0) {
15643
+ if (!isObject12(value) || !Array.isArray(value.deliveries) || value.deliveries.length === 0) {
14732
15644
  return { error: "deliveries must be a non-empty array" };
14733
15645
  }
14734
15646
  const deliveries = [];
14735
15647
  for (const raw of value.deliveries) {
14736
- if (!isObject11(raw) || !isNonEmptyString11(raw.attemptId) || !isNonEmptyString11(raw.eventId) || !isNonEmptyString11(raw.suid) || typeof raw.payload !== "string" || !isSafeInteger(raw.enqueuedAt)) {
15648
+ if (!isObject12(raw) || !isNonEmptyString11(raw.attemptId) || !isNonEmptyString11(raw.eventId) || !isNonEmptyString11(raw.suid) || typeof raw.payload !== "string" || !isSafeInteger(raw.enqueuedAt)) {
14737
15649
  return { error: "each delivery needs attemptId, eventId, suid, payload, and enqueuedAt" };
14738
15650
  }
14739
15651
  if (!isNonEmptyString11(raw.eventType) || raw.provenance !== "g32" || !isNonEmptyString11(raw.timestamp) || !isNonEmptyString11(raw.allocatorLineageId)) return { error: "delivery must carry the complete G32 identity" };
14740
- if (!isObject11(raw.completeness)) {
15652
+ if (!isObject12(raw.completeness)) {
14741
15653
  return { error: "delivery must carry a readable global receipt/membership join proof" };
14742
15654
  }
14743
15655
  const completeness = raw.completeness;
14744
15656
  const obligationSequence = completeness.obligationSequence;
14745
15657
  const memberships = completeness.localCommittedMembership;
14746
- if (!isNonEmptyString11(completeness.eventDigest) || !isSafeInteger(obligationSequence) || obligationSequence < 1 || !Array.isArray(memberships) || memberships.length !== 1 || !isObject11(memberships[0]) || memberships[0].eventId !== raw.eventId || typeof memberships[0].tag !== "string") {
15658
+ if (!isNonEmptyString11(completeness.eventDigest) || !isSafeInteger(obligationSequence) || obligationSequence < 1 || !Array.isArray(memberships) || memberships.length !== 1 || !isObject12(memberships[0]) || memberships[0].eventId !== raw.eventId || typeof memberships[0].tag !== "string") {
14747
15659
  return { error: "delivery must carry a readable global receipt/membership join proof" };
14748
15660
  }
14749
15661
  const membership = memberships[0];
@@ -14782,7 +15694,7 @@ function outboxMarkFrom(value) {
14782
15694
  return { value: { deliveries, nowMs } };
14783
15695
  }
14784
15696
  function g44SourceScanFrom(value) {
14785
- if (!isObject11(value) || !isNonEmptyString11(value.serviceId) || !isNonEmptyString11(value.tag) || !isSafeInteger(value.upperBoundSequence) || value.upperBoundSequence < 0 || !isSafeInteger(value.afterSequence) || value.afterSequence < 0 || !isSafeInteger(value.limit) || value.limit < 1 || value.limit > 256) {
15697
+ if (!isObject12(value) || !isNonEmptyString11(value.serviceId) || !isNonEmptyString11(value.tag) || !isSafeInteger(value.upperBoundSequence) || value.upperBoundSequence < 0 || !isSafeInteger(value.afterSequence) || value.afterSequence < 0 || !isSafeInteger(value.limit) || value.limit < 1 || value.limit > 256) {
14786
15698
  return { error: "source scan needs serviceId, tag, and a bounded compound cursor" };
14787
15699
  }
14788
15700
  return {
@@ -14796,7 +15708,7 @@ function g44SourceScanFrom(value) {
14796
15708
  };
14797
15709
  }
14798
15710
  function g46TagStateSourceFrom(value) {
14799
- if (!isObject11(value) || !isNonEmptyString11(value.tag) || typeof value.cursor !== "string" || !isSafeInteger(value.limit) || value.limit < 1 || value.limit > 256 || value.through !== void 0 && typeof value.through !== "string") {
15711
+ if (!isObject12(value) || !isNonEmptyString11(value.tag) || typeof value.cursor !== "string" || !isSafeInteger(value.limit) || value.limit < 1 || value.limit > 256 || value.through !== void 0 && typeof value.through !== "string") {
14800
15712
  return { error: "G46 source read needs tag, cursor, optional through, and a bounded limit" };
14801
15713
  }
14802
15714
  try {
@@ -14970,8 +15882,8 @@ function logicalNow(record) {
14970
15882
  return record.clockNowMs ?? Date.now() + record.clockOffsetMs;
14971
15883
  }
14972
15884
  function expireReservation(record) {
14973
- const active = record.activeReservation;
14974
- if (active === null || active.expiresAt > logicalNow(record)) {
15885
+ const active2 = record.activeReservation;
15886
+ if (active2 === null || active2.expiresAt > logicalNow(record)) {
14975
15887
  return { record, expired: false };
14976
15888
  }
14977
15889
  return {
@@ -15089,7 +16001,7 @@ var TagDurableObject = class {
15089
16001
  const url = new URL(request.url);
15090
16002
  const tag = url.searchParams.get("__tag");
15091
16003
  if (!isNonEmptyString11(tag)) {
15092
- return error8(400, "tag_identity_required", "Tag identity is required");
16004
+ return error9(400, "tag_identity_required", "Tag identity is required");
15093
16005
  }
15094
16006
  const serviceId = url.searchParams.get("__serviceId");
15095
16007
  if (request.method === "GET" && url.pathname === "/head-facts") {
@@ -15097,10 +16009,10 @@ var TagDurableObject = class {
15097
16009
  observation.markFirstStorageRead();
15098
16010
  try {
15099
16011
  const facts = this.readHeadFacts(tag);
15100
- return facts === void 0 ? error8(404, "tag_not_found", "Tag has no durable state yet") : json10(facts);
16012
+ return facts === void 0 ? error9(404, "tag_not_found", "Tag has no durable state yet") : json11(facts);
15101
16013
  } catch (caught) {
15102
16014
  if (caught instanceof TagIdentityConflict) {
15103
- return error8(409, "tag_identity_conflict", "Tag Durable Object identity changed");
16015
+ return error9(409, "tag_identity_conflict", "Tag Durable Object identity changed");
15104
16016
  }
15105
16017
  throw caught;
15106
16018
  }
@@ -15111,9 +16023,9 @@ var TagDurableObject = class {
15111
16023
  observation.markFirstStorageRead();
15112
16024
  const record = this.readStoredRecord(tag);
15113
16025
  if (record === void 0) {
15114
- return error8(404, "tag_not_found", "Tag has no durable state yet");
16026
+ return error9(404, "tag_not_found", "Tag has no durable state yet");
15115
16027
  }
15116
- return record.tag === tag ? json10(requireG32TagRecord(record)) : error8(409, "tag_identity_conflict", "Tag Durable Object identity changed");
16028
+ return record.tag === tag ? json11(requireG32TagRecord(record)) : error9(409, "tag_identity_conflict", "Tag Durable Object identity changed");
15117
16029
  });
15118
16030
  }
15119
16031
  if (request.method === "GET" && url.pathname === "/repair/facts") {
@@ -15121,7 +16033,7 @@ var TagDurableObject = class {
15121
16033
  }
15122
16034
  if (request.method === "POST" && url.pathname === "/debug/alarm") {
15123
16035
  const record = await this.runAlarm();
15124
- return record === void 0 ? error8(404, "tag_not_found", "Tag has no durable state yet") : json10(record);
16036
+ return record === void 0 ? error9(404, "tag_not_found", "Tag has no durable state yet") : json11(record);
15125
16037
  }
15126
16038
  if (request.method === "POST" && url.pathname === "/acquire") {
15127
16039
  return this.traceCommitActor(request, tag, serviceId, activation, observation, (body2) => this.acquire(tag, body2, observation));
@@ -15144,37 +16056,37 @@ var TagDurableObject = class {
15144
16056
  }
15145
16057
  const body = await this.jsonBody(request);
15146
16058
  if (body === void 0) {
15147
- return error8(400, "malformed_tag_request", "Request body must be JSON");
16059
+ return error9(400, "malformed_tag_request", "Request body must be JSON");
15148
16060
  }
15149
16061
  if (request.method === "POST" && url.pathname === "/__internal/g46/tag-state-incremental") {
15150
16062
  if (request.headers.get("x-sdt-g46-source-read") !== "1") {
15151
- return error8(403, "g46_source_read_forbidden", "G46 source reads require the TagState adapter");
16063
+ return error9(403, "g46_source_read_forbidden", "G46 source reads require the TagState adapter");
15152
16064
  }
15153
16065
  const parsed = g46TagStateSourceFrom(body);
15154
16066
  if (parsed.value === void 0 || parsed.value.tag !== tag) {
15155
- return error8(400, "g46_source_read_invalid", parsed.error ?? "G46 source read is invalid");
16067
+ return error9(400, "g46_source_read_invalid", parsed.error ?? "G46 source read is invalid");
15156
16068
  }
15157
16069
  try {
15158
- return json10(await this.g43TagStateIncrementalCatchUp(parsed.value));
16070
+ return json11(await this.g43TagStateIncrementalCatchUp(parsed.value));
15159
16071
  } catch (caught) {
15160
16072
  if (caught instanceof TagIdentityConflict) {
15161
- return error8(409, "tag_identity_conflict", "Tag Durable Object identity changed");
16073
+ return error9(409, "tag_identity_conflict", "Tag Durable Object identity changed");
15162
16074
  }
15163
- return error8(503, "g46_source_read_unavailable", caught instanceof Error ? caught.message : "G46 source read is unavailable");
16075
+ return error9(503, "g46_source_read_unavailable", caught instanceof Error ? caught.message : "G46 source read is unavailable");
15164
16076
  }
15165
16077
  }
15166
16078
  if (request.method === "POST" && url.pathname === "/__internal/g44/source-obligations") {
15167
16079
  if (request.headers.get("x-sdt-g44-source-scan") !== "1") {
15168
- return error8(403, "g44_source_scan_forbidden", "G44 source scan requires the internal scanner seam");
16080
+ return error9(403, "g44_source_scan_forbidden", "G44 source scan requires the internal scanner seam");
15169
16081
  }
15170
16082
  const parsed = g44SourceScanFrom(body);
15171
16083
  if (parsed.value === void 0 || parsed.value.tag !== tag || parsed.value.serviceId !== serviceId) {
15172
- return error8(400, "g44_source_scan_invalid", parsed.error ?? "G44 source scan identity is invalid");
16084
+ return error9(400, "g44_source_scan_invalid", parsed.error ?? "G44 source scan identity is invalid");
15173
16085
  }
15174
16086
  try {
15175
- return json10(await this.g44ReadSourceObligations(parsed.value));
16087
+ return json11(await this.g44ReadSourceObligations(parsed.value));
15176
16088
  } catch (failure3) {
15177
- return error8(503, "g44_source_scan_unavailable", failure3 instanceof Error ? failure3.message : "G44 source scan is unavailable");
16089
+ return error9(503, "g44_source_scan_unavailable", failure3 instanceof Error ? failure3.message : "G44 source scan is unavailable");
15178
16090
  }
15179
16091
  }
15180
16092
  if (request.method === "POST" && url.pathname === "/bootstrap/admit") {
@@ -15221,7 +16133,7 @@ var TagDurableObject = class {
15221
16133
  }
15222
16134
  if (request.method === "POST" && url.pathname === "/__internal/g77/inspect-target") {
15223
16135
  if (!isNonEmptyString11(serviceId)) {
15224
- return error8(400, "service_identity_required", "Service identity is required");
16136
+ return error9(400, "service_identity_required", "Service identity is required");
15225
16137
  }
15226
16138
  return this.inspectG77Target(serviceId, tag, body);
15227
16139
  }
@@ -15229,28 +16141,28 @@ var TagDurableObject = class {
15229
16141
  return this.fenceAbsentG77Target(tag, body);
15230
16142
  }
15231
16143
  if (request.method === "POST" && url.pathname === "/__internal/g77/capabilities") {
15232
- return json10({ inspectTarget: true, fenceAbsentTarget: true });
16144
+ return json11({ inspectTarget: true, fenceAbsentTarget: true });
15233
16145
  }
15234
- return error8(404, "tag_route_not_found", "Tag route was not found");
16146
+ return error9(404, "tag_route_not_found", "Tag route was not found");
15235
16147
  }
15236
16148
  /** Identity-bound installed/absent inspection for G77 issuance reconciliation. */
15237
16149
  inspectG77Target(serviceId, tag, body) {
15238
- if (!isObject11(body) || !isNonEmptyString11(body.eventId) || !isNonEmptyString11(body.suid)) {
15239
- return error8(400, "invalid_inspect_target", "eventId and suid are required");
16150
+ if (!isObject12(body) || !isNonEmptyString11(body.eventId) || !isNonEmptyString11(body.suid)) {
16151
+ return error9(400, "invalid_inspect_target", "eventId and suid are required");
15240
16152
  }
15241
16153
  const pinnedWriterEpoch = isNonNegativeInteger4(body.pinnedWriterEpoch) ? body.pinnedWriterEpoch : 0;
15242
16154
  const attemptId = isNonEmptyString11(body.attemptId) ? body.attemptId : void 0;
15243
16155
  const sql = this.sqlStorage();
15244
- if (sql === void 0) return error8(503, "tag_sql_unavailable", "Tag SQL storage is unavailable");
16156
+ if (sql === void 0) return error9(503, "tag_sql_unavailable", "Tag SQL storage is unavailable");
15245
16157
  const identity2 = sql.exec("SELECT tag FROM tag_identity WHERE singleton = 1").toArray()[0];
15246
16158
  if (identity2 === void 0) {
15247
16159
  if (attemptId !== void 0) {
15248
- return json10({ inspectionStatus: "absent-never-contacted" });
16160
+ return json11({ inspectionStatus: "absent-never-contacted" });
15249
16161
  }
15250
- return error8(409, "target_not_terminal", "Target is not terminal under pinned writer authority");
16162
+ return error9(409, "target_not_terminal", "Target is not terminal under pinned writer authority");
15251
16163
  }
15252
16164
  if (sqlString(identity2.tag, "tag_identity.tag") !== tag) {
15253
- return error8(409, "tag_identity_mismatch", "Tag identity does not match the inspected tag");
16165
+ return error9(409, "tag_identity_mismatch", "Tag identity does not match the inspected tag");
15254
16166
  }
15255
16167
  const event = sql.exec(`
15256
16168
  SELECT attempt_id, event_id, suid FROM tag_event
@@ -15263,41 +16175,41 @@ var TagDurableObject = class {
15263
16175
  `, serviceId, body.eventId).toArray()[0];
15264
16176
  if (obligation !== void 0) {
15265
16177
  const obligationDigest = sqlString(obligation.event_digest, "tag_outbox_obligation.event_digest");
15266
- return json10({
16178
+ return json11({
15267
16179
  terminalStatus: "installed-and-covered",
15268
16180
  eventId: body.eventId,
15269
16181
  obligationDigest
15270
16182
  });
15271
16183
  }
15272
- return error8(409, "target_not_terminal", "Target append is in flight under pinned writer authority");
16184
+ return error9(409, "target_not_terminal", "Target append is in flight under pinned writer authority");
15273
16185
  }
15274
16186
  if (attemptId !== void 0) {
15275
16187
  const tombstone = sql.exec("SELECT epoch FROM tag_tombstone WHERE attempt_id = ?", attemptId).toArray()[0];
15276
16188
  const tombstoneEpoch = tombstone === void 0 ? void 0 : sqlNumber(tombstone.epoch, "tag_tombstone.epoch");
15277
16189
  if (tombstoneEpoch !== void 0 && pinnedWriterEpoch <= tombstoneEpoch) {
15278
- return json10({ terminalStatus: "absent-and-irrevocably-fenced", tombstoneEpoch });
16190
+ return json11({ terminalStatus: "absent-and-irrevocably-fenced", tombstoneEpoch });
15279
16191
  }
15280
16192
  const reservation = sql.exec("SELECT attempt_id, expires_at FROM tag_reservation WHERE singleton = 1").toArray()[0];
15281
16193
  if (reservation !== void 0 && sqlString(reservation.attempt_id, "tag_reservation.attempt_id") === attemptId) {
15282
- return error8(409, "target_not_terminal", "Active reservation holds writer authority");
16194
+ return error9(409, "target_not_terminal", "Active reservation holds writer authority");
15283
16195
  }
15284
16196
  const epoch2 = sql.exec("SELECT attempt_id FROM tag_epoch WHERE attempt_id = ?", attemptId).toArray()[0];
15285
16197
  if (epoch2 !== void 0) {
15286
- return json10({ inspectionStatus: "absent-but-unfenced" });
16198
+ return json11({ inspectionStatus: "absent-but-unfenced" });
15287
16199
  }
15288
- return json10({ inspectionStatus: "absent-never-contacted" });
16200
+ return json11({ inspectionStatus: "absent-never-contacted" });
15289
16201
  }
15290
- return error8(409, "target_not_terminal", "Target is not terminal under pinned writer authority");
16202
+ return error9(409, "target_not_terminal", "Target is not terminal under pinned writer authority");
15291
16203
  }
15292
16204
  /** Reconciler-only fence for never-contacted targets; creates durable tombstone state. */
15293
16205
  async fenceAbsentG77Target(tag, body) {
15294
16206
  const parsed = reservationFrom(body);
15295
16207
  if (parsed.value === void 0) {
15296
- return error8(400, "invalid_fence_target", parsed.error ?? "attemptId and epoch are required");
16208
+ return error9(400, "invalid_fence_target", parsed.error ?? "attemptId and epoch are required");
15297
16209
  }
15298
16210
  this.ensureSqlTag(tag);
15299
16211
  const result2 = await this.cancelSql(tag, { ...parsed.value, forceTombstone: true });
15300
- return result2.status >= 200 && result2.status < 300 ? json10(result2.body) : error8(result2.status, "fence_target_rejected", "Absent target fence was rejected");
16212
+ return result2.status >= 200 && result2.status < 300 ? json11(result2.body) : error9(result2.status, "fence_target_rejected", "Absent target fence was rejected");
15301
16213
  }
15302
16214
  async alarm() {
15303
16215
  this.activation.beginHandler();
@@ -15644,21 +16556,21 @@ var TagDurableObject = class {
15644
16556
  const result2 = await authority;
15645
16557
  g44GlobalArrayAuthorityResultByD1.set(database, result2);
15646
16558
  return result2;
15647
- } catch (error10) {
16559
+ } catch (error11) {
15648
16560
  if (g44GlobalArrayAuthorityByD1.get(database) === authority) {
15649
16561
  g44GlobalArrayAuthorityByD1.delete(database);
15650
16562
  }
15651
- throw error10;
16563
+ throw error11;
15652
16564
  }
15653
16565
  }
15654
16566
  async readG44GlobalArrayAuthority(database) {
15655
16567
  try {
15656
16568
  await database.prepare('SELECT "EventDigest" FROM dcb_events WHERE 1 = 0').all();
15657
16569
  return true;
15658
- } catch (error10) {
15659
- const message = error10 instanceof Error ? error10.message : String(error10);
16570
+ } catch (error11) {
16571
+ const message = error11 instanceof Error ? error11.message : String(error11);
15660
16572
  if (/no such (?:table|column):\s*(?:dcb_events|EventDigest)/i.test(message)) return false;
15661
- throw error10;
16573
+ throw error11;
15662
16574
  }
15663
16575
  }
15664
16576
  async traceCommitActor(request, tag, serviceId, activation, observation, callback) {
@@ -15668,10 +16580,10 @@ var TagDurableObject = class {
15668
16580
  { actorClass: "TAG", actorKey: `tag:${serviceId}:${tag}`, activation, observation },
15669
16581
  async () => {
15670
16582
  body = await this.jsonBody(request);
15671
- const attemptId = isObject11(body) && isNonEmptyString11(body.attemptId) ? body.attemptId : void 0;
16583
+ const attemptId = isObject12(body) && isNonEmptyString11(body.attemptId) ? body.attemptId : void 0;
15672
16584
  return attemptId === void 0 || !isNonEmptyString11(serviceId) ? void 0 : { attemptId, serviceId };
15673
16585
  },
15674
- async () => body === void 0 ? error8(400, "malformed_tag_request", "Request body must be JSON") : callback(body)
16586
+ async () => body === void 0 ? error9(400, "malformed_tag_request", "Request body must be JSON") : callback(body)
15675
16587
  );
15676
16588
  }
15677
16589
  /**
@@ -15885,6 +16797,7 @@ var TagDurableObject = class {
15885
16797
  ensureSqlTag(tag) {
15886
16798
  const sql = this.sqlStorage();
15887
16799
  if (sql === void 0) throw new Error("Tag SQL storage is unavailable");
16800
+ ensureTagCommitReceiptWrittenVersion(sql);
15888
16801
  const existing = sql.exec("SELECT tag FROM tag_identity WHERE singleton = 1").toArray()[0];
15889
16802
  if (existing !== void 0) {
15890
16803
  if (sqlString(existing.tag, "tag_identity.tag") !== tag) throw new Error("Tag Durable Object identity changed");
@@ -15997,17 +16910,18 @@ var TagDurableObject = class {
15997
16910
  sql.exec("UPDATE tag_control SET head_suid = ?, version = ?, updated_at = ? WHERE singleton = 1", head, version, committedAt);
15998
16911
  sql.exec("UPDATE tag_head SET service_id = ?, head_suid = ? WHERE singleton = 1", serviceId, head);
15999
16912
  }
16000
- writeCommittedSqlReceipt(sql, input, committedAt, eventCount, head, confirmsReservation) {
16913
+ writeCommittedSqlReceipt(sql, input, committedAt, eventCount, head, confirmsReservation, writtenVersion) {
16001
16914
  sql.exec(`
16002
16915
  INSERT INTO tag_commit_receipt
16003
- (attempt_id, epoch, committed_at, committed_event_count, head_suid, reservation_confirmed)
16004
- VALUES (?, ?, ?, ?, ?, ?)
16916
+ (attempt_id, epoch, committed_at, committed_event_count, head_suid, reservation_confirmed, written_version)
16917
+ VALUES (?, ?, ?, ?, ?, ?, ?)
16005
16918
  ON CONFLICT(attempt_id, epoch) DO UPDATE SET
16006
16919
  committed_at = excluded.committed_at,
16007
16920
  committed_event_count = excluded.committed_event_count,
16008
16921
  head_suid = excluded.head_suid,
16009
- reservation_confirmed = excluded.reservation_confirmed
16010
- `, input.attemptId, input.epoch, committedAt, eventCount, head, confirmsReservation ? 1 : 0);
16922
+ reservation_confirmed = excluded.reservation_confirmed,
16923
+ written_version = excluded.written_version
16924
+ `, input.attemptId, input.epoch, committedAt, eventCount, head, confirmsReservation ? 1 : 0, writtenVersion);
16011
16925
  }
16012
16926
  /**
16013
16927
  * The normal append path deliberately probes only the indexed rows it needs
@@ -16049,11 +16963,29 @@ var TagDurableObject = class {
16049
16963
  return { event, obligation, exact };
16050
16964
  });
16051
16965
  if (existingCandidates.every(({ exact }) => exact)) {
16052
- return { status: 200, body: { status: "duplicate", version } };
16966
+ const receipts = sql.exec(`
16967
+ SELECT epoch, committed_at, written_version, head_suid FROM tag_commit_receipt
16968
+ WHERE attempt_id = ?
16969
+ `, input.attemptId).toArray();
16970
+ const sameEpoch = receipts.find((row) => sqlNumber(row.epoch, "tag_commit_receipt.epoch") === input.epoch);
16971
+ const replayHead = input.candidates.at(-1)?.suid;
16972
+ const byHead = replayHead === void 0 ? [] : receipts.filter((row) => sqlString(row.head_suid, "tag_commit_receipt.head_suid") === replayHead);
16973
+ const receipt = sameEpoch ?? (byHead.length === 1 ? byHead[0] : void 0) ?? (receipts.length === 1 ? receipts[0] : void 0);
16974
+ if (receipt === void 0) {
16975
+ await this.rearmScheduler(txn);
16976
+ return { ...rejected("duplicate_receipt_missing"), body: { ...rejected("duplicate_receipt_missing").body, version } };
16977
+ }
16978
+ const storedAt = sqlNullableString(receipt.committed_at, "tag_commit_receipt.committed_at");
16979
+ const storedVersion = sqlNullableNumber(receipt.written_version, "tag_commit_receipt.written_version");
16980
+ if (storedAt === null || storedVersion === null) {
16981
+ await this.rearmScheduler(txn);
16982
+ return { ...rejected("duplicate_receipt_unknown"), body: { ...rejected("duplicate_receipt_unknown").body, version } };
16983
+ }
16984
+ return { status: 200, body: { status: "duplicate", version: storedVersion, updatedAt: storedAt } };
16053
16985
  }
16054
- const active = sql.exec("SELECT * FROM tag_reservation WHERE singleton = 1").toArray()[0];
16986
+ const active2 = sql.exec("SELECT * FROM tag_reservation WHERE singleton = 1").toArray()[0];
16055
16987
  const now2 = sqlNullableNumber(control.clock_now_ms, "tag_control.clock_now_ms") ?? Date.now() + sqlNumber(control.clock_offset_ms, "tag_control.clock_offset_ms");
16056
- let reservation = active;
16988
+ let reservation = active2;
16057
16989
  if (reservation !== void 0 && sqlNumber(reservation.expires_at, "tag_reservation.expires_at") <= now2) {
16058
16990
  sql.exec("DELETE FROM tag_reservation WHERE singleton = 1");
16059
16991
  version += 1;
@@ -16146,7 +17078,7 @@ var TagDurableObject = class {
16146
17078
  if (input.faultInjection === "after-append-before-confirm") {
16147
17079
  throw new AppendTransactionFault("Simulated interruption before atomic commit receipt");
16148
17080
  }
16149
- this.writeCommittedSqlReceipt(sql, input, committedAt, events.length, head, confirmsReservation);
17081
+ this.writeCommittedSqlReceipt(sql, input, committedAt, events.length, head, confirmsReservation, version + 1);
16150
17082
  if (confirmsReservation) sql.exec("DELETE FROM tag_reservation WHERE singleton = 1");
16151
17083
  await this.rearmScheduler(txn);
16152
17084
  return {
@@ -16154,7 +17086,8 @@ var TagDurableObject = class {
16154
17086
  body: {
16155
17087
  status: "appended",
16156
17088
  fenceGate: { checked: true, activeFenceCount: 0 },
16157
- version: version + 1
17089
+ version: version + 1,
17090
+ updatedAt: committedAt
16158
17091
  },
16159
17092
  hopFacts
16160
17093
  };
@@ -16555,18 +17488,20 @@ var TagDurableObject = class {
16555
17488
  );
16556
17489
  this.upsertSourcePartitionRegistration(sql, eventServiceId, record.tag, outbox.eventId);
16557
17490
  }
17491
+ ensureTagCommitReceiptWrittenVersion(sql);
16558
17492
  for (const confirmation of record.confirmations) {
16559
17493
  sql.exec(
16560
17494
  `
16561
17495
  INSERT OR IGNORE INTO tag_commit_receipt
16562
- (attempt_id, epoch, committed_at, committed_event_count, head_suid, reservation_confirmed)
16563
- VALUES (?, ?, ?, ?, ?, 1)
17496
+ (attempt_id, epoch, committed_at, committed_event_count, head_suid, reservation_confirmed, written_version)
17497
+ VALUES (?, ?, ?, ?, ?, 1, ?)
16564
17498
  `,
16565
17499
  confirmation.attemptId,
16566
17500
  confirmation.epoch,
16567
17501
  record.updatedAt,
16568
17502
  record.events.filter((event) => event.attemptId === confirmation.attemptId).length,
16569
- record.head
17503
+ record.head,
17504
+ record.version
16570
17505
  );
16571
17506
  }
16572
17507
  }
@@ -16615,13 +17550,13 @@ var TagDurableObject = class {
16615
17550
  async acquire(tag, body, observation) {
16616
17551
  const parsed = acquireFrom(body, tag);
16617
17552
  if (parsed.value === void 0) {
16618
- return error8(400, "invalid_tag_acquire", parsed.error ?? "Invalid acquire request");
17553
+ return error9(400, "invalid_tag_acquire", parsed.error ?? "Invalid acquire request");
16619
17554
  }
16620
17555
  const input = parsed.value;
16621
17556
  observation?.markFirstStorageRead();
16622
17557
  if (this.sqlStorage() !== void 0) {
16623
17558
  const result3 = await this.acquireSql(tag, input);
16624
- return json10(result3.body, result3.status);
17559
+ return json11(result3.body, result3.status);
16625
17560
  }
16626
17561
  const result2 = await this.ctx.storage.transaction(async (txn) => {
16627
17562
  const loaded = await this.recordFor(txn, tag);
@@ -16656,9 +17591,9 @@ var TagDurableObject = class {
16656
17591
  body: { ...rejected("consistency_head_mismatch").body, version: record.version }
16657
17592
  };
16658
17593
  }
16659
- const active = record.activeReservation;
16660
- if (active !== null) {
16661
- if (active.attemptId === input.attemptId && active.epoch === input.epoch) {
17594
+ const active2 = record.activeReservation;
17595
+ if (active2 !== null) {
17596
+ if (active2.attemptId === input.attemptId && active2.epoch === input.epoch) {
16662
17597
  return {
16663
17598
  status: 200,
16664
17599
  body: {
@@ -16703,18 +17638,18 @@ var TagDurableObject = class {
16703
17638
  body: { status: "reserved", reservation, fenceGate, version: updated.version }
16704
17639
  };
16705
17640
  });
16706
- return json10(result2.body, result2.status);
17641
+ return json11(result2.body, result2.status);
16707
17642
  }
16708
17643
  async cancel(tag, body, observation) {
16709
17644
  const parsed = reservationFrom(body);
16710
17645
  if (parsed.value === void 0) {
16711
- return error8(400, "invalid_tag_cancel", parsed.error ?? "Invalid cancel request");
17646
+ return error9(400, "invalid_tag_cancel", parsed.error ?? "Invalid cancel request");
16712
17647
  }
16713
17648
  const input = parsed.value;
16714
17649
  observation?.markFirstStorageRead();
16715
17650
  if (this.sqlStorage() !== void 0) {
16716
17651
  const result3 = await this.cancelSql(tag, input);
16717
- return json10(result3.body, result3.status);
17652
+ return json11(result3.body, result3.status);
16718
17653
  }
16719
17654
  const result2 = await this.ctx.storage.transaction(async (txn) => {
16720
17655
  const loaded = await this.recordFor(txn, tag);
@@ -16749,8 +17684,8 @@ var TagDurableObject = class {
16749
17684
  record = await this.commitExpiryIfNeeded(txn, expiry);
16750
17685
  return { ...rejected(epochError), body: { ...rejected(epochError).body, version: record.version } };
16751
17686
  }
16752
- const active = record.activeReservation;
16753
- if (active === null || active.attemptId !== input.attemptId || active.epoch !== input.epoch || active.token !== input.reservationToken) {
17687
+ const active2 = record.activeReservation;
17688
+ if (active2 === null || active2.attemptId !== input.attemptId || active2.epoch !== input.epoch || active2.token !== input.reservationToken) {
16754
17689
  record = await this.commitExpiryIfNeeded(txn, expiry);
16755
17690
  return {
16756
17691
  ...rejected("reservation_token_required"),
@@ -16765,12 +17700,12 @@ var TagDurableObject = class {
16765
17700
  });
16766
17701
  return { status: 200, body: { status: "cancelled", idempotent: false, version: updated.version } };
16767
17702
  });
16768
- return json10(result2.body, result2.status);
17703
+ return json11(result2.body, result2.status);
16769
17704
  }
16770
17705
  async seal(tag, body, observation) {
16771
17706
  const parsed = epochFrom(body);
16772
17707
  if (parsed.value === void 0) {
16773
- return error8(400, "invalid_tag_seal", parsed.error ?? "Invalid seal request");
17708
+ return error9(400, "invalid_tag_seal", parsed.error ?? "Invalid seal request");
16774
17709
  }
16775
17710
  const input = parsed.value;
16776
17711
  observation?.markFirstStorageRead();
@@ -16805,7 +17740,7 @@ var TagDurableObject = class {
16805
17740
  });
16806
17741
  return { status: 200, body: { status: "sealed", highestEpoch: input.epoch, version: updated.version } };
16807
17742
  });
16808
- return json10(result2.body, result2.status);
17743
+ return json11(result2.body, result2.status);
16809
17744
  }
16810
17745
  /**
16811
17746
  * Coordinator-only import admission. This is deliberately not a flag on
@@ -16814,8 +17749,8 @@ var TagDurableObject = class {
16814
17749
  */
16815
17750
  async bootstrapAppend(tag, body, serviceId) {
16816
17751
  const parsed = bootstrapAppendFrom(body, tag);
16817
- if (parsed.value === void 0) return error8(400, "invalid_bootstrap_admission", parsed.error ?? "Invalid bootstrap admission");
16818
- if (serviceId !== parsed.value.targetServiceId) return error8(409, "bootstrap_service_scope_mismatch", "Bootstrap target service does not match tag scope");
17752
+ if (parsed.value === void 0) return error9(400, "invalid_bootstrap_admission", parsed.error ?? "Invalid bootstrap admission");
17753
+ if (serviceId !== parsed.value.targetServiceId) return error9(409, "bootstrap_service_scope_mismatch", "Bootstrap target service does not match tag scope");
16819
17754
  const input = parsed.value;
16820
17755
  const result2 = await this.ctx.storage.transaction(async (txn) => {
16821
17756
  const loaded = await this.recordFor(txn, tag);
@@ -16836,10 +17771,10 @@ var TagDurableObject = class {
16836
17771
  );
16837
17772
  return { status: 201, body: { status: "bootstrap_admitted", version: updated.version } };
16838
17773
  });
16839
- return json10(result2.body, result2.status);
17774
+ return json11(result2.body, result2.status);
16840
17775
  }
16841
17776
  async closeBootstrap(tag, body) {
16842
- if (!isObject11(body) || !isNonEmptyString11(body.importId) || !isEpoch(body.leaseEpoch)) return error8(400, "invalid_bootstrap_close", "bootstrap importId and leaseEpoch are required");
17777
+ if (!isObject12(body) || !isNonEmptyString11(body.importId) || !isEpoch(body.leaseEpoch)) return error9(400, "invalid_bootstrap_close", "bootstrap importId and leaseEpoch are required");
16843
17778
  const result2 = await this.ctx.storage.transaction(async (txn) => {
16844
17779
  const loaded = await this.recordFor(txn, tag);
16845
17780
  const record = loaded.record;
@@ -16849,7 +17784,7 @@ var TagDurableObject = class {
16849
17784
  const updated = await this.commit(txn, record, { bootstrapAdmission: { ...admission, closed: true } });
16850
17785
  return { status: 200, body: { status: "closed", version: updated.version } };
16851
17786
  });
16852
- return json10(result2.body, result2.status);
17787
+ return json11(result2.body, result2.status);
16853
17788
  }
16854
17789
  directDoorbellPreflight(domainDeliveryClass) {
16855
17790
  const domainClass = domainDeliveryClass === void 0 ? void 0 : readDomainDeliveryClass({ DOMAIN_DELIVERY_CLASS: domainDeliveryClass });
@@ -16868,7 +17803,7 @@ var TagDurableObject = class {
16868
17803
  async append(tag, body, serviceId, domainDeliveryClass, observation) {
16869
17804
  const parsed = appendFrom(body, tag);
16870
17805
  if (parsed.value === void 0) {
16871
- return error8(400, "invalid_tag_append", parsed.error ?? "Invalid append request");
17806
+ return error9(400, "invalid_tag_append", parsed.error ?? "Invalid append request");
16872
17807
  }
16873
17808
  const input = parsed.value;
16874
17809
  try {
@@ -16906,7 +17841,7 @@ var TagDurableObject = class {
16906
17841
  if ((result3.status === 201 || result3.status === 200) && serviceId !== null && serviceId.length > 0 && sourcePartitionRegistration !== "unconfigured") {
16907
17842
  this.scheduleSourcePartitionWatermark(tag, serviceId);
16908
17843
  }
16909
- const response4 = json10(result3.body, result3.status);
17844
+ const response4 = json11(result3.body, result3.status);
16910
17845
  if (result3.status === 201 && serviceId !== null && serviceId.length > 0 && this.env.AUTO_DRAIN_OUTBOX === "true" && (this.env.DOWNSTREAM_QUEUE !== void 0 || doorbellPreflight.status === "ready" && this.env.DOWNSTREAM_DOORBELL !== void 0)) {
16911
17846
  const directRows = doorbellPreflight.status === "ready" && this.env.DOWNSTREAM_DOORBELL !== void 0 ? await this.directDeliveryBeforeResponse(tag, serviceId) : void 0;
16912
17847
  if (sourcePartitionRegistration !== "unconfigured" || sourcePartitionWasRegistered) {
@@ -16923,7 +17858,19 @@ var TagDurableObject = class {
16923
17858
  const loaded = await this.recordFor(txn, tag);
16924
17859
  let record = loaded.record;
16925
17860
  if (batchIsExactDuplicate(record, input)) {
16926
- return { status: 200, body: { status: "duplicate", version: record.version } };
17861
+ const receipts = record.writeReceipts ?? {};
17862
+ const sameEpoch = receipts[`${input.attemptId}:${input.epoch}`];
17863
+ const forAttempt = Object.entries(receipts).filter(([key]) => key.startsWith(`${input.attemptId}:`));
17864
+ const replayHead = input.candidates.at(-1)?.suid;
17865
+ const byHead = replayHead === void 0 ? [] : forAttempt.filter(([, value]) => value.headSuid === replayHead);
17866
+ const receipt = sameEpoch ?? (byHead.length === 1 ? byHead[0]?.[1] : void 0) ?? (forAttempt.length === 1 ? forAttempt[0]?.[1] : void 0);
17867
+ if (receipt === void 0) {
17868
+ return {
17869
+ ...rejected("duplicate_receipt_unknown"),
17870
+ body: { ...rejected("duplicate_receipt_unknown").body, version: record.version }
17871
+ };
17872
+ }
17873
+ return { status: 200, body: { status: "duplicate", version: receipt.version, updatedAt: receipt.updatedAt } };
16927
17874
  }
16928
17875
  const expiry = expireReservation(record);
16929
17876
  record = expiry.record;
@@ -16936,9 +17883,9 @@ var TagDurableObject = class {
16936
17883
  await this.commitExpiryIfNeeded(txn, expiry);
16937
17884
  return fenceGateRejected();
16938
17885
  }
16939
- const active = record.activeReservation;
16940
- const confirmsReservation = active !== null && active.attemptId === input.attemptId && active.epoch === input.epoch && active.token === input.reservationToken;
16941
- if (active !== null && (active.attemptId !== input.attemptId || active.epoch !== input.epoch || active.token !== input.reservationToken)) {
17886
+ const active2 = record.activeReservation;
17887
+ const confirmsReservation = active2 !== null && active2.attemptId === input.attemptId && active2.epoch === input.epoch && active2.token === input.reservationToken;
17888
+ if (active2 !== null && (active2.attemptId !== input.attemptId || active2.epoch !== input.epoch || active2.token !== input.reservationToken)) {
16942
17889
  record = await this.commitExpiryIfNeeded(txn, expiry);
16943
17890
  return {
16944
17891
  ...rejected("reservation_token_required"),
@@ -17000,13 +17947,20 @@ var TagDurableObject = class {
17000
17947
  alarmDueAt: null,
17001
17948
  confirmations: confirmsReservation ? withMaxEpoch(record.confirmations, input.attemptId, input.epoch) : record.confirmations
17002
17949
  });
17003
- await this.write(txn, updated, serviceId ?? "");
17950
+ const recorded = {
17951
+ ...updated,
17952
+ writeReceipts: {
17953
+ ...record.writeReceipts ?? {},
17954
+ [`${input.attemptId}:${input.epoch}`]: { version: updated.version, updatedAt: updated.updatedAt, headSuid: updated.head }
17955
+ }
17956
+ };
17957
+ await this.write(txn, recorded, serviceId ?? "");
17004
17958
  return {
17005
17959
  status: 201,
17006
- body: { status: "appended", fenceGate, version: updated.version }
17960
+ body: { status: "appended", fenceGate, version: recorded.version, updatedAt: recorded.updatedAt }
17007
17961
  };
17008
17962
  });
17009
- const response3 = json10(result2.body, result2.status);
17963
+ const response3 = json11(result2.body, result2.status);
17010
17964
  if (result2.status === 201 && serviceId !== null && serviceId.length > 0 && this.env.AUTO_DRAIN_OUTBOX === "true" && (this.env.DOWNSTREAM_QUEUE !== void 0 || doorbellPreflight.status === "ready" && this.env.DOWNSTREAM_DOORBELL !== void 0)) {
17011
17965
  const directRows = doorbellPreflight.status === "ready" && this.env.DOWNSTREAM_DOORBELL !== void 0 ? await this.directDeliveryBeforeResponse(tag, serviceId) : void 0;
17012
17966
  withGlobalAdmission2(
@@ -17018,16 +17972,16 @@ var TagDurableObject = class {
17018
17972
  return response3;
17019
17973
  } catch (failure3) {
17020
17974
  if (failure3 instanceof PartitionRegistrationUnavailableError) {
17021
- return error8(503, "partition_registration_unavailable", "Source partition registration is unavailable; retry the commit.", true);
17975
+ return error9(503, "partition_registration_unavailable", "Source partition registration is unavailable; retry the commit.", true);
17022
17976
  }
17023
17977
  if (failure3 instanceof AppendTransactionFault) {
17024
- return error8(
17978
+ return error9(
17025
17979
  503,
17026
17980
  "simulated_append_crash",
17027
17981
  "Simulated interruption before atomic append and confirmation commit"
17028
17982
  );
17029
17983
  }
17030
- return error8(500, "tag_append_failure", "Tag append could not be persisted");
17984
+ return error9(500, "tag_append_failure", "Tag append could not be persisted");
17031
17985
  }
17032
17986
  }
17033
17987
  /**
@@ -17143,7 +18097,7 @@ var TagDurableObject = class {
17143
18097
  let timer;
17144
18098
  const operationResult = Promise.resolve().then(operation).then(
17145
18099
  (value) => ({ status: "completed", value }),
17146
- (error10) => ({ status: "failed", error: error10 })
18100
+ (error11) => ({ status: "failed", error: error11 })
17147
18101
  );
17148
18102
  const timeout = new Promise((resolve) => {
17149
18103
  timer = setTimeout(() => resolve({ status: "timeout" }), budgetMs);
@@ -17194,14 +18148,14 @@ var TagDurableObject = class {
17194
18148
  envelopeBytes,
17195
18149
  status: "success"
17196
18150
  });
17197
- } catch (error10) {
18151
+ } catch (error11) {
17198
18152
  console.warn("direct_doorbell_status", {
17199
18153
  status: "queued-degraded",
17200
18154
  reason: "direct_doorbell_delivery_failed",
17201
18155
  correlationId,
17202
18156
  envelopeBytes,
17203
- failureKind: classifyDirectDoorbellFailure(error10),
17204
- error: String(error10)
18157
+ failureKind: classifyDirectDoorbellFailure(error11),
18158
+ error: String(error11)
17205
18159
  });
17206
18160
  }
17207
18161
  }
@@ -17262,7 +18216,7 @@ var TagDurableObject = class {
17262
18216
  async confirm(tag, body) {
17263
18217
  const parsed = reservationFrom(body);
17264
18218
  if (parsed.value === void 0) {
17265
- return error8(400, "invalid_tag_confirm", parsed.error ?? "Invalid confirm request");
18219
+ return error9(400, "invalid_tag_confirm", parsed.error ?? "Invalid confirm request");
17266
18220
  }
17267
18221
  const input = parsed.value;
17268
18222
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -17278,8 +18232,8 @@ var TagDurableObject = class {
17278
18232
  record = await this.commitExpiryIfNeeded(txn, expiry);
17279
18233
  return { ...rejected(epochError), body: { ...rejected(epochError).body, version: record.version } };
17280
18234
  }
17281
- const active = record.activeReservation;
17282
- if (active !== null && active.attemptId === input.attemptId && active.epoch === input.epoch && active.token === input.reservationToken) {
18235
+ const active2 = record.activeReservation;
18236
+ if (active2 !== null && active2.attemptId === input.attemptId && active2.epoch === input.epoch && active2.token === input.reservationToken) {
17283
18237
  record = await this.commitExpiryIfNeeded(txn, expiry);
17284
18238
  return {
17285
18239
  ...rejected("append_required_for_confirmation"),
@@ -17292,12 +18246,12 @@ var TagDurableObject = class {
17292
18246
  body: { ...rejected("confirmation_not_found").body, version: record.version }
17293
18247
  };
17294
18248
  });
17295
- return json10(result2.body, result2.status);
18249
+ return json11(result2.body, result2.status);
17296
18250
  }
17297
18251
  async installFence(tag, body) {
17298
18252
  const parsed = fenceFrom(body);
17299
18253
  if (parsed.value === void 0) {
17300
- return error8(400, "invalid_tag_fence", parsed.error ?? "Invalid fence request");
18254
+ return error9(400, "invalid_tag_fence", parsed.error ?? "Invalid fence request");
17301
18255
  }
17302
18256
  const input = parsed.value;
17303
18257
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -17334,12 +18288,12 @@ var TagDurableObject = class {
17334
18288
  });
17335
18289
  return { status: 201, body: { status: "fence-installed", idempotent: false, version: updated.version } };
17336
18290
  });
17337
- return json10(result2.body, result2.status);
18291
+ return json11(result2.body, result2.status);
17338
18292
  }
17339
18293
  async clearFence(tag, body) {
17340
18294
  const parsed = fenceFrom(body);
17341
18295
  if (parsed.value === void 0) {
17342
- return error8(400, "invalid_tag_fence", parsed.error ?? "Invalid fence request");
18296
+ return error9(400, "invalid_tag_fence", parsed.error ?? "Invalid fence request");
17343
18297
  }
17344
18298
  const input = parsed.value;
17345
18299
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -17365,7 +18319,7 @@ var TagDurableObject = class {
17365
18319
  });
17366
18320
  return { status: 200, body: { status: "fence-cleared", idempotent: false, version: updated.version } };
17367
18321
  });
17368
- return json10(result2.body, result2.status);
18322
+ return json11(result2.body, result2.status);
17369
18323
  }
17370
18324
  /**
17371
18325
  * Returns Tag-side repair facts only. Journal observations are deliberately
@@ -17401,7 +18355,7 @@ var TagDurableObject = class {
17401
18355
  }
17402
18356
  };
17403
18357
  });
17404
- return json10(result2.body, result2.status);
18358
+ return json11(result2.body, result2.status);
17405
18359
  }
17406
18360
  /**
17407
18361
  * Internal outbox handoff: enqueuedAt is persisted before any Queue send so
@@ -17411,10 +18365,10 @@ var TagDurableObject = class {
17411
18365
  async pendingOutbox(tag, serviceId, body) {
17412
18366
  const parsed = outboxPendingFrom(body);
17413
18367
  if (parsed.value === void 0) {
17414
- return error8(400, "invalid_outbox_pending", parsed.error ?? "Invalid outbox pending request");
18368
+ return error9(400, "invalid_outbox_pending", parsed.error ?? "Invalid outbox pending request");
17415
18369
  }
17416
18370
  if (!isNonEmptyString11(serviceId)) {
17417
- return error8(400, "outbox_service_identity_required", "Outbox delivery requires a service identity");
18371
+ return error9(400, "outbox_service_identity_required", "Outbox delivery requires a service identity");
17418
18372
  }
17419
18373
  const input = parsed.value;
17420
18374
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -17490,7 +18444,7 @@ var TagDurableObject = class {
17490
18444
  }
17491
18445
  return { status: 200, body: { rows } };
17492
18446
  });
17493
- return json10(result2.body, result2.status);
18447
+ return json11(result2.body, result2.status);
17494
18448
  }
17495
18449
  /**
17496
18450
  * Source-side obligation scanner. It deliberately does not call the Queue,
@@ -17560,7 +18514,7 @@ var TagDurableObject = class {
17560
18514
  }
17561
18515
  };
17562
18516
  });
17563
- return json10(result2.body, result2.status);
18517
+ return json11(result2.body, result2.status);
17564
18518
  }
17565
18519
  /** Record a retry or terminal poison disposition without changing the source event. */
17566
18520
  async recordOutboxFailure(tag, delivery, failure3) {
@@ -17614,16 +18568,16 @@ var TagDurableObject = class {
17614
18568
  async markOutboxDelivered(tag, body) {
17615
18569
  const parsed = outboxMarkFrom(body);
17616
18570
  if (parsed.value === void 0) {
17617
- return error8(400, "invalid_outbox_delivery_mark", parsed.error ?? "Invalid outbox delivery mark");
18571
+ return error9(400, "invalid_outbox_delivery_mark", parsed.error ?? "Invalid outbox delivery mark");
17618
18572
  }
17619
18573
  const input = parsed.value;
17620
18574
  try {
17621
18575
  const joined = await Promise.all(input.deliveries.map((delivery) => this.globalReceiptMatches(delivery)));
17622
18576
  if (joined.some((value) => !value)) {
17623
- return error8(409, "outbox_global_receipt_unverified", "Global receipt and membership must be read back before source acknowledgement");
18577
+ return error9(409, "outbox_global_receipt_unverified", "Global receipt and membership must be read back before source acknowledgement");
17624
18578
  }
17625
18579
  } catch {
17626
- return error8(503, "outbox_global_receipt_unavailable", "Global receipt verification is unavailable");
18580
+ return error9(503, "outbox_global_receipt_unavailable", "Global receipt verification is unavailable");
17627
18581
  }
17628
18582
  const result2 = await this.ctx.storage.transaction(async (txn) => {
17629
18583
  if (this.sqlStorage() !== void 0) {
@@ -17662,7 +18616,7 @@ var TagDurableObject = class {
17662
18616
  }
17663
18617
  return { status: 200, body: { marked, idempotent: marked === 0 } };
17664
18618
  });
17665
- return json10(result2.body, result2.status);
18619
+ return json11(result2.body, result2.status);
17666
18620
  }
17667
18621
  /**
17668
18622
  * The delivery handoff reads its universe from `tag_outbox_obligation`.
@@ -17801,7 +18755,7 @@ var TagDurableObject = class {
17801
18755
  async acquireRepairLease(tag, body) {
17802
18756
  const parsed = repairAcquireFrom(body, tag);
17803
18757
  if (parsed.value === void 0) {
17804
- return error8(400, "invalid_repair_acquire", parsed.error ?? "Invalid repair acquire request");
18758
+ return error9(400, "invalid_repair_acquire", parsed.error ?? "Invalid repair acquire request");
17805
18759
  }
17806
18760
  const input = parsed.value;
17807
18761
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -17847,12 +18801,12 @@ var TagDurableObject = class {
17847
18801
  }
17848
18802
  };
17849
18803
  });
17850
- return json10(result2.body, result2.status);
18804
+ return json11(result2.body, result2.status);
17851
18805
  }
17852
18806
  async renewRepairLease(tag, body) {
17853
18807
  const parsed = repairLeaseFrom(body);
17854
18808
  if (parsed.value === void 0) {
17855
- return error8(400, "invalid_repair_renew", parsed.error ?? "Invalid repair renew request");
18809
+ return error9(400, "invalid_repair_renew", parsed.error ?? "Invalid repair renew request");
17856
18810
  }
17857
18811
  const input = parsed.value;
17858
18812
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -17876,12 +18830,12 @@ var TagDurableObject = class {
17876
18830
  }
17877
18831
  };
17878
18832
  });
17879
- return json10(result2.body, result2.status);
18833
+ return json11(result2.body, result2.status);
17880
18834
  }
17881
18835
  async unionRepairScope(tag, body) {
17882
18836
  const parsed = repairScopeUnionFrom(body, tag);
17883
18837
  if (parsed.value === void 0) {
17884
- return error8(400, "invalid_repair_scope_union", parsed.error ?? "Invalid repair scope union request");
18838
+ return error9(400, "invalid_repair_scope_union", parsed.error ?? "Invalid repair scope union request");
17885
18839
  }
17886
18840
  const input = parsed.value;
17887
18841
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -17917,12 +18871,12 @@ var TagDurableObject = class {
17917
18871
  body: { status: "repair-scope-unioned", scopeVersion: updated.repairScopeVersion, scope: updated.repairScope }
17918
18872
  };
17919
18873
  });
17920
- return json10(result2.body, result2.status);
18874
+ return json11(result2.body, result2.status);
17921
18875
  }
17922
18876
  async applyRepair(tag, body) {
17923
18877
  const parsed = repairApplyFrom(body, tag);
17924
18878
  if (parsed.value === void 0) {
17925
- return error8(400, "invalid_repair_apply", parsed.error ?? "Invalid repair apply request");
18879
+ return error9(400, "invalid_repair_apply", parsed.error ?? "Invalid repair apply request");
17926
18880
  }
17927
18881
  const input = parsed.value;
17928
18882
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -18003,12 +18957,12 @@ var TagDurableObject = class {
18003
18957
  body: { status: branch, idempotent: false, head: (updatedRecord ?? record).head, version: (updatedRecord ?? record).version }
18004
18958
  };
18005
18959
  });
18006
- return json10(result2.body, result2.status);
18960
+ return json11(result2.body, result2.status);
18007
18961
  }
18008
18962
  async auditRepair(tag, body) {
18009
18963
  const parsed = repairAuditFrom(body, tag);
18010
18964
  if (parsed.value === void 0) {
18011
- return error8(400, "invalid_repair_audit", parsed.error ?? "Invalid repair audit request");
18965
+ return error9(400, "invalid_repair_audit", parsed.error ?? "Invalid repair audit request");
18012
18966
  }
18013
18967
  const input = parsed.value;
18014
18968
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -18045,12 +18999,12 @@ var TagDurableObject = class {
18045
18999
  await txn.put(REPAIR_FACTS_KEY, { ...facts, audits: [...facts.audits, audit] });
18046
19000
  return { status: 200, body: { status: "repair-audited", idempotent: false, branch: audit.branch } };
18047
19001
  });
18048
- return json10(result2.body, result2.status);
19002
+ return json11(result2.body, result2.status);
18049
19003
  }
18050
19004
  async clearRepairFence(tag, body) {
18051
19005
  const parsed = repairClearFrom(body);
18052
19006
  if (parsed.value === void 0) {
18053
- return error8(400, "invalid_repair_clear", parsed.error ?? "Invalid repair clear request");
19007
+ return error9(400, "invalid_repair_clear", parsed.error ?? "Invalid repair clear request");
18054
19008
  }
18055
19009
  const input = parsed.value;
18056
19010
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -18081,16 +19035,16 @@ var TagDurableObject = class {
18081
19035
  });
18082
19036
  return { status: 200, body: { status: "repair-fence-cleared", idempotent: false, version: updated.version } };
18083
19037
  });
18084
- return json10(result2.body, result2.status);
19038
+ return json11(result2.body, result2.status);
18085
19039
  }
18086
19040
  async setClockOffset(tag, body) {
18087
- if (!isObject11(body)) {
18088
- return error8(400, "invalid_tag_clock", "offsetMs or nowMs must be a safe integer");
19041
+ if (!isObject12(body)) {
19042
+ return error9(400, "invalid_tag_clock", "offsetMs or nowMs must be a safe integer");
18089
19043
  }
18090
19044
  const nowMs = body.nowMs;
18091
19045
  const offsetMs = body.offsetMs;
18092
19046
  if (!isSafeInteger(nowMs) && !isSafeInteger(offsetMs)) {
18093
- return error8(400, "invalid_tag_clock", "offsetMs or nowMs must be a safe integer");
19047
+ return error9(400, "invalid_tag_clock", "offsetMs or nowMs must be a safe integer");
18094
19048
  }
18095
19049
  const result2 = await this.ctx.storage.transaction(async (txn) => {
18096
19050
  const loaded = await this.recordFor(txn, tag);
@@ -18108,7 +19062,7 @@ var TagDurableObject = class {
18108
19062
  }
18109
19063
  };
18110
19064
  });
18111
- return json10(result2.body, result2.status);
19065
+ return json11(result2.body, result2.status);
18112
19066
  }
18113
19067
  async runAlarm() {
18114
19068
  const due = await this.ctx.storage.transaction(async (txn) => {
@@ -18227,16 +19181,16 @@ var TagStateCheckpointFault = class extends Error {
18227
19181
  this.name = "TagStateCheckpointFault";
18228
19182
  }
18229
19183
  };
18230
- function json11(body, status = 200) {
19184
+ function json12(body, status = 200) {
18231
19185
  return new Response(JSON.stringify(body), {
18232
19186
  status,
18233
19187
  headers: { "content-type": "application/json; charset=utf-8" }
18234
19188
  });
18235
19189
  }
18236
- function error9(status, code, message) {
18237
- return json11({ code, error: message }, status);
19190
+ function error10(status, code, message) {
19191
+ return json12({ code, error: message }, status);
18238
19192
  }
18239
- function isObject12(value) {
19193
+ function isObject13(value) {
18240
19194
  return typeof value === "object" && value !== null && !Array.isArray(value);
18241
19195
  }
18242
19196
  function isNonEmptyString12(value) {
@@ -18251,7 +19205,7 @@ function sqlNullableString2(value, column) {
18251
19205
  return sqlString2(value, column);
18252
19206
  }
18253
19207
  function parseIdentity(value) {
18254
- if (!isObject12(value) || !isNonEmptyString12(value.serviceId) || !isNonEmptyString12(value.tag) || !isNonEmptyString12(value.projectorId)) {
19208
+ if (!isObject13(value) || !isNonEmptyString12(value.serviceId) || !isNonEmptyString12(value.tag) || !isNonEmptyString12(value.projectorId)) {
18255
19209
  return void 0;
18256
19210
  }
18257
19211
  return { serviceId: value.serviceId, tag: value.tag, projectorId: value.projectorId };
@@ -18313,17 +19267,17 @@ var TagStateDurableObject = class {
18313
19267
  async fetch(request) {
18314
19268
  const url = new URL(request.url);
18315
19269
  if (request.method !== "POST" || url.pathname !== "/read") {
18316
- return error9(404, "tag_state_route_not_found", "TagState route was not found");
19270
+ return error10(404, "tag_state_route_not_found", "TagState route was not found");
18317
19271
  }
18318
19272
  let body;
18319
19273
  try {
18320
19274
  body = await request.json();
18321
19275
  } catch {
18322
- return error9(400, "tag_state_validation_error", "TagState request must be JSON");
19276
+ return error10(400, "tag_state_validation_error", "TagState request must be JSON");
18323
19277
  }
18324
19278
  const identity2 = parseIdentity(body);
18325
19279
  if (identity2 === void 0) {
18326
- return error9(400, "tag_state_validation_error", "TagState identity requires serviceId, tag, and projectorId");
19280
+ return error10(400, "tag_state_validation_error", "TagState identity requires serviceId, tag, and projectorId");
18327
19281
  }
18328
19282
  return await this.read(identity2);
18329
19283
  }
@@ -18345,16 +19299,16 @@ var TagStateDurableObject = class {
18345
19299
  return await this.continueRebuild(identity2, projector, cache);
18346
19300
  } catch (caught) {
18347
19301
  if (caught instanceof TagStateIdentityConflict) {
18348
- return error9(409, "tag_state_identity_conflict", "TagState Durable Object identity changed");
19302
+ return error10(409, "tag_state_identity_conflict", "TagState Durable Object identity changed");
18349
19303
  }
18350
19304
  if (caught instanceof TagStateUnknownProjector) {
18351
- return error9(404, "tag_state_unknown_projector", "TagState projector is not registered");
19305
+ return error10(404, "tag_state_unknown_projector", "TagState projector is not registered");
18352
19306
  }
18353
19307
  if (caught instanceof TagStateRegistryFailure) {
18354
- return error9(503, "tag_state_projector_registry_failure", "TagState projector registry is unavailable");
19308
+ return error10(503, "tag_state_projector_registry_failure", "TagState projector registry is unavailable");
18355
19309
  }
18356
19310
  if (caught instanceof TagStateSourceFailure) {
18357
- return error9(caught.status, "tag_state_source_frontier_failure", "TagState source frontier could not be read");
19311
+ return error10(caught.status, "tag_state_source_frontier_failure", "TagState source frontier could not be read");
18358
19312
  }
18359
19313
  if (caught instanceof TagStateCacheCorruption) {
18360
19314
  try {
@@ -18362,21 +19316,21 @@ var TagStateDurableObject = class {
18362
19316
  this.beginRebuild(projector, "cache-corrupt");
18363
19317
  } catch (rebuildFailure) {
18364
19318
  if (rebuildFailure instanceof TagStateRegistryFailure) {
18365
- return error9(503, "tag_state_projector_registry_failure", "TagState projector registry is unavailable");
19319
+ return error10(503, "tag_state_projector_registry_failure", "TagState projector registry is unavailable");
18366
19320
  }
18367
19321
  }
18368
- return error9(409, "tag_state_cache_corrupt", "TagState cache is corrupt and is rebuilding");
19322
+ return error10(409, "tag_state_cache_corrupt", "TagState cache is corrupt and is rebuilding");
18369
19323
  }
18370
19324
  if (caught instanceof TagStateCheckpointFault) {
18371
- return error9(503, "tag_state_rebuild_interrupted", "TagState replay checkpoint was interrupted");
19325
+ return error10(503, "tag_state_rebuild_interrupted", "TagState replay checkpoint was interrupted");
18372
19326
  }
18373
- return error9(503, "tag_state_unavailable", "TagState cache is unavailable");
19327
+ return error10(503, "tag_state_unavailable", "TagState cache is unavailable");
18374
19328
  }
18375
19329
  }
18376
19330
  async beginDeltaOrRespondReady(identity2, projector, cache) {
18377
19331
  const page = await this.readSource(identity2, cache.lastSuid, void 0);
18378
19332
  if (page.events.length === 0 && page.completeThrough !== null) {
18379
- return json11(this.success(projector, cache.stateJson, cache.lastSuid));
19333
+ return json12(this.success(projector, cache.stateJson, cache.lastSuid));
18380
19334
  }
18381
19335
  const rebuild = this.beginRebuild(projector, "normal-delta", {
18382
19336
  cursor: cache.lastSuid,
@@ -18425,9 +19379,9 @@ var TagStateDurableObject = class {
18425
19379
  });
18426
19380
  if (this.g46CheckpointFault === "after-checkpoint") throw new TagStateCheckpointFault();
18427
19381
  if (!complete) {
18428
- return error9(503, "tag_state_rebuild_in_progress", "TagState replay is rebuilding to its frozen frontier");
19382
+ return error10(503, "tag_state_rebuild_in_progress", "TagState replay is rebuilding to its frozen frontier");
18429
19383
  }
18430
- return json11(this.success(projector, accumulatorJson, page.completeThrough));
19384
+ return json12(this.success(projector, accumulatorJson, page.completeThrough));
18431
19385
  }
18432
19386
  success(projector, stateJson, lastSortedUniqueId) {
18433
19387
  try {
@@ -18484,7 +19438,7 @@ var TagStateDurableObject = class {
18484
19438
  }
18485
19439
  }
18486
19440
  assertSourcePage(cursor, expectedThrough, page) {
18487
- if (!isObject12(page) || !Array.isArray(page.events) || typeof page.lastSortableUniqueId !== "string" || typeof page.through !== "string" || page.completeThrough !== null && typeof page.completeThrough !== "string") {
19441
+ if (!isObject13(page) || !Array.isArray(page.events) || typeof page.lastSortableUniqueId !== "string" || typeof page.through !== "string" || page.completeThrough !== null && typeof page.completeThrough !== "string") {
18488
19442
  throw new TagStateSourceFailure(503, new Error("TagState source response was malformed"));
18489
19443
  }
18490
19444
  if (expectedThrough !== void 0 && expectedThrough !== null && page.through !== expectedThrough) {
@@ -18909,9 +19863,9 @@ var PostgresEventStore = class {
18909
19863
  await transaction.unsafe(SCHEMA, [], { prepare: false });
18910
19864
  });
18911
19865
  this.sql = sql;
18912
- } catch (error10) {
19866
+ } catch (error11) {
18913
19867
  await sql.end({ timeout: 1 });
18914
- throw error10;
19868
+ throw error11;
18915
19869
  }
18916
19870
  }
18917
19871
  /** Close an owned request/test client without touching durable records. */
@@ -19102,6 +20056,65 @@ var PostgresEventStore = class {
19102
20056
  }
19103
20057
  return outcome === "stored" ? { outcome, kind: "stored", event: stored } : { outcome, kind: outcome, incident };
19104
20058
  }
20059
+ /**
20060
+ * DDL columns only. C# rows have no provenance and no allocator lineage;
20061
+ * this read must not invent either, and it must not treat Tags as
20062
+ * committed membership.
20063
+ */
20064
+ async readLogicalEvents(serviceId) {
20065
+ const rows = await this.query(
20066
+ `SELECT "ServiceId" AS service_id, "Id"::text AS event_id,
20067
+ "SortableUniqueId" AS suid, "Payload"::text AS payload,
20068
+ "EventType" AS event_type, "Tags" AS event_tags,
20069
+ "Timestamp"::text AS timestamp, "CausationId" AS causation_id,
20070
+ "CorrelationId" AS correlation_id, "ExecutedUser" AS executed_user
20071
+ FROM dcb_events
20072
+ WHERE "ServiceId" = $1
20073
+ ORDER BY "SortableUniqueId" ASC, "Id" ASC`,
20074
+ [serviceId]
20075
+ );
20076
+ return rows.map((row) => ({
20077
+ serviceId: asString4(row.service_id, "service_id"),
20078
+ id: asString4(row.event_id, "event_id"),
20079
+ sortableUniqueId: asString4(row.suid, "suid"),
20080
+ eventType: asString4(row.event_type, "event_type"),
20081
+ payload: asString4(row.payload, "payload"),
20082
+ tags: asStringArray2(row.event_tags, "event_tags"),
20083
+ timestamp: canonicalUtcTimestamp(row.timestamp, "timestamp"),
20084
+ causationId: nullableString2(row.causation_id, "causation_id"),
20085
+ correlationId: nullableString2(row.correlation_id, "correlation_id"),
20086
+ executedUser: nullableString2(row.executed_user, "executed_user")
20087
+ }));
20088
+ }
20089
+ /** Insert one DDL row. Does not write dcb_event_ops or a provenance stamp. */
20090
+ async appendLogicalEvent(event) {
20091
+ JSON.parse(event.payload);
20092
+ assertSortableUniqueId(event.sortableUniqueId);
20093
+ if (!isRfc4122Uuid(event.id)) {
20094
+ throw new CanonicalEventIdentityConflictError("postgres", event.id, "logical event id must be an RFC 4122 UUID");
20095
+ }
20096
+ assertUtcTimestamp(event.timestamp, event.id);
20097
+ const sql = this.requireSql();
20098
+ await sql.begin(async (transaction) => {
20099
+ await transaction.unsafe(
20100
+ `INSERT INTO dcb_events
20101
+ ("ServiceId", "Id", "SortableUniqueId", "EventType", "Payload", "Tags", "Timestamp", "CausationId", "CorrelationId", "ExecutedUser")
20102
+ VALUES ($1, $2::uuid, $3, $4, $5::text::json, $6::text::jsonb, $7::timestamptz, $8, $9, $10)`,
20103
+ [
20104
+ event.serviceId,
20105
+ event.id,
20106
+ event.sortableUniqueId,
20107
+ event.eventType,
20108
+ event.payload,
20109
+ JSON.stringify(event.tags),
20110
+ event.timestamp,
20111
+ event.causationId,
20112
+ event.correlationId,
20113
+ event.executedUser
20114
+ ]
20115
+ );
20116
+ });
20117
+ }
19105
20118
  async readAllEvents(serviceId, since) {
19106
20119
  if (since.length !== 0) assertSortableUniqueId(since);
19107
20120
  const rows = await this.query(
@@ -19574,12 +20587,12 @@ function encodedCommitSnapshotLogBytes(record) {
19574
20587
  function assertCommitSnapshotLogSize(record) {
19575
20588
  const encodedBytes2 = encodedCommitSnapshotLogBytes(record);
19576
20589
  if (encodedBytes2 > COMMIT_SNAPSHOT_LOG_BYTE_BUDGET) {
19577
- const error10 = new Error(
20590
+ const error11 = new Error(
19578
20591
  `Commit snapshot log is ${encodedBytes2} bytes; budget is ${COMMIT_SNAPSHOT_LOG_BYTE_BUDGET} bytes`
19579
20592
  );
19580
- error10.code = "commit-snapshot-log-size";
19581
- error10.encodedBytes = encodedBytes2;
19582
- throw error10;
20593
+ error11.code = "commit-snapshot-log-size";
20594
+ error11.encodedBytes = encodedBytes2;
20595
+ throw error11;
19583
20596
  }
19584
20597
  return encodedBytes2;
19585
20598
  }
@@ -19598,8 +20611,8 @@ function createCommitTraceConsoleSink(options = {}) {
19598
20611
  if (record === void 0) return;
19599
20612
  try {
19600
20613
  assertCommitSnapshotLogSize(record);
19601
- } catch (error10) {
19602
- const encodedBytes2 = typeof error10 === "object" && error10 !== null && "encodedBytes" in error10 && typeof error10.encodedBytes === "number" ? error10.encodedBytes : encodedCommitSnapshotLogBytes(record);
20614
+ } catch (error11) {
20615
+ const encodedBytes2 = typeof error11 === "object" && error11 !== null && "encodedBytes" in error11 && typeof error11.encodedBytes === "number" ? error11.encodedBytes : encodedCommitSnapshotLogBytes(record);
19603
20616
  reportRejectedSize(Object.freeze({
19604
20617
  schema: COMMIT_SNAPSHOT_LOG_SCHEMA,
19605
20618
  event: "commit.snapshot-size-rejected",
@@ -19608,41 +20621,107 @@ function createCommitTraceConsoleSink(options = {}) {
19608
20621
  encodedBytes: encodedBytes2,
19609
20622
  byteBudget: COMMIT_SNAPSHOT_LOG_BYTE_BUDGET
19610
20623
  }));
19611
- throw error10;
20624
+ throw error11;
19612
20625
  }
19613
20626
  log(record);
19614
20627
  }
19615
20628
  });
19616
20629
  }
19617
20630
 
19618
- // src/scope/ControlRouteScope.ts
19619
- function response2(status, code, error10) {
19620
- return new Response(JSON.stringify({ code, error: error10 }), {
19621
- status,
19622
- headers: { "content-type": "application/json; charset=utf-8" }
19623
- });
20631
+ // src/shard/ShardRotation.ts
20632
+ var ShardRotationError = class extends Error {
20633
+ diagnostic;
20634
+ constructor(diagnostic) {
20635
+ super(diagnostic.code);
20636
+ this.name = "ShardRotationError";
20637
+ this.diagnostic = diagnostic;
20638
+ }
20639
+ };
20640
+ function fail(code, path, reason) {
20641
+ throw new ShardRotationError({ code, path, reason });
19624
20642
  }
19625
- function scopeIdentityMissingResponse() {
19626
- return response2(503, "scope.identity_missing", "A deployment service identity is required for this scope");
20643
+ function createRotationState(active2) {
20644
+ if (typeof active2 !== "string" || active2.length === 0) fail("ACTIVE_COUNT", "active", "active-missing");
20645
+ return { sealed: [], active: active2, ledger: [] };
19627
20646
  }
19628
- function enforceControlRouteScope(input) {
19629
- let actual;
19630
- try {
19631
- actual = input.provider.forRequest(input.request, input.requestOptions).serviceId;
19632
- } catch (caught) {
19633
- if (caught instanceof ServiceIdentityMissingError) {
19634
- console.error({ schema: "sdt.scope/v1", code: "scope.identity_missing", route: input.route });
19635
- return { response: scopeIdentityMissingResponse() };
19636
- }
19637
- throw caught;
20647
+ function assertStrictlyBefore(lastD1_1, firstD1_2) {
20648
+ assertSortableUniqueId(lastD1_1);
20649
+ assertSortableUniqueId(firstD1_2);
20650
+ if (compareSortableUniqueId(lastD1_1, firstD1_2) >= 0) {
20651
+ fail("ORDER_INVARIANT", "last(D1-1)<first(D1-2)", "order-invariant");
19638
20652
  }
19639
- if (input.pathServiceId !== actual) {
19640
- console.warn({ schema: "sdt.scope/v1", code: "scope.mismatch", route: input.route });
19641
- return {
19642
- response: response2(403, "scope.mismatch", "The path service identity is not authorized for this deployment")
19643
- };
20653
+ }
20654
+ function maxSortableUniqueId(values) {
20655
+ if (values.length === 0) fail("SEAL_MAX_MISSING", "d1-1", "seal-max-missing");
20656
+ let max = assertSortableUniqueId(values[0]).value;
20657
+ for (let i = 1; i < values.length; i += 1) {
20658
+ const next = assertSortableUniqueId(values[i]).value;
20659
+ if (next > max) max = next;
19644
20660
  }
19645
- return { serviceId: actual };
20661
+ return max;
20662
+ }
20663
+ function rotateAppend(state, sealedId, shardSuids, nextActiveId) {
20664
+ if (sealedId !== state.active) fail("UNKNOWN_SHARD", sealedId, "unknown-shard");
20665
+ if (typeof nextActiveId !== "string" || nextActiveId.length === 0 || nextActiveId === sealedId) {
20666
+ fail("ACTIVE_COUNT", "active", "active-count");
20667
+ }
20668
+ if (state.sealed.some((entry) => entry.id === nextActiveId)) {
20669
+ fail("ACTIVE_COUNT", nextActiveId, "active-already-sealed");
20670
+ }
20671
+ if (state.sealed.some((entry) => entry.id === sealedId)) fail("IDENTITY_SWAP", sealedId, "identity-swap");
20672
+ const lastSuid = maxSortableUniqueId(shardSuids);
20673
+ return {
20674
+ sealed: [...state.sealed, { id: sealedId, lastSuid }],
20675
+ active: nextActiveId,
20676
+ ledger: state.ledger
20677
+ };
20678
+ }
20679
+ function replaceSealedIdentity(state, index, nextId) {
20680
+ if (index < 0 || index >= state.sealed.length) fail("UNKNOWN_SHARD", "sealed", "unknown-shard");
20681
+ fail("IDENTITY_SWAP", state.sealed[index].id, `identity-swap:${nextId}`);
20682
+ }
20683
+ function refuseSealedWrite(state, shardId) {
20684
+ if (state.sealed.some((entry) => entry.id === shardId)) fail("SEALED_WRITE", shardId, "sealed-write");
20685
+ }
20686
+ function admitActiveWrite(state, shardId, firstOrNextSuid) {
20687
+ assertSortableUniqueId(firstOrNextSuid);
20688
+ refuseSealedWrite(state, shardId);
20689
+ if (shardId !== state.active) fail("UNKNOWN_SHARD", shardId, "unknown-shard");
20690
+ if (state.sealed.length === 0) return;
20691
+ const previous = state.sealed[state.sealed.length - 1];
20692
+ assertStrictlyBefore(previous.lastSuid, firstOrNextSuid);
20693
+ }
20694
+ function recordLateArrival(state, sealedShardId, suid) {
20695
+ assertSortableUniqueId(suid);
20696
+ const sealed = state.sealed.find((entry) => entry.id === sealedShardId);
20697
+ if (sealed === void 0) fail("UNKNOWN_SHARD", sealedShardId, "unknown-shard");
20698
+ if (compareSortableUniqueId(suid, sealed.lastSuid) > 0) {
20699
+ fail("ORDER_INVARIANT", sealedShardId, "not-late-arrival");
20700
+ }
20701
+ return {
20702
+ ...state,
20703
+ ledger: [...state.ledger, { shardId: sealed.id, suid, reason: "sealed-range" }]
20704
+ };
20705
+ }
20706
+ var SILENT_MERGE_TOKENS = [
20707
+ ["merge", "Ledger", "Into", "Sealed"],
20708
+ ["merge", "OnRead", "Sealed"],
20709
+ ["silent", "Merge", "Ledger"],
20710
+ ["ledger", ".concat(", "sealed"],
20711
+ ["sealed", ".concat(", "ledger"]
20712
+ ];
20713
+ function assertNoSilentLedgerMerge(source) {
20714
+ const lowered = source.toLowerCase();
20715
+ for (const token of SILENT_MERGE_TOKENS) {
20716
+ const needle = token.join("").toLowerCase();
20717
+ if (lowered.includes(needle)) fail("SILENT_MERGE", "ledger", "silent-merge");
20718
+ }
20719
+ }
20720
+ function refuseSilentLedgerMerge() {
20721
+ fail("SILENT_MERGE", "ledger", "silent-merge");
20722
+ }
20723
+ function refuseSafeWindowSeal() {
20724
+ fail("SAFEWINDOW_SEAL", "safe-window", "safewindow-seal");
19646
20725
  }
19647
20726
 
19648
20727
  // src/index.ts
@@ -19652,6 +20731,10 @@ function createRuntimeWorker(options = {}) {
19652
20731
  const storeProvider = options.storeProvider ?? POSTGRES_STORE_PROVIDER;
19653
20732
  return {
19654
20733
  async fetch(request, env, ctx) {
20734
+ const url = new URL(request.url);
20735
+ if (isIncidentMaintenancePath(url.pathname)) {
20736
+ return handleIncidentMaintenance(request, env, options.serviceIdentityProvider ?? envServiceIdentity(env));
20737
+ }
19655
20738
  const serviceIdentity = options.serviceIdentityProvider ?? envServiceIdentity(env);
19656
20739
  const requestIdentityOptions = { allowG11Verification: env.G11_VERIFICATION_ENABLED === "true" };
19657
20740
  let requestServiceId;
@@ -19660,7 +20743,6 @@ function createRuntimeWorker(options = {}) {
19660
20743
  } catch {
19661
20744
  return scopeIdentityMissingResponse();
19662
20745
  }
19663
- const url = new URL(request.url);
19664
20746
  if (url.pathname === "/api/sekiban/serialized/commit") {
19665
20747
  return handleSerializedCommit(request, env, {
19666
20748
  domainDeliveryClass: options.config?.deliveryClass,
@@ -19689,7 +20771,7 @@ function createRuntimeWorker(options = {}) {
19689
20771
  return handleOperatorBootstrap(request, env, storeProvider);
19690
20772
  }
19691
20773
  if (url.pathname === "/internal/downstream/drain" && request.method === "POST") {
19692
- return handleOutboxDrainRequest(request, env);
20774
+ return handleOutboxDrainRequest(request, env, { serviceIdentityProvider: serviceIdentity });
19693
20775
  }
19694
20776
  if (url.pathname === "/internal/projection/lag") {
19695
20777
  return handleProjectionLag(request, env, composition.projectors, storeProvider, serviceIdentity);
@@ -19822,6 +20904,8 @@ export {
19822
20904
  GLOBAL_COMPLETENESS_INTERIM_DISPOSITION,
19823
20905
  GlobalCompletenessReconciler,
19824
20906
  IDLE_EXPERIMENT_SCHEDULE_MS,
20907
+ IncidentLifecycle,
20908
+ IncidentLifecycleError,
19825
20909
  JournalDurableObject,
19826
20910
  MAX_PUBLISHED_SAFE_WINDOW_MS,
19827
20911
  MAX_SERVICE_BINDING_INVOCATIONS_PER_REQUEST,
@@ -19842,17 +20926,21 @@ export {
19842
20926
  SORTABLE_UNIQUE_ID_TICKS_DIGITS,
19843
20927
  ScopeNameError,
19844
20928
  ServiceIdentityMissingError,
20929
+ ShardRotationError,
19845
20930
  SortableUniqueIdError,
19846
20931
  TEST_SERVICE_ID_HEADER,
19847
20932
  TagDurableObject,
19848
20933
  TagStateDurableObject,
19849
20934
  UnsafeWindowMaterializedViewError,
19850
20935
  UnsafeWindowMaterializedViewStore,
20936
+ admitActiveWrite,
19851
20937
  allocateOrderRange,
19852
20938
  assertCanonicalEventType,
19853
20939
  assertCommitSnapshotLogSize,
19854
20940
  assertDotNetTicks,
20941
+ assertNoSilentLedgerMerge,
19855
20942
  assertSortableUniqueId,
20943
+ assertStrictlyBefore,
19856
20944
  beginWorkerInvocationObservation,
19857
20945
  bootstrapDigest,
19858
20946
  buildScopeName,
@@ -19869,6 +20957,7 @@ export {
19869
20957
  createCommitTraceConsoleSink,
19870
20958
  createPostgresBootstrapAdapter,
19871
20959
  createPostgresStoreProvider,
20960
+ createRotationState,
19872
20961
  createRuntimeCommitPort,
19873
20962
  createRuntimeWorker,
19874
20963
  createTraceCorrelationId,
@@ -19893,8 +20982,10 @@ export {
19893
20982
  isScopeServiceId,
19894
20983
  isSortableUniqueId,
19895
20984
  isUuidV7,
20985
+ maxSortableUniqueId,
19896
20986
  nativeTracingFromContext,
19897
20987
  noOpNativeTracing,
20988
+ normalizeIncidentIdentity,
19898
20989
  observeLegacySortableUniqueIdDecision,
19899
20990
  observedIdleGapLowerBoundMs,
19900
20991
  parseBootstrapDump,
@@ -19904,10 +20995,16 @@ export {
19904
20995
  processDownstreamDoorbell,
19905
20996
  readDirectDoorbellConfig,
19906
20997
  readDomainDeliveryClass,
20998
+ recordLateArrival,
20999
+ refuseSafeWindowSeal,
21000
+ refuseSealedWrite,
21001
+ refuseSilentLedgerMerge,
19907
21002
  registeredEventParsers,
21003
+ replaceSealedIdentity,
19908
21004
  requestServiceIdentity,
19909
21005
  requireServiceIdentity,
19910
21006
  resolveDeliveryIdentity,
21007
+ rotateAppend,
19911
21008
  safeWindowCeilingExceeded,
19912
21009
  safeWindowCutoffSuid,
19913
21010
  safeWindowMs,