@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
@@ -926,10 +926,10 @@ var systemOrderClock = Object.freeze({
926
926
  }
927
927
  });
928
928
  var ORDER_SUID_LIMIT = DOTNET_MAX_TICKS + 1n;
929
- function asOrderClockError(error10) {
930
- if (error10 instanceof OrderClockReadError) return error10;
931
- const detail = error10 instanceof Error ? error10.message : "SortableUniqueId allocation failed";
932
- return new OrderClockReadError(detail, { cause: error10 });
929
+ function asOrderClockError(error11) {
930
+ if (error11 instanceof OrderClockReadError) return error11;
931
+ const detail = error11 instanceof Error ? error11.message : "SortableUniqueId allocation failed";
932
+ return new OrderClockReadError(detail, { cause: error11 });
933
933
  }
934
934
  function allocateOrderRange(watermark, count, clockTick, options = {}) {
935
935
  if (!Number.isSafeInteger(count) || count <= 0) {
@@ -958,9 +958,9 @@ function allocateOrderRange(watermark, count, clockTick, options = {}) {
958
958
  watermark: suids.at(-1),
959
959
  suids: Object.freeze(suids)
960
960
  });
961
- } catch (error10) {
962
- if (error10 instanceof SortableUniqueIdError) throw error10;
963
- throw asOrderClockError(error10);
961
+ } catch (error11) {
962
+ if (error11 instanceof SortableUniqueIdError) throw error11;
963
+ throw asOrderClockError(error11);
964
964
  }
965
965
  }
966
966
  function diagnosticAllocatedAt(ticks) {
@@ -978,7 +978,7 @@ function diagnosticAllocatedAt(ticks) {
978
978
  var commit_trace_manifest_default = {
979
979
  schemaVersion: 2,
980
980
  name: "commit-trace-manifest",
981
- description: "Authority for the sdt.commit span manifests. means/19 links to RENDERED-VIEWS.md; it does not duplicate these tables.",
981
+ 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.",
982
982
  remoteInvocationUniverse: [
983
983
  "S16"
984
984
  ],
@@ -3391,9 +3391,9 @@ var commit_trace_manifest_default = {
3391
3391
 
3392
3392
  // src/trace/AttributionRatio.ts
3393
3393
  function failure(code, message) {
3394
- const error10 = new Error(`${code}:${message}`);
3395
- error10.name = "CommitTraceAttributionError";
3396
- throw error10;
3394
+ const error11 = new Error(`${code}:${message}`);
3395
+ error11.name = "CommitTraceAttributionError";
3396
+ throw error11;
3397
3397
  }
3398
3398
  function clip(interval, root) {
3399
3399
  const start = Math.max(interval[0], root[0]);
@@ -3706,8 +3706,8 @@ var CommitTrace = class {
3706
3706
  unattributed,
3707
3707
  attributionGatePassed: unattributed.unattributedRatio <= 0.05
3708
3708
  });
3709
- } catch (error10) {
3710
- this.noteObservationFailure(error10);
3709
+ } catch (error11) {
3710
+ this.noteObservationFailure(error11);
3711
3711
  return Object.freeze({
3712
3712
  ...base,
3713
3713
  runtimeVerification: this.observationVerification()
@@ -3774,9 +3774,9 @@ var CommitTrace = class {
3774
3774
  throw new Error(`Commit trace root ${rowId} is not active`);
3775
3775
  }
3776
3776
  attributes = this.attributesFor(row, options);
3777
- } catch (error10) {
3778
- if (!this.isFailOpen()) throw error10;
3779
- this.noteObservationFailure(error10);
3777
+ } catch (error11) {
3778
+ if (!this.isFailOpen()) throw error11;
3779
+ this.noteObservationFailure(error11);
3780
3780
  return callback(disabledChild());
3781
3781
  }
3782
3782
  const execute = async (native2) => {
@@ -3902,8 +3902,8 @@ var CommitTrace = class {
3902
3902
  for (const [key, value] of Object.entries(attributes)) {
3903
3903
  try {
3904
3904
  native.setAttribute(key, value);
3905
- } catch (error10) {
3906
- this.noteObservationFailure(error10);
3905
+ } catch (error11) {
3906
+ this.noteObservationFailure(error11);
3907
3907
  }
3908
3908
  }
3909
3909
  }
@@ -3920,8 +3920,8 @@ var CommitTrace = class {
3920
3920
  now() {
3921
3921
  try {
3922
3922
  return this.clock().now();
3923
- } catch (error10) {
3924
- this.noteObservationFailure(error10);
3923
+ } catch (error11) {
3924
+ this.noteObservationFailure(error11);
3925
3925
  return Date.now();
3926
3926
  }
3927
3927
  }
@@ -3929,8 +3929,8 @@ var CommitTrace = class {
3929
3929
  let beforeVerification;
3930
3930
  try {
3931
3931
  beforeVerification = this.snapshot();
3932
- } catch (error10) {
3933
- this.noteObservationFailure(error10);
3932
+ } catch (error11) {
3933
+ this.noteObservationFailure(error11);
3934
3934
  return;
3935
3935
  }
3936
3936
  if (this.options.runtimeVerifier !== void 0) {
@@ -3941,15 +3941,15 @@ var CommitTrace = class {
3941
3941
  this.options.runtimeVerifier.verify(beforeVerification);
3942
3942
  this.runtimeVerification = Object.freeze({ passed: true });
3943
3943
  }
3944
- } catch (error10) {
3945
- const code = typeof error10 === "object" && error10 !== null && "code" in error10 && typeof error10.code === "string" ? error10.code : "runtime-verifier-error";
3944
+ } catch (error11) {
3945
+ const code = typeof error11 === "object" && error11 !== null && "code" in error11 && typeof error11.code === "string" ? error11.code : "runtime-verifier-error";
3946
3946
  this.runtimeVerification = Object.freeze({ passed: false, code });
3947
3947
  }
3948
3948
  }
3949
3949
  try {
3950
3950
  this.options.sink?.record(this.snapshot());
3951
- } catch (error10) {
3952
- this.noteObservationFailure(error10);
3951
+ } catch (error11) {
3952
+ this.noteObservationFailure(error11);
3953
3953
  }
3954
3954
  }
3955
3955
  /**
@@ -3961,8 +3961,8 @@ var CommitTrace = class {
3961
3961
  async scheduleDetachedObservation() {
3962
3962
  try {
3963
3963
  await this.options.scheduleDetachedObservation?.();
3964
- } catch (error10) {
3965
- this.noteObservationFailure(error10);
3964
+ } catch (error11) {
3965
+ this.noteObservationFailure(error11);
3966
3966
  }
3967
3967
  }
3968
3968
  isFailOpen() {
@@ -3971,9 +3971,9 @@ var CommitTrace = class {
3971
3971
  observationVerification() {
3972
3972
  return Object.freeze({ passed: false, code: this.observationFailureCode ?? "trace-observation-error" });
3973
3973
  }
3974
- noteObservationFailure(error10) {
3974
+ noteObservationFailure(error11) {
3975
3975
  if (this.observationFailureCode !== void 0) return;
3976
- this.observationFailureCode = typeof error10 === "object" && error10 !== null && "code" in error10 && typeof error10.code === "string" ? error10.code : "trace-observation-error";
3976
+ this.observationFailureCode = typeof error11 === "object" && error11 !== null && "code" in error11 && typeof error11.code === "string" ? error11.code : "trace-observation-error";
3977
3977
  this.runtimeVerification = this.observationVerification();
3978
3978
  }
3979
3979
  /**
@@ -3994,9 +3994,9 @@ var CommitTrace = class {
3994
3994
  return callback(void 0);
3995
3995
  }
3996
3996
  return await result2;
3997
- } catch (error10) {
3998
- if (callbackStarted) throw error10;
3999
- this.noteObservationFailure(error10);
3997
+ } catch (error11) {
3998
+ if (callbackStarted) throw error11;
3999
+ this.noteObservationFailure(error11);
4000
4000
  return callback(void 0);
4001
4001
  }
4002
4002
  }
@@ -4085,8 +4085,8 @@ async function enterNativeSpanFailOpen(nativeTracing, name, callback) {
4085
4085
  const result2 = nativeTracing.enterSpan(name, wrapped);
4086
4086
  if (!callbackStarted) return callback(void 0);
4087
4087
  return await result2;
4088
- } catch (error10) {
4089
- if (callbackStarted) throw error10;
4088
+ } catch (error11) {
4089
+ if (callbackStarted) throw error11;
4090
4090
  return callback(void 0);
4091
4091
  }
4092
4092
  }
@@ -4118,9 +4118,9 @@ async function enterNativeCommitSpan(nativeTracing, name, input, callback) {
4118
4118
  if (response3 !== void 0 && input.face !== "reconcile-root") setNativeAttribute(span, "http.status", response3.status);
4119
4119
  }
4120
4120
  return result2;
4121
- } catch (error10) {
4121
+ } catch (error11) {
4122
4122
  setNativeAttribute(span, "outcome", "exception");
4123
- throw error10;
4123
+ throw error11;
4124
4124
  }
4125
4125
  });
4126
4126
  }
@@ -4159,9 +4159,9 @@ async function enterNativeActorHandleSpan(nativeTracing, input, resolveIdentity,
4159
4159
  if (response3 !== void 0) setNativeAttribute(span, "http.status", response3.status);
4160
4160
  }
4161
4161
  return result2;
4162
- } catch (error10) {
4162
+ } catch (error11) {
4163
4163
  if (identity2 !== void 0) setNativeAttribute(span, "outcome", "exception");
4164
- throw error10;
4164
+ throw error11;
4165
4165
  } finally {
4166
4166
  input.observation?.finish();
4167
4167
  }
@@ -4289,6 +4289,8 @@ var ATTEMPT_KEY_PREFIX2 = "attempt:";
4289
4289
  var ROLLBACK_WARNING_WINDOW_MS = 1000n;
4290
4290
  var AllocationTransactionFault = class extends Error {
4291
4291
  };
4292
+ var ImportSeedRequiredError = class extends Error {
4293
+ };
4292
4294
  function json(body, status = 200) {
4293
4295
  return new Response(JSON.stringify(body), {
4294
4296
  status,
@@ -4328,7 +4330,17 @@ function seedFrom(value) {
4328
4330
  } catch {
4329
4331
  return { error: "highWatermark must be an allocator SUID" };
4330
4332
  }
4331
- return { value: { importId: value.importId, leaseEpoch: value.leaseEpoch, highWatermark: value.highWatermark } };
4333
+ let storeMaximum;
4334
+ if (value.storeMaximum !== void 0) {
4335
+ if (!isNonEmptyString2(value.storeMaximum)) return { error: "storeMaximum must be an allocator SUID" };
4336
+ try {
4337
+ decodeSuid(value.storeMaximum);
4338
+ } catch {
4339
+ return { error: "storeMaximum must be an allocator SUID" };
4340
+ }
4341
+ storeMaximum = value.storeMaximum;
4342
+ }
4343
+ return { value: { importId: value.importId, leaseEpoch: value.leaseEpoch, highWatermark: value.highWatermark, ...storeMaximum !== void 0 ? { storeMaximum } : {} } };
4332
4344
  }
4333
4345
  function newAllocatorLineageId() {
4334
4346
  return crypto.randomUUID();
@@ -4383,7 +4395,8 @@ function allocateFrom(value) {
4383
4395
  faultInjection,
4384
4396
  ...serviceId !== void 0 ? { serviceId } : {},
4385
4397
  ...bootstrapCommandId !== void 0 ? { bootstrapCommandId } : {},
4386
- ...bootstrapEpoch !== void 0 ? { bootstrapEpoch } : {}
4398
+ ...bootstrapEpoch !== void 0 ? { bootstrapEpoch } : {},
4399
+ ...value.requiresImportSeed === true ? { requiresImportSeed: true } : {}
4387
4400
  }
4388
4401
  };
4389
4402
  }
@@ -4768,11 +4781,12 @@ var AllocatorDurableObject = class {
4768
4781
  };
4769
4782
  }
4770
4783
  const state = persistedState === void 0 ? currentState(lineage) : { ...persistedState, allocatorLineageId: lineage, schemaVersion: 5, bootstrapSeed: persistedState.bootstrapSeed ?? null, lastRollbackWarningFingerprint: persistedState.lastRollbackWarningFingerprint ?? null };
4784
+ if (input.requiresImportSeed === true && state.bootstrapSeed === null) throw new ImportSeedRequiredError();
4771
4785
  let clockTick;
4772
4786
  try {
4773
4787
  clockTick = this.orderClock.tick();
4774
- } catch (error10) {
4775
- throw error10 instanceof OrderClockReadError ? error10 : new OrderClockReadError("Order clock failed before allocation write", { cause: error10 });
4788
+ } catch (error11) {
4789
+ throw error11 instanceof OrderClockReadError ? error11 : new OrderClockReadError("Order clock failed before allocation write", { cause: error11 });
4776
4790
  }
4777
4791
  const range = allocateOrderRange(state.allocatedWatermark, input.candidates.length, clockTick);
4778
4792
  const rollback = range.observedTicks !== null && range.physicalTicks < range.observedTicks;
@@ -4846,6 +4860,9 @@ var AllocatorDurableObject = class {
4846
4860
  }
4847
4861
  return json(result2.vector, result2.created ? 201 : 200);
4848
4862
  } catch (failure3) {
4863
+ if (failure3 instanceof ImportSeedRequiredError) {
4864
+ return error(409, "allocator_seed_required", "commit before import seed");
4865
+ }
4849
4866
  if (failure3 instanceof AllocationTransactionFault) {
4850
4867
  return error(
4851
4868
  503,
@@ -4886,7 +4903,10 @@ var AllocatorDurableObject = class {
4886
4903
  return { status: 409, body: { code: "allocator_seed_rejected", error: "allocator already seeded" } };
4887
4904
  }
4888
4905
  if (state.allocatedWatermark !== null) return { status: 409, body: { code: "allocator_seed_rejected", error: "allocator already allocating" } };
4889
- const updated = { ...state, allocatedWatermark: input.highWatermark, bootstrapSeed: input };
4906
+ if (input.storeMaximum !== void 0 && input.highWatermark < input.storeMaximum) {
4907
+ return { status: 409, body: { code: "allocator_seed_below_store_max", error: "seed below store maximum" } };
4908
+ }
4909
+ const updated = { ...state, allocatedWatermark: input.highWatermark, bootstrapSeed: { importId: input.importId, leaseEpoch: input.leaseEpoch, highWatermark: input.highWatermark } };
4890
4910
  await txn.put(STATE_KEY, updated);
4891
4911
  return { status: 201, body: updated };
4892
4912
  });
@@ -4911,7 +4931,7 @@ var isPlainRecord = (value) => {
4911
4931
  return prototype === Object.prototype || prototype === null;
4912
4932
  };
4913
4933
  function assertJsonValue(value, boundary = "value") {
4914
- const active = /* @__PURE__ */ new WeakSet();
4934
+ const active2 = /* @__PURE__ */ new WeakSet();
4915
4935
  const visit = (candidate, path) => {
4916
4936
  if (candidate === null || typeof candidate === "string" || typeof candidate === "boolean") {
4917
4937
  return candidate;
@@ -4923,10 +4943,10 @@ function assertJsonValue(value, boundary = "value") {
4923
4943
  if (typeof candidate !== "object") {
4924
4944
  throw new JsonValidationError(`Value at ${path} is not JSON serializable`, boundary, path);
4925
4945
  }
4926
- if (active.has(candidate)) {
4946
+ if (active2.has(candidate)) {
4927
4947
  throw new JsonValidationError(`Cyclic JSON value at ${path}`, boundary, path);
4928
4948
  }
4929
- active.add(candidate);
4949
+ active2.add(candidate);
4930
4950
  try {
4931
4951
  if (Array.isArray(candidate)) {
4932
4952
  return candidate.map((item, index) => visit(item, `${path}[${index}]`));
@@ -4940,7 +4960,7 @@ function assertJsonValue(value, boundary = "value") {
4940
4960
  }
4941
4961
  return result2;
4942
4962
  } finally {
4943
- active.delete(candidate);
4963
+ active2.delete(candidate);
4944
4964
  }
4945
4965
  };
4946
4966
  return visit(value, "$");
@@ -5035,16 +5055,16 @@ function createUuidV7(nowMs = Date.now()) {
5035
5055
  if (typeof globalThis.crypto?.getRandomValues !== "function") {
5036
5056
  throw new Error("crypto.getRandomValues is required for UUIDv7");
5037
5057
  }
5038
- const bytes = new Uint8Array(16);
5039
- globalThis.crypto.getRandomValues(bytes);
5058
+ const bytes2 = new Uint8Array(16);
5059
+ globalThis.crypto.getRandomValues(bytes2);
5040
5060
  let time = BigInt(nowMs);
5041
5061
  for (let index = 5; index >= 0; index -= 1) {
5042
- bytes[index] = Number(time & 0xffn);
5062
+ bytes2[index] = Number(time & 0xffn);
5043
5063
  time >>= 8n;
5044
5064
  }
5045
- bytes[6] = bytes[6] & 15 | 112;
5046
- bytes[8] = bytes[8] & 63 | 128;
5047
- const hex = [...bytes].map((value) => value.toString(16).padStart(2, "0")).join("");
5065
+ bytes2[6] = bytes2[6] & 15 | 112;
5066
+ bytes2[8] = bytes2[8] & 63 | 128;
5067
+ const hex = [...bytes2].map((value) => value.toString(16).padStart(2, "0")).join("");
5048
5068
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
5049
5069
  }
5050
5070
  function isRfc4122Uuid(value) {
@@ -5160,7 +5180,7 @@ var epoch = (value) => typeof value === "number" && Number.isSafeInteger(value)
5160
5180
  var response = (body, status = 200) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json; charset=utf-8" } });
5161
5181
  var reject = (code, message, status = 409) => response({ code, error: message }, status);
5162
5182
  function empty(serviceId) {
5163
- 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 };
5183
+ 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 };
5164
5184
  }
5165
5185
  function expired(control) {
5166
5186
  return control.leaseUntil !== null && control.leaseUntil <= Date.now();
@@ -5171,12 +5191,22 @@ function commands(control) {
5171
5191
  function released(control) {
5172
5192
  return { ...control.releasedCommands ?? {} };
5173
5193
  }
5194
+ function permits(control) {
5195
+ return { ...control.writePermits ?? {} };
5196
+ }
5174
5197
  function fault(body, point) {
5175
5198
  return object(body) && body.faultAt === point;
5176
5199
  }
5177
5200
  function encodedBytes(value) {
5178
5201
  return new TextEncoder().encode(JSON.stringify(value)).byteLength;
5179
5202
  }
5203
+ async function readBody(request) {
5204
+ try {
5205
+ return await request.json();
5206
+ } catch {
5207
+ return void 0;
5208
+ }
5209
+ }
5180
5210
  var BootstrapCoordinatorDurableObject = class {
5181
5211
  constructor(ctx, env, nativeTracing = noOpNativeTracing) {
5182
5212
  this.ctx = ctx;
@@ -5198,6 +5228,8 @@ var BootstrapCoordinatorDurableObject = class {
5198
5228
  if (request.method === "POST" && url.pathname === "/command/admit") return this.traceCommand(request, serviceId, activation2, observation, "admit");
5199
5229
  if (request.method === "POST" && url.pathname === "/command/finalize") return this.traceCommand(request, serviceId, activation2, observation, "finalize");
5200
5230
  if (request.method === "POST" && url.pathname === "/command/release") return this.traceCommand(request, serviceId, activation2, observation, "release");
5231
+ if (request.method === "POST" && url.pathname === "/command/permit") return this.permit(serviceId, await readBody(request));
5232
+ if (request.method === "POST" && url.pathname === "/command/permit-release") return this.permitRelease(serviceId, await readBody(request));
5201
5233
  let body;
5202
5234
  try {
5203
5235
  body = await request.json();
@@ -5254,6 +5286,7 @@ var BootstrapCoordinatorDurableObject = class {
5254
5286
  const control = await txn.get(CONTROL) ?? empty(serviceId);
5255
5287
  if (control.status === "READY") return { error: "bootstrap_ready_permanent" };
5256
5288
  if (control.status !== "EMPTY") return control.importId === importId && control.digest === dump.manifest.contentDigest ? { control } : { error: "bootstrap_plan_conflict" };
5289
+ if (Object.keys(permits(control)).length !== 0) return { error: "bootstrap_write_permit_active" };
5257
5290
  if (control.normalInFlight !== 0 || Object.keys(commands(control)).length !== 0) return { error: "bootstrap_normal_command_in_flight" };
5258
5291
  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 };
5259
5292
  await txn.put(CONTROL, next);
@@ -5266,17 +5299,17 @@ var BootstrapCoordinatorDurableObject = class {
5266
5299
  chunks(events) {
5267
5300
  const chunks = [];
5268
5301
  let current = [];
5269
- let bytes = 0;
5302
+ let bytes2 = 0;
5270
5303
  for (const event of events) {
5271
5304
  const eventBytes = encodedBytes(event);
5272
5305
  if (eventBytes > MAX_CHUNK_BYTES) throw new Error("bootstrap event exceeds encoded chunk bound");
5273
- if (current.length === MAX_CHUNK_EVENTS || bytes + eventBytes > MAX_CHUNK_BYTES) {
5306
+ if (current.length === MAX_CHUNK_EVENTS || bytes2 + eventBytes > MAX_CHUNK_BYTES) {
5274
5307
  chunks.push(current);
5275
5308
  current = [];
5276
- bytes = 0;
5309
+ bytes2 = 0;
5277
5310
  }
5278
5311
  current.push(event);
5279
- bytes += eventBytes;
5312
+ bytes2 += eventBytes;
5280
5313
  }
5281
5314
  if (current.length > 0) chunks.push(current);
5282
5315
  return chunks;
@@ -5422,6 +5455,45 @@ var BootstrapCoordinatorDurableObject = class {
5422
5455
  const control = await this.control(serviceId);
5423
5456
  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`);
5424
5457
  }
5458
+ async permit(serviceId, body) {
5459
+ if (!object(body) || !string(body.commandId) || !string(body.digest)) return reject("bootstrap_permit_invalid", "commandId and digest are required", 400);
5460
+ const commandId = body.commandId;
5461
+ const digest2 = body.digest;
5462
+ const result2 = await this.ctx.storage.transaction(async (txn) => {
5463
+ const control = await txn.get(CONTROL) ?? empty(serviceId);
5464
+ const active2 = permits(control);
5465
+ if (active2[commandId] !== void 0) {
5466
+ return active2[commandId] === digest2 ? { control } : { digestMismatch: true };
5467
+ }
5468
+ if (control.status !== "EMPTY" && control.status !== "READY") return { rejected: true };
5469
+ const updated = { ...control, writePermits: { ...active2, [commandId]: digest2 } };
5470
+ await txn.put(CONTROL, updated);
5471
+ return { control: updated };
5472
+ });
5473
+ if ("digestMismatch" in result2) return reject("bootstrap_permit_digest_mismatch", "bootstrap permit digest does not match the held permit");
5474
+ if ("rejected" in result2) return reject("bootstrap_command_rejected", "bootstrap epoch rejects normal durable mutation");
5475
+ return response({ leaseEpoch: result2.control.leaseEpoch, admitted: true });
5476
+ }
5477
+ async permitRelease(serviceId, body) {
5478
+ if (!object(body) || !string(body.commandId)) return reject("bootstrap_permit_invalid", "commandId is required", 400);
5479
+ const commandId = body.commandId;
5480
+ const digest2 = string(body.digest) ? body.digest : void 0;
5481
+ const result2 = await this.ctx.storage.transaction(async (txn) => {
5482
+ const control = await txn.get(CONTROL) ?? empty(serviceId);
5483
+ const active2 = permits(control);
5484
+ if (active2[commandId] !== void 0 && digest2 !== void 0 && active2[commandId] !== digest2) {
5485
+ return { digestMismatch: true };
5486
+ }
5487
+ if (active2[commandId] === void 0) return { control };
5488
+ const next = { ...active2 };
5489
+ delete next[commandId];
5490
+ const updated = { ...control, writePermits: next };
5491
+ await txn.put(CONTROL, updated);
5492
+ return { control: updated };
5493
+ });
5494
+ if ("digestMismatch" in result2) return reject("bootstrap_permit_digest_mismatch", "bootstrap permit digest does not match the held permit");
5495
+ return response({ leaseEpoch: result2.control.leaseEpoch, admitted: true });
5496
+ }
5425
5497
  async command(serviceId, body, action, observation) {
5426
5498
  if (!object(body) || !string(body.commandId)) return reject("bootstrap_command_invalid", "commandId is required", 400);
5427
5499
  const commandId = body.commandId;
@@ -5487,13 +5559,13 @@ function byteCompare(left, right) {
5487
5559
  }
5488
5560
  function concat(parts) {
5489
5561
  const length = parts.reduce((total, part) => total + part.byteLength, 0);
5490
- const bytes = new Uint8Array(length);
5562
+ const bytes2 = new Uint8Array(length);
5491
5563
  let offset = 0;
5492
5564
  for (const part of parts) {
5493
- bytes.set(part, offset);
5565
+ bytes2.set(part, offset);
5494
5566
  offset += part.byteLength;
5495
5567
  }
5496
- return bytes;
5568
+ return bytes2;
5497
5569
  }
5498
5570
  function lengthPrefix(length) {
5499
5571
  if (!Number.isSafeInteger(length) || length < 0 || length > 4294967295) {
@@ -5522,8 +5594,8 @@ function requiredUtf8(input, name) {
5522
5594
  function tagSetBytes(tags) {
5523
5595
  const canonical2 = canonicalDeclaredTagSet(tags);
5524
5596
  return concat(canonical2.map((tag) => {
5525
- const bytes = utf8(tag);
5526
- return concat([lengthPrefix(bytes.byteLength), bytes]);
5597
+ const bytes2 = utf8(tag);
5598
+ return concat([lengthPrefix(bytes2.byteLength), bytes2]);
5527
5599
  }));
5528
5600
  }
5529
5601
  function canonicalDeclaredTagSet(tags) {
@@ -5593,16 +5665,16 @@ function eventDigestBytes(input) {
5593
5665
  ]);
5594
5666
  }
5595
5667
  async function eventDigestHex(input) {
5596
- const bytes = eventDigestBytes(input);
5597
- const source = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
5598
- const digest = await crypto.subtle.digest("SHA-256", source);
5599
- return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
5668
+ const bytes2 = eventDigestBytes(input);
5669
+ const source = bytes2.buffer.slice(bytes2.byteOffset, bytes2.byteOffset + bytes2.byteLength);
5670
+ const digest2 = await crypto.subtle.digest("SHA-256", source);
5671
+ return [...new Uint8Array(digest2)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
5600
5672
  }
5601
5673
 
5602
5674
  // src/bootstrap/BootstrapStoreAdapter.ts
5603
- function arrayBufferBase64(bytes) {
5675
+ function arrayBufferBase64(bytes2) {
5604
5676
  let binary = "";
5605
- for (const byte of bytes) binary += String.fromCharCode(byte);
5677
+ for (const byte of bytes2) binary += String.fromCharCode(byte);
5606
5678
  return btoa(binary);
5607
5679
  }
5608
5680
  var BootstrapIdentityConflictError = class extends Error {
@@ -6713,6 +6785,22 @@ var COMMIT_TEST_FAULTS = [
6713
6785
  var INITIAL_OWNER_EPOCH = 0;
6714
6786
  var MAX_WRITE_ATTEMPTS = 2;
6715
6787
  var OUTCOME_UNDETERMINED_ERROR = "Commit outcome is undetermined; reread tag heads and event/query state before retrying because blind retry may create duplicate events.";
6788
+ function commitPermitDigest(allTags, candidates) {
6789
+ const normalized = JSON.stringify({
6790
+ tags: [...allTags].sort(),
6791
+ events: candidates.map((candidate) => ({
6792
+ eventId: candidate.eventId,
6793
+ payload: candidate.payload,
6794
+ tags: [...candidate.tags].sort()
6795
+ })).sort((left, right) => left.eventId < right.eventId ? -1 : left.eventId > right.eventId ? 1 : 0)
6796
+ });
6797
+ let hash = 2166136261;
6798
+ for (let index = 0; index < normalized.length; index += 1) {
6799
+ hash ^= normalized.charCodeAt(index);
6800
+ hash = Math.imul(hash, 16777619) >>> 0;
6801
+ }
6802
+ return `fnv1a32:${hash.toString(16).padStart(8, "0")}`;
6803
+ }
6716
6804
  var GLOBAL_ADMISSION_HEADER = "x-sdt-global-admission";
6717
6805
  var runtimeCommitTraceVerifier = {
6718
6806
  verify(snapshot) {
@@ -6766,19 +6854,19 @@ var CommitPayloadAdmissionError = class extends Error {
6766
6854
  code;
6767
6855
  };
6768
6856
  function decodeBase64Utf8Json(value) {
6769
- let bytes;
6857
+ let bytes2;
6770
6858
  try {
6771
6859
  const binary = atob(value);
6772
- bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));
6860
+ bytes2 = Uint8Array.from(binary, (character) => character.charCodeAt(0));
6773
6861
  } catch {
6774
6862
  throw new CommitPayloadAdmissionError("invalid_payload_utf8", "Payload base64 could not be decoded");
6775
6863
  }
6776
- if (bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191) {
6864
+ if (bytes2[0] === 239 && bytes2[1] === 187 && bytes2[2] === 191) {
6777
6865
  throw new CommitPayloadAdmissionError("invalid_payload_utf8", "Payload must not start with a UTF-8 BOM");
6778
6866
  }
6779
6867
  let text;
6780
6868
  try {
6781
- text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
6869
+ text = new TextDecoder("utf-8", { fatal: true }).decode(bytes2);
6782
6870
  } catch {
6783
6871
  throw new CommitPayloadAdmissionError("invalid_payload_utf8", "Payload must be valid UTF-8 JSON text");
6784
6872
  }
@@ -6824,9 +6912,9 @@ function assertExactMemberPaths(actual, registered, path = "$") {
6824
6912
  }
6825
6913
  }
6826
6914
  function encodeBase64Utf8(value) {
6827
- const bytes = new TextEncoder().encode(value);
6915
+ const bytes2 = new TextEncoder().encode(value);
6828
6916
  let binary = "";
6829
- for (const byte of bytes) binary += String.fromCharCode(byte);
6917
+ for (const byte of bytes2) binary += String.fromCharCode(byte);
6830
6918
  return btoa(binary);
6831
6919
  }
6832
6920
  function faultFromRequest(request) {
@@ -7085,25 +7173,43 @@ var CommitWorker = class {
7085
7173
  return responseWithAttempt(error3(409, "bootstrap_command_rejected", "Bootstrap admission could not be released"), attemptId, fault2 !== void 0);
7086
7174
  }
7087
7175
  await this.retiredJournalMilestone("S04", traceState?.scope);
7176
+ const permitDigest = commitPermitDigest(input.allTags, candidates);
7177
+ let permitHeld = false;
7178
+ const releasePermit = async () => {
7179
+ if (!permitHeld) return;
7180
+ permitHeld = false;
7181
+ await this.bootstrapPermitRelease(attemptId, permitDigest);
7182
+ };
7183
+ const permit = await this.bootstrapPermitAcquire(attemptId, permitDigest);
7184
+ if (!permit.ok) {
7185
+ if (permit.code === "bootstrap_permit_digest_mismatch") {
7186
+ return responseWithAttempt(error3(409, "bootstrap_permit_digest_mismatch", "Bootstrap write permit digest does not match"), attemptId, fault2 !== void 0);
7187
+ }
7188
+ return responseWithAttempt(error3(409, "bootstrap_command_rejected", "Bootstrap is importing; commit is unavailable"), attemptId, fault2 !== void 0);
7189
+ }
7190
+ permitHeld = this.env.BOOTSTRAP !== void 0;
7088
7191
  const reservations = await this.acquireReservations(input, attemptId, fault2, traceState?.scope);
7089
7192
  await this.retiredJournalMilestone("S05a", traceState?.scope, 0);
7090
7193
  if (reservations.failure !== void 0) {
7091
- return this.finishReservationFailure(
7194
+ const failure3 = await this.finishReservationFailure(
7092
7195
  [...reservations.successes.keys()],
7093
7196
  attemptId,
7094
7197
  reservations.failure,
7095
7198
  fault2,
7096
7199
  traceState?.scope
7097
7200
  );
7201
+ if (failure3.resolved) await releasePermit();
7202
+ return failure3.response;
7098
7203
  }
7099
7204
  if (fault2 === "after-reservations-before-allocation") {
7100
- await this.cancelReservations([...reservations.successes.keys()], attemptId, fault2, traceState?.scope);
7205
+ const cleanup = await this.cancelReservations([...reservations.successes.keys()], attemptId, fault2, traceState?.scope);
7206
+ if (cleanup.failedTags.length === 0) await releasePermit();
7101
7207
  return this.noApplicationOutcome(attemptId, true);
7102
7208
  }
7103
7209
  await this.hooks.beforeBootstrapAllocation?.();
7104
7210
  const allocation = await this.allocate(candidates, attemptId, fault2, bootstrapEpoch, traceState?.scope);
7105
7211
  if (allocation === void 0) {
7106
- return this.finishReservationFailure(
7212
+ const failure3 = await this.finishReservationFailure(
7107
7213
  [...reservations.successes.keys()],
7108
7214
  attemptId,
7109
7215
  {
@@ -7114,10 +7220,13 @@ var CommitWorker = class {
7114
7220
  fault2,
7115
7221
  traceState?.scope
7116
7222
  );
7223
+ if (failure3.resolved) await releasePermit();
7224
+ return failure3.response;
7117
7225
  }
7118
7226
  const allocatedCandidates = this.withAllocatedSuids(candidates, allocation);
7119
7227
  if (allocatedCandidates === void 0) {
7120
- await this.cancelReservations([...reservations.successes.keys()], attemptId, fault2, traceState?.scope);
7228
+ const cleanup = await this.cancelReservations([...reservations.successes.keys()], attemptId, fault2, traceState?.scope);
7229
+ if (cleanup.failedTags.length === 0) await releasePermit();
7121
7230
  return this.noApplicationOutcome(attemptId, fault2 !== void 0);
7122
7231
  }
7123
7232
  for (const candidate of allocatedCandidates) {
@@ -7132,15 +7241,18 @@ var CommitWorker = class {
7132
7241
  }
7133
7242
  await this.retiredJournalMilestone("S05b", traceState?.scope, 1);
7134
7243
  if (fault2 === "journal-cas-after-allocator") {
7135
- await this.cancelReservations(input.allTags, attemptId, fault2, traceState?.scope);
7244
+ const cleanup = await this.cancelReservations(input.allTags, attemptId, fault2, traceState?.scope);
7245
+ if (cleanup.failedTags.length === 0) await releasePermit();
7136
7246
  return this.noApplicationOutcome(attemptId, true);
7137
7247
  }
7138
7248
  await this.retiredJournalMilestone("S05c", traceState?.scope, 2);
7139
7249
  await this.hooks.beforeBootstrapFinalization?.();
7140
7250
  if (await this.bootstrapCommand("finalize", attemptId, bootstrapEpoch, traceState?.scope, "S10") === void 0) {
7141
- await this.cancelReservations(input.allTags, attemptId, fault2, traceState?.scope);
7251
+ const cleanup = await this.cancelReservations(input.allTags, attemptId, fault2, traceState?.scope);
7252
+ if (cleanup.failedTags.length === 0) await releasePermit();
7142
7253
  return responseWithAttempt(error3(409, "bootstrap_command_rejected", "Bootstrap fencing epoch changed before commit write"), attemptId, fault2 !== void 0);
7143
7254
  }
7255
+ await this.hooks.beforeAuthoritativeAppend?.();
7144
7256
  const writes = await this.appendAllTags(
7145
7257
  input,
7146
7258
  allocatedCandidates,
@@ -7156,6 +7268,7 @@ var CommitWorker = class {
7156
7268
  return this.noApplicationOutcome(attemptId, true);
7157
7269
  }
7158
7270
  if (writes.committedTags.size === 0 && writes.registrationUnavailableTags.length === writes.pendingTags.length) {
7271
+ await releasePermit();
7159
7272
  return responseWithAttempt(
7160
7273
  error3(
7161
7274
  503,
@@ -7167,20 +7280,25 @@ var CommitWorker = class {
7167
7280
  fault2 !== void 0
7168
7281
  );
7169
7282
  }
7283
+ await releasePermit();
7170
7284
  return this.partialWriteOutcome(input, allocatedCandidates, writes, attemptId, fault2 !== void 0);
7171
7285
  }
7286
+ await this.hooks.afterAppendBeforeResponse?.();
7172
7287
  await this.retiredJournalMilestone("S05d", traceState?.scope, 3);
7173
7288
  if (fault2 === "sealing-after-cas") {
7289
+ await releasePermit();
7174
7290
  return this.noApplicationOutcome(attemptId, true);
7175
7291
  }
7176
7292
  try {
7177
- const success = await this.successResponse(input, allocatedCandidates, attemptId, startedAt, fault2, traceState?.scope);
7293
+ const success = await this.successResponse(input, allocatedCandidates, attemptId, startedAt, fault2, traceState?.scope, writes);
7294
+ await releasePermit();
7178
7295
  return responseWithAttempt(
7179
7296
  withGlobalAdmission(json4(success, 200), writes.globalAdmission),
7180
7297
  attemptId,
7181
7298
  fault2 !== void 0
7182
7299
  );
7183
7300
  } catch {
7301
+ await releasePermit();
7184
7302
  return responseWithAttempt(
7185
7303
  error3(500, "internal_error", "Committed records could not be read while preparing the response"),
7186
7304
  attemptId,
@@ -7227,6 +7345,51 @@ var CommitWorker = class {
7227
7345
  const result2 = traceScope === void 0 || rowId === void 0 ? await invoke() : await traceScope.span(rowId, {}, invoke);
7228
7346
  return result2.leaseEpoch;
7229
7347
  }
7348
+ /**
7349
+ * SDT-G36 bootstrap write permit. Deliberately untraced: it must not add
7350
+ * `sdt.commit/v2` rows or new trace identities. Only a bootstrap barrier,
7351
+ * never commit-outcome authority. No JOURNAL, no alarm, no lease expiry.
7352
+ */
7353
+ bootstrapStub() {
7354
+ if (this.env.BOOTSTRAP === void 0) return void 0;
7355
+ return this.env.BOOTSTRAP.get(scopeIdFor(this.env.BOOTSTRAP, {
7356
+ serviceId: this.serviceId,
7357
+ doClass: "bootstrap",
7358
+ identity: "coordinator"
7359
+ }));
7360
+ }
7361
+ async bootstrapPermitAcquire(commandId, digest2) {
7362
+ const stub = this.bootstrapStub();
7363
+ if (stub === void 0) return { ok: true };
7364
+ try {
7365
+ const url = new URL(`https://commit-worker.internal/command/permit`);
7366
+ url.searchParams.set("__serviceId", this.serviceId);
7367
+ const response3 = await stub.fetch(new Request(url, {
7368
+ method: "POST",
7369
+ headers: { "content-type": "application/json" },
7370
+ body: JSON.stringify({ commandId, digest: digest2 })
7371
+ }));
7372
+ if (response3.ok) return { ok: true };
7373
+ const body = await response3.clone().json().catch(() => void 0);
7374
+ return { ok: false, code: typeof body?.code === "string" ? body.code : void 0 };
7375
+ } catch {
7376
+ return { ok: false };
7377
+ }
7378
+ }
7379
+ async bootstrapPermitRelease(commandId, digest2) {
7380
+ const stub = this.bootstrapStub();
7381
+ if (stub === void 0) return;
7382
+ try {
7383
+ const url = new URL(`https://commit-worker.internal/command/permit-release`);
7384
+ url.searchParams.set("__serviceId", this.serviceId);
7385
+ await stub.fetch(new Request(url, {
7386
+ method: "POST",
7387
+ headers: { "content-type": "application/json" },
7388
+ body: JSON.stringify({ commandId, digest: digest2 })
7389
+ }));
7390
+ } catch {
7391
+ }
7392
+ }
7230
7393
  async postJson(stub, path, body, traceScope, rowId, traceOptions = {}) {
7231
7394
  const invoke = async () => {
7232
7395
  const response3 = await stub.fetch(
@@ -7372,6 +7535,7 @@ var CommitWorker = class {
7372
7535
  let pending = [...input.allTags];
7373
7536
  const committedTags = /* @__PURE__ */ new Set();
7374
7537
  const lastFailureCodeByTag = /* @__PURE__ */ new Map();
7538
+ const tagWriteFacts = /* @__PURE__ */ new Map();
7375
7539
  let globalAdmission = "admitted";
7376
7540
  for (let attempt = 0; attempt < MAX_WRITE_ATTEMPTS && pending.length > 0; attempt += 1) {
7377
7541
  const append = (stageScope) => Promise.allSettled(
@@ -7398,12 +7562,26 @@ var CommitWorker = class {
7398
7562
  retryIndex: attempt,
7399
7563
  attemptId
7400
7564
  });
7401
- const body = response3.status === 503 ? await response3.clone().json().catch(() => void 0) : void 0;
7565
+ const success = response3.status >= 200 && response3.status < 300;
7566
+ let appendVersion;
7567
+ let appendUpdatedAt;
7568
+ let code;
7569
+ try {
7570
+ const parsed = await response3.clone().json();
7571
+ if (isObject5(parsed)) {
7572
+ if (typeof parsed.version === "number" && Number.isSafeInteger(parsed.version)) appendVersion = parsed.version;
7573
+ if (typeof parsed.updatedAt === "string" && parsed.updatedAt.length > 0) appendUpdatedAt = parsed.updatedAt;
7574
+ if (typeof parsed.code === "string") code = parsed.code;
7575
+ }
7576
+ } catch {
7577
+ }
7402
7578
  return {
7403
7579
  tag,
7404
- success: response3.status >= 200 && response3.status < 300,
7580
+ success,
7405
7581
  globalAdmission: readGlobalAdmission(response3),
7406
- code: isObject5(body) && typeof body.code === "string" ? body.code : void 0
7582
+ code,
7583
+ appendVersion,
7584
+ appendUpdatedAt
7407
7585
  };
7408
7586
  })
7409
7587
  );
@@ -7415,6 +7593,9 @@ var CommitWorker = class {
7415
7593
  committedTags.add(tag);
7416
7594
  lastFailureCodeByTag.delete(tag);
7417
7595
  globalAdmission = mergeGlobalAdmission(globalAdmission, result2.value.globalAdmission);
7596
+ if (result2.value.appendVersion !== void 0 && result2.value.appendUpdatedAt !== void 0) {
7597
+ tagWriteFacts.set(tag, { version: result2.value.appendVersion, updatedAt: result2.value.appendUpdatedAt });
7598
+ }
7418
7599
  } else {
7419
7600
  lastFailureCodeByTag.set(
7420
7601
  tag,
@@ -7431,7 +7612,8 @@ var CommitWorker = class {
7431
7612
  registrationUnavailableTags: pending.filter(
7432
7613
  (tag) => lastFailureCodeByTag.get(tag) === "partition_registration_unavailable"
7433
7614
  ),
7434
- globalAdmission
7615
+ globalAdmission,
7616
+ tagWriteFacts
7435
7617
  };
7436
7618
  }
7437
7619
  /**
@@ -7464,10 +7646,13 @@ var CommitWorker = class {
7464
7646
  if (traceScope !== void 0) {
7465
7647
  await traceScope.span("S17", {}, async () => void 0);
7466
7648
  }
7467
- await this.cancelReservations(tags, attemptId, fault2, traceScope);
7649
+ const cleanup = await this.cancelReservations(tags, attemptId, fault2, traceScope);
7468
7650
  await this.retiredJournalMilestone("S05e", traceScope, 4);
7469
7651
  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");
7470
- return responseWithAttempt(response3, attemptId, fault2 !== void 0);
7652
+ return {
7653
+ response: responseWithAttempt(response3, attemptId, fault2 !== void 0),
7654
+ resolved: cleanup.failedTags.length === 0
7655
+ };
7471
7656
  }
7472
7657
  /**
7473
7658
  * Persist the local partial-write fact for each tag whose append did not
@@ -7504,22 +7689,25 @@ var CommitWorker = class {
7504
7689
  }
7505
7690
  }, 500), attemptId, exposeAttempt);
7506
7691
  }
7507
- async successResponse(input, candidates, attemptId, startedAt, fault2, traceScope) {
7508
- const readStates = (stageScope) => Promise.all(input.allTags.map(async (tag, memberIndex) => {
7692
+ async successResponse(input, candidates, attemptId, startedAt, fault2, traceScope, writes) {
7693
+ const assemble = async (stageScope) => {
7509
7694
  if (fault2 === "tag-state-unavailable") {
7510
7695
  throw new Error("Test fault made the committed tag state unavailable");
7511
7696
  }
7512
- const response3 = await this.tagRequest(tag, "/head-facts", void 0, stageScope?.fork(), stageScope === void 0 ? void 0 : "S14", { memberIndex, attemptId });
7513
- if (response3.status !== 200) {
7514
- throw new Error("Committed tag state was unavailable while preparing the response");
7515
- }
7516
- const body = await response3.json();
7517
- if (typeof body.version !== "number" || typeof body.updatedAt !== "string" || typeof body.head !== "string") {
7518
- throw new Error("Committed tag state was malformed while preparing the response");
7697
+ const results = [];
7698
+ for (const [memberIndex, tag] of input.allTags.entries()) {
7699
+ const read = () => {
7700
+ const fact = writes?.tagWriteFacts.get(tag);
7701
+ if (fact === void 0) {
7702
+ throw new Error("Committed tag state was unavailable while preparing the response");
7703
+ }
7704
+ return { tag, version: fact.version, writtenAt: fact.updatedAt };
7705
+ };
7706
+ results.push(stageScope === void 0 ? read() : await stageScope.fork().span("S14", { tag, memberIndex, attemptId }, async () => read()));
7519
7707
  }
7520
- return { tag, version: body.version, writtenAt: body.updatedAt };
7521
- }));
7522
- const tagWriteResults = traceScope === void 0 ? await readStates() : await traceScope.span("S13", {}, async (stage) => readStates(stage));
7708
+ return results;
7709
+ };
7710
+ const tagWriteResults = traceScope === void 0 ? await assemble() : await traceScope.span("S13", {}, async (stage) => assemble(stage));
7523
7711
  return {
7524
7712
  writtenEvents: candidates.map((candidate) => ({
7525
7713
  payload: encodeBase64Utf8(candidate.payload),
@@ -7911,15 +8099,15 @@ function observePostAdmission(observer, message, source, input) {
7911
8099
  observedAt: Date.now()
7912
8100
  });
7913
8101
  }
7914
- function errorText(error10) {
7915
- if (error10 instanceof Error && error10.message.length > 0) return error10.message;
7916
- return String(error10);
8102
+ function errorText(error11) {
8103
+ if (error11 instanceof Error && error11.message.length > 0) return error11.message;
8104
+ return String(error11);
7917
8105
  }
7918
8106
  function deliveryCorrelationId(message, source, supplied) {
7919
8107
  return supplied ?? `${source}:${message.serviceId}:${message.eventId}:${message.attemptId}`;
7920
8108
  }
7921
- function defaultFailureClass(error10) {
7922
- const candidate = error10;
8109
+ function defaultFailureClass(error11) {
8110
+ const candidate = error11;
7923
8111
  if (candidate.failureClass === "duplicate-race") return "duplicate-race";
7924
8112
  if (candidate.failureClass === "nonretryable-definition-poison") return "nonretryable-definition-poison";
7925
8113
  if (candidate.failureClass === "retryable-transient") return "retryable-transient";
@@ -7978,8 +8166,8 @@ async function applyViewHandlers(views, message, storedEvent, arrivedAt, source,
7978
8166
  result: { id: view.id, status, durationMs: Math.max(0, performance.now() - viewStartedAt) },
7979
8167
  failure: void 0
7980
8168
  };
7981
- } catch (error10) {
7982
- const failureClass = view.classifyError?.(error10) ?? defaultFailureClass(error10);
8169
+ } catch (error11) {
8170
+ const failureClass = view.classifyError?.(error11) ?? defaultFailureClass(error11);
7983
8171
  observePostAdmission(observer, message, source, {
7984
8172
  stage: "unsafe-view-apply",
7985
8173
  boundary: "end",
@@ -7991,10 +8179,10 @@ async function applyViewHandlers(views, message, storedEvent, arrivedAt, source,
7991
8179
  id: view.id,
7992
8180
  status: "failed",
7993
8181
  failureClass,
7994
- error: errorText(error10),
8182
+ error: errorText(error11),
7995
8183
  durationMs: Math.max(0, performance.now() - viewStartedAt)
7996
8184
  },
7997
- failure: { phase: "view", class: failureClass, viewId: view.id, error: errorText(error10) }
8185
+ failure: { phase: "view", class: failureClass, viewId: view.id, error: errorText(error11) }
7998
8186
  };
7999
8187
  }
8000
8188
  }));
@@ -8024,15 +8212,15 @@ async function processDeliveryCore(message, source, env, options = {}) {
8024
8212
  // settled; this is the durable post-batch observation boundary.
8025
8213
  observedAt: Date.now()
8026
8214
  });
8027
- } catch (error10) {
8028
- const failures2 = [{ phase: "recordDelivery", class: "retryable-transient", error: errorText(error10) }];
8215
+ } catch (error11) {
8216
+ const failures2 = [{ phase: "recordDelivery", class: "retryable-transient", error: errorText(error11) }];
8029
8217
  return result(source, message, "stored", arrivedAt, false, [], failures2, options.correlationId, startedAt);
8030
8218
  }
8031
8219
  if (outcome.outcome !== "stored") {
8032
8220
  try {
8033
8221
  await store.projectDeliveryIncidents?.(message.serviceId);
8034
- } catch (error10) {
8035
- const failures2 = [{ phase: "detector", class: "retryable-transient", error: errorText(error10) }];
8222
+ } catch (error11) {
8223
+ const failures2 = [{ phase: "detector", class: "retryable-transient", error: errorText(error11) }];
8036
8224
  return result(source, message, outcome.outcome, arrivedAt, false, [], failures2, options.correlationId, startedAt);
8037
8225
  }
8038
8226
  return result(source, message, outcome.outcome, arrivedAt, false, [], [], options.correlationId, startedAt);
@@ -8061,20 +8249,20 @@ async function processDeliveryCore(message, source, env, options = {}) {
8061
8249
  boundary: "end",
8062
8250
  outcome: "available"
8063
8251
  });
8064
- } catch (error10) {
8252
+ } catch (error11) {
8065
8253
  observePostAdmission(options.durableHopObserver, message, source, {
8066
8254
  stage: "post-record-delivery-global-receipt-readback",
8067
8255
  boundary: "end",
8068
8256
  outcome: "error"
8069
8257
  });
8070
- failures.push({ phase: "recordDelivery", class: "retryable-transient", error: errorText(error10) });
8258
+ failures.push({ phase: "recordDelivery", class: "retryable-transient", error: errorText(error11) });
8071
8259
  return result(source, message, "stored", arrivedAt, false, [], failures, options.correlationId, startedAt);
8072
8260
  }
8073
8261
  if (options.afterGlobalReceipt !== void 0) {
8074
8262
  try {
8075
8263
  await options.afterGlobalReceipt({ message, receipt, arrivedAt, source });
8076
- } catch (error10) {
8077
- failures.push({ phase: "drain", class: "retryable-transient", error: errorText(error10) });
8264
+ } catch (error11) {
8265
+ failures.push({ phase: "drain", class: "retryable-transient", error: errorText(error11) });
8078
8266
  }
8079
8267
  }
8080
8268
  }
@@ -8091,8 +8279,8 @@ async function processDeliveryCore(message, source, env, options = {}) {
8091
8279
  if (options.beforeViews !== void 0) {
8092
8280
  try {
8093
8281
  await options.beforeViews({ message, event: storedEvent, arrivedAt, source });
8094
- } catch (error10) {
8095
- failures.push({ phase: "completeness", class: "retryable-transient", error: errorText(error10) });
8282
+ } catch (error11) {
8283
+ failures.push({ phase: "completeness", class: "retryable-transient", error: errorText(error11) });
8096
8284
  return result(source, message, "stored", arrivedAt, false, viewResults, failures, options.correlationId, startedAt);
8097
8285
  }
8098
8286
  }
@@ -8112,14 +8300,14 @@ async function processDeliveryCore(message, source, env, options = {}) {
8112
8300
  boundary: "end",
8113
8301
  outcome: "applied"
8114
8302
  });
8115
- } catch (error10) {
8303
+ } catch (error11) {
8116
8304
  observePostAdmission(options.durableHopObserver, message, source, {
8117
8305
  stage: "detector",
8118
8306
  boundary: "end",
8119
8307
  outcome: "error"
8120
8308
  });
8121
8309
  try {
8122
- await options.onDetectorFailure?.({ message, arrivedAt, source, error: error10 });
8310
+ await options.onDetectorFailure?.({ message, arrivedAt, source, error: error11 });
8123
8311
  } catch (healthError) {
8124
8312
  failures.push({
8125
8313
  phase: "detector",
@@ -8127,7 +8315,7 @@ async function processDeliveryCore(message, source, env, options = {}) {
8127
8315
  error: `detector_health_record_failed:${errorText(healthError)}`
8128
8316
  });
8129
8317
  }
8130
- failures.push({ phase: "detector", class: "retryable-transient", error: errorText(error10) });
8318
+ failures.push({ phase: "detector", class: "retryable-transient", error: errorText(error11) });
8131
8319
  return result(source, message, "stored", arrivedAt, false, [], failures, options.correlationId, startedAt);
8132
8320
  }
8133
8321
  const views = gatedViews;
@@ -8144,16 +8332,16 @@ async function processDeliveryCore(message, source, env, options = {}) {
8144
8332
  if (options.onStored !== void 0) {
8145
8333
  try {
8146
8334
  await options.onStored({ message, event: storedEvent, arrivedAt, source });
8147
- } catch (error10) {
8148
- failures.push({ phase: "view", class: "retryable-transient", viewId: "legacy-onStored", error: errorText(error10) });
8335
+ } catch (error11) {
8336
+ failures.push({ phase: "view", class: "retryable-transient", viewId: "legacy-onStored", error: errorText(error11) });
8149
8337
  }
8150
8338
  }
8151
8339
  const preliminary = result(source, message, "stored", arrivedAt, detectorApplied, viewResults, failures, options.correlationId, startedAt);
8152
8340
  if (options.afterDelivery !== void 0 && failures.every((failure3) => failure3.class === "duplicate-race")) {
8153
8341
  try {
8154
8342
  await options.afterDelivery({ message, event: storedEvent, arrivedAt, source, result: preliminary });
8155
- } catch (error10) {
8156
- failures.push({ phase: "drain", class: "retryable-transient", error: errorText(error10) });
8343
+ } catch (error11) {
8344
+ failures.push({ phase: "drain", class: "retryable-transient", error: errorText(error11) });
8157
8345
  }
8158
8346
  }
8159
8347
  return result(source, message, "stored", arrivedAt, detectorApplied, viewResults, failures, options.correlationId, startedAt);
@@ -8175,8 +8363,8 @@ function asNumber(value, name) {
8175
8363
  if (!Number.isSafeInteger(number) || number < 0) throw new Error(`G44 ${name} must be a non-negative safe integer`);
8176
8364
  return number;
8177
8365
  }
8178
- function errorText2(error10) {
8179
- return error10 instanceof Error && error10.message.length > 0 ? error10.message : String(error10);
8366
+ function errorText2(error11) {
8367
+ return error11 instanceof Error && error11.message.length > 0 ? error11.message : String(error11);
8180
8368
  }
8181
8369
  function settledFrontierFromCursor(cursorJson) {
8182
8370
  const cursor = settledCursorFromJson(cursorJson);
@@ -8280,8 +8468,8 @@ var GlobalCompletenessReconciler = class {
8280
8468
  let snapshots;
8281
8469
  try {
8282
8470
  snapshots = await this.snapshotPartitions(serviceId);
8283
- } catch (error10) {
8284
- const message = errorText2(error10);
8471
+ } catch (error11) {
8472
+ const message = errorText2(error11);
8285
8473
  await this.appendFinding(serviceId, {
8286
8474
  identity: scannerFailureIdentity(serviceId),
8287
8475
  type: "GLOBAL_ARRAY_SCANNER_FAILURE",
@@ -8323,7 +8511,7 @@ var GlobalCompletenessReconciler = class {
8323
8511
  let joined;
8324
8512
  try {
8325
8513
  joined = this.options.globalReceiptMatcher === void 0 ? await this.globalReceiptMatches(snapshot.serviceId, snapshot.tag, obligation) : await this.options.globalReceiptMatcher(snapshot.serviceId, snapshot.tag, obligation);
8326
- } catch (error10) {
8514
+ } catch (error11) {
8327
8515
  await this.appendFinding(snapshot.serviceId, {
8328
8516
  identity: `GLOBAL_RECEIPT_UNAVAILABLE|${snapshot.serviceId}|${snapshot.tag}|${obligation.obligationSequence}|${obligation.eventId}|${obligation.eventDigest}`,
8329
8517
  type: "GLOBAL_ARRAY_RECEIPT_UNAVAILABLE",
@@ -8332,7 +8520,7 @@ var GlobalCompletenessReconciler = class {
8332
8520
  eventId: obligation.eventId,
8333
8521
  eventDigest: obligation.eventDigest
8334
8522
  }, nowMs).catch(() => void 0);
8335
- throw error10;
8523
+ throw error11;
8336
8524
  }
8337
8525
  if (!joined) {
8338
8526
  await this.appendObligationFinding(snapshot.serviceId, snapshot.tag, obligation, nowMs);
@@ -8351,8 +8539,8 @@ var GlobalCompletenessReconciler = class {
8351
8539
  if (afterSequence !== snapshot.upperBoundSequence) {
8352
8540
  throw new Error(`source_partition_range_incomplete:${snapshot.tag}`);
8353
8541
  }
8354
- } catch (error10) {
8355
- if (errorText2(error10).startsWith("source_")) {
8542
+ } catch (error11) {
8543
+ if (errorText2(error11).startsWith("source_")) {
8356
8544
  await this.appendFinding(snapshot.serviceId, {
8357
8545
  identity: sourceUnavailableIdentity(snapshot.serviceId, snapshot.tag),
8358
8546
  type: "GLOBAL_ARRAY_SOURCE_PARTITION_UNAVAILABLE",
@@ -8362,7 +8550,7 @@ var GlobalCompletenessReconciler = class {
8362
8550
  eventDigest: null
8363
8551
  }, nowMs).catch(() => void 0);
8364
8552
  }
8365
- throw error10;
8553
+ throw error11;
8366
8554
  }
8367
8555
  }
8368
8556
  const endSnapshots = await this.snapshotPartitions(serviceId);
@@ -8381,8 +8569,8 @@ var GlobalCompletenessReconciler = class {
8381
8569
  }
8382
8570
  await this.writeHealth(serviceId, "HEALTHY", JSON.stringify(cursor), nowMs, null, nowMs);
8383
8571
  return { kind: "FULL", partitions: snapshots, scannedObligations: scanned };
8384
- } catch (error10) {
8385
- const message = errorText2(error10);
8572
+ } catch (error11) {
8573
+ const message = errorText2(error11);
8386
8574
  const health = message.startsWith("source_") ? "UNKNOWN" : "FAILED";
8387
8575
  if (health === "FAILED") {
8388
8576
  await this.appendFinding(serviceId, {
@@ -8524,8 +8712,8 @@ var GlobalCompletenessReconciler = class {
8524
8712
  * without applying views. It shares the scanner's single health/finding
8525
8713
  * authority rather than creating a second incident workflow.
8526
8714
  */
8527
- async recordDetectorFailure(serviceId, error10, nowMs) {
8528
- const message = `detector_failure:${errorText2(error10).slice(0, 256)}`;
8715
+ async recordDetectorFailure(serviceId, error11, nowMs) {
8716
+ const message = `detector_failure:${errorText2(error11).slice(0, 256)}`;
8529
8717
  await this.appendFinding(serviceId, {
8530
8718
  identity: `GLOBAL_DETECTOR_FAILURE|${serviceId}`,
8531
8719
  type: "GLOBAL_ARRAY_DETECTOR_FAILURE",
@@ -8664,7 +8852,7 @@ var GlobalCompletenessReconciler = class {
8664
8852
  nowMs
8665
8853
  ).run();
8666
8854
  }
8667
- async writeHealth(serviceId, status, cursor, lastFullScanAt, error10, nowMs) {
8855
+ async writeHealth(serviceId, status, cursor, lastFullScanAt, error11, nowMs) {
8668
8856
  await this.database.prepare(
8669
8857
  `INSERT INTO serialized_dcb_completeness_scanner_health
8670
8858
  (service_id, scanner_version, status, cursor_json, last_full_scan_at, last_error, updated_at)
@@ -8676,7 +8864,7 @@ var GlobalCompletenessReconciler = class {
8676
8864
  last_full_scan_at = COALESCE(excluded.last_full_scan_at, serialized_dcb_completeness_scanner_health.last_full_scan_at),
8677
8865
  last_error = excluded.last_error,
8678
8866
  updated_at = excluded.updated_at`
8679
- ).bind(serviceId, this.scannerVersion, status, cursor, lastFullScanAt, error10, nowMs).run();
8867
+ ).bind(serviceId, this.scannerVersion, status, cursor, lastFullScanAt, error11, nowMs).run();
8680
8868
  }
8681
8869
  };
8682
8870
  function globalReceiptAcknowledgement(message, receivedAt) {
@@ -8768,7 +8956,7 @@ function sourceAcknowledgementOptions(env, options) {
8768
8956
  if (decision.kind !== "SETTLED") {
8769
8957
  throw new Error(`global_completeness_${decision.kind}:${decision.health.status}`);
8770
8958
  }
8771
- } catch (error10) {
8959
+ } catch (error11) {
8772
8960
  if (!completed) {
8773
8961
  observeG60PostAdmission(options.durableHopObserver, {
8774
8962
  stage: "completeness-coverage",
@@ -8783,7 +8971,7 @@ function sourceAcknowledgementOptions(env, options) {
8783
8971
  observedAt: Date.now()
8784
8972
  });
8785
8973
  }
8786
- throw error10;
8974
+ throw error11;
8787
8975
  }
8788
8976
  } : options.beforeViews;
8789
8977
  const observedSourceAcknowledgement = sourceAcknowledgement === void 0 ? void 0 : async (input) => {
@@ -8791,14 +8979,14 @@ function sourceAcknowledgementOptions(env, options) {
8791
8979
  try {
8792
8980
  await sourceAcknowledgement(input);
8793
8981
  observeSourceSubstep(options.durableHopObserver, { ...input, boundary: "end", outcome: "acknowledged" });
8794
- } catch (error10) {
8982
+ } catch (error11) {
8795
8983
  observeSourceSubstep(options.durableHopObserver, { ...input, boundary: "end", outcome: "error" });
8796
- throw error10;
8984
+ throw error11;
8797
8985
  }
8798
8986
  };
8799
- const detectorFailure = hasG44Authority ? async ({ message, arrivedAt, error: error10, source }) => {
8800
- await options.onDetectorFailure?.({ message, arrivedAt, error: error10, source });
8801
- await new GlobalCompletenessReconciler(env.D1, env.TAG).recordDetectorFailure(message.serviceId, error10, arrivedAt);
8987
+ const detectorFailure = hasG44Authority ? async ({ message, arrivedAt, error: error11, source }) => {
8988
+ await options.onDetectorFailure?.({ message, arrivedAt, error: error11, source });
8989
+ await new GlobalCompletenessReconciler(env.D1, env.TAG).recordDetectorFailure(message.serviceId, error11, arrivedAt);
8802
8990
  } : options.onDetectorFailure;
8803
8991
  return {
8804
8992
  ...options,
@@ -8813,9 +9001,9 @@ function sharedStore(env, provider) {
8813
9001
  async function admitBootstrapRoute(env, serviceId, route) {
8814
9002
  if (env.BOOTSTRAP === void 0) {
8815
9003
  if (env.G38_DOORBELL_DELIVERY_ROLE === "receiver") {
8816
- const error10 = new Error(`bootstrap_route_binding_missing:${route}`);
8817
- error10.name = "BootstrapRouteBindingMissingError";
8818
- throw error10;
9004
+ const error11 = new Error(`bootstrap_route_binding_missing:${route}`);
9005
+ error11.name = "BootstrapRouteBindingMissingError";
9006
+ throw error11;
8819
9007
  }
8820
9008
  return;
8821
9009
  }
@@ -8904,10 +9092,10 @@ async function handleDownstreamQueue(batch, env, options = {}) {
8904
9092
  if (outcome.outcome === "stored" && !outcome.failures.some((failure3) => failure3.phase === "recordDelivery")) {
8905
9093
  try {
8906
9094
  options.afterStoredQueueDelivery?.({ message: queued.body, result: outcome });
8907
- } catch (error10) {
9095
+ } catch (error11) {
8908
9096
  console.warn("safe_lane_kick", {
8909
9097
  status: "failed-to-schedule",
8910
- error: error10 instanceof Error ? error10.message : String(error10),
9098
+ error: error11 instanceof Error ? error11.message : String(error11),
8911
9099
  serviceId: queued.body.serviceId,
8912
9100
  eventId: queued.body.eventId,
8913
9101
  attemptId: queued.body.attemptId
@@ -8929,6 +9117,36 @@ async function stabilizeDownstream(env, options = {}, serviceId, serviceIdentity
8929
9117
  });
8930
9118
  }
8931
9119
 
9120
+ // src/scope/ControlRouteScope.ts
9121
+ function response2(status, code, error11) {
9122
+ return new Response(JSON.stringify({ code, error: error11 }), {
9123
+ status,
9124
+ headers: { "content-type": "application/json; charset=utf-8" }
9125
+ });
9126
+ }
9127
+ function scopeIdentityMissingResponse() {
9128
+ return response2(503, "scope.identity_missing", "A deployment service identity is required for this scope");
9129
+ }
9130
+ function enforceControlRouteScope(input) {
9131
+ let actual;
9132
+ try {
9133
+ actual = input.provider.forRequest(input.request, input.requestOptions).serviceId;
9134
+ } catch (caught) {
9135
+ if (caught instanceof ServiceIdentityMissingError) {
9136
+ console.error({ schema: "sdt.scope/v1", code: "scope.identity_missing", route: input.route });
9137
+ return { response: scopeIdentityMissingResponse() };
9138
+ }
9139
+ throw caught;
9140
+ }
9141
+ if (input.pathServiceId !== actual) {
9142
+ console.warn({ schema: "sdt.scope/v1", code: "scope.mismatch", route: input.route });
9143
+ return {
9144
+ response: response2(403, "scope.mismatch", "The path service identity is not authorized for this deployment")
9145
+ };
9146
+ }
9147
+ return { serviceId: actual };
9148
+ }
9149
+
8932
9150
  // src/downstream/OutboxDrain.ts
8933
9151
  function json5(body, status = 200) {
8934
9152
  return new Response(JSON.stringify(body), {
@@ -9025,15 +9243,32 @@ async function handleOutboxDrainRequest(request, env, options = {}) {
9025
9243
  if (!isDrainRequest(body)) {
9026
9244
  return json5({ error: "serviceId and unique non-empty tags are required", code: "invalid_outbox_drain_request" }, 400);
9027
9245
  }
9246
+ const requestedServiceId = body.serviceId;
9247
+ const tags = body.tags;
9248
+ const provider = options.serviceIdentityProvider ?? envServiceIdentity(env);
9249
+ let authority;
9250
+ try {
9251
+ authority = provider.forRequest(request).serviceId;
9252
+ } catch (caught) {
9253
+ if (caught instanceof ServiceIdentityMissingError) return scopeIdentityMissingResponse();
9254
+ throw caught;
9255
+ }
9256
+ if (requestedServiceId !== authority) {
9257
+ console.warn({ schema: "sdt.scope/v1", code: "scope.mismatch", route: "outbox-drain" });
9258
+ return json5({
9259
+ code: "scope.mismatch",
9260
+ error: "The request service identity is not authorized for this deployment"
9261
+ }, 403);
9262
+ }
9028
9263
  try {
9029
9264
  const results = [];
9030
- for (const tag of body.tags) {
9031
- results.push(await drainTagOutbox({ serviceId: body.serviceId, tag }, env, systemPipelineClock, options));
9265
+ for (const tag of tags) {
9266
+ results.push(await drainTagOutbox({ serviceId: authority, tag }, env, systemPipelineClock, options));
9032
9267
  }
9033
9268
  return json5({ results });
9034
- } catch (error10) {
9269
+ } catch (error11) {
9035
9270
  return json5({
9036
- error: error10 instanceof Error ? error10.message : "Outbox drain failed",
9271
+ error: error11 instanceof Error ? error11.message : "Outbox drain failed",
9037
9272
  code: "outbox_drain_failed"
9038
9273
  }, 503);
9039
9274
  }
@@ -9783,9 +10018,9 @@ function isNonEmptyString7(value) {
9783
10018
  return typeof value === "string" && value.length > 0;
9784
10019
  }
9785
10020
  function base64Json(value) {
9786
- const bytes = new TextEncoder().encode(JSON.stringify(value));
10021
+ const bytes2 = new TextEncoder().encode(JSON.stringify(value));
9787
10022
  let binary = "";
9788
- for (const byte of bytes) {
10023
+ for (const byte of bytes2) {
9789
10024
  binary += String.fromCharCode(byte);
9790
10025
  }
9791
10026
  return btoa(binary);
@@ -9963,9 +10198,9 @@ function decodeStoredJson(value) {
9963
10198
  }
9964
10199
  }
9965
10200
  function jsonBytes(value) {
9966
- const bytes = new TextEncoder().encode(JSON.stringify(value));
10201
+ const bytes2 = new TextEncoder().encode(JSON.stringify(value));
9967
10202
  let binary = "";
9968
- for (const byte of bytes) binary += String.fromCharCode(byte);
10203
+ for (const byte of bytes2) binary += String.fromCharCode(byte);
9969
10204
  return btoa(binary);
9970
10205
  }
9971
10206
  function isRuntimeBridgedProjector(definition) {
@@ -10158,8 +10393,8 @@ function asNumber2(value, name) {
10158
10393
  if (!Number.isSafeInteger(number)) throw new Error(`D1 ${name} was not a safe integer`);
10159
10394
  return number;
10160
10395
  }
10161
- function errorText3(error10) {
10162
- return (error10 instanceof Error ? error10.message : String(error10)).slice(0, 256);
10396
+ function errorText3(error11) {
10397
+ return (error11 instanceof Error ? error11.message : String(error11)).slice(0, 256);
10163
10398
  }
10164
10399
  function sortedUnique2(values) {
10165
10400
  return [...new Set(values)].sort((left, right) => binaryCompare(left, right));
@@ -10346,8 +10581,8 @@ var D1EventStore = class {
10346
10581
  let failure3;
10347
10582
  try {
10348
10583
  result2 = await this.recordDeliveryCore(message, arrivedAt, deliverySource, mutationAttemptId);
10349
- } catch (error10) {
10350
- failure3 = { error: error10 };
10584
+ } catch (error11) {
10585
+ failure3 = { error: error11 };
10351
10586
  }
10352
10587
  const retryReason = failure3 === void 0 ? null : errorText3(failure3.error);
10353
10588
  const suppressDiagnostic = failure3?.error instanceof D1IdentityConflictError && failure3.error.beforeMutation;
@@ -10918,8 +11153,8 @@ var D1EventStore = class {
10918
11153
  if (replay === null || replay === void 0) return finish({ kind: "miss" });
10919
11154
  const event = await this.eventById(serviceId, asString3(replay.event_id, "replay.event_id"));
10920
11155
  return event === void 0 ? finish({ kind: "unknown", reason: "replay-event-row-disappeared" }) : finish({ kind: "replay", event });
10921
- } catch (error10) {
10922
- return finish({ kind: "unknown", reason: errorText3(error10) });
11156
+ } catch (error11) {
11157
+ return finish({ kind: "unknown", reason: errorText3(error11) });
10923
11158
  }
10924
11159
  }
10925
11160
  /**
@@ -11394,8 +11629,8 @@ var D1EventStore = class {
11394
11629
  try {
11395
11630
  try {
11396
11631
  await this.options.beforeG69AdmissionAttempt?.();
11397
- } catch (error10) {
11398
- await appendFailedDiagnostic(errorText3(error10));
11632
+ } catch (error11) {
11633
+ await appendFailedDiagnostic(errorText3(error11));
11399
11634
  return;
11400
11635
  }
11401
11636
  const afterObservedAt = Date.now();
@@ -11469,15 +11704,15 @@ function integer(row, key) {
11469
11704
  function operationId() {
11470
11705
  return `mv-unsafe-${crypto.randomUUID()}`;
11471
11706
  }
11472
- function errorFrom(error10) {
11473
- const value = String(error10);
11707
+ function errorFrom(error11) {
11708
+ const value = String(error11);
11474
11709
  if (value.includes("mv_unsafe_receipts") && (value.includes("UNIQUE") || value.includes("constraint"))) {
11475
- return new UnsafeWindowMaterializedViewError("UNSAFE_DUPLICATE_RACE", false, "Concurrent unsafe receipt was committed by another delivery", { cause: error10 });
11710
+ return new UnsafeWindowMaterializedViewError("UNSAFE_DUPLICATE_RACE", false, "Concurrent unsafe receipt was committed by another delivery", { cause: error11 });
11476
11711
  }
11477
- if (value.includes("unsafe_row_cas")) return new UnsafeWindowMaterializedViewError("UNSAFE_ROW_CAS_MISMATCH", true, "Unsafe row version changed before atomic apply", { cause: error10 });
11478
- if (value.includes("unsafe_suid_contradiction")) return new UnsafeWindowMaterializedViewError("UNSAFE_SUID_CONTRADICTION", false, "Unsafe same-SUID payload contradiction", { cause: error10 });
11479
- if (value.includes("unsafe_safe_ahead")) return new UnsafeWindowMaterializedViewError("UNSAFE_SAFE_AHEAD", false, "Safe head already covers unsafe event", { cause: error10 });
11480
- if (value.includes("unsafe_behind_frontier")) return new UnsafeWindowMaterializedViewError("UNSAFE_BEHIND_FRONTIER", false, "Unsafe reads are fail-closed pending rebuild", { cause: error10 });
11712
+ if (value.includes("unsafe_row_cas")) return new UnsafeWindowMaterializedViewError("UNSAFE_ROW_CAS_MISMATCH", true, "Unsafe row version changed before atomic apply", { cause: error11 });
11713
+ if (value.includes("unsafe_suid_contradiction")) return new UnsafeWindowMaterializedViewError("UNSAFE_SUID_CONTRADICTION", false, "Unsafe same-SUID payload contradiction", { cause: error11 });
11714
+ if (value.includes("unsafe_safe_ahead")) return new UnsafeWindowMaterializedViewError("UNSAFE_SAFE_AHEAD", false, "Safe head already covers unsafe event", { cause: error11 });
11715
+ if (value.includes("unsafe_behind_frontier")) return new UnsafeWindowMaterializedViewError("UNSAFE_BEHIND_FRONTIER", false, "Unsafe reads are fail-closed pending rebuild", { cause: error11 });
11481
11716
  return void 0;
11482
11717
  }
11483
11718
  var UnsafeWindowMaterializedViewStore = class {
@@ -11610,8 +11845,8 @@ var UnsafeWindowMaterializedViewStore = class {
11610
11845
  await this.options.beforeApplyBatch?.(input, statements);
11611
11846
  try {
11612
11847
  await this.database.batch(statements);
11613
- } catch (error10) {
11614
- const text = String(error10);
11848
+ } catch (error11) {
11849
+ const text = String(error11);
11615
11850
  const guardFailure = text.includes("mv_atomic_guards") || text.includes("checkpoint_match") || text.includes("mv_unsafe_receipts") && (text.includes("UNIQUE") || text.includes("constraint"));
11616
11851
  if (guardFailure) {
11617
11852
  const receipt = await this.database.prepare(
@@ -11619,16 +11854,16 @@ var UnsafeWindowMaterializedViewStore = class {
11619
11854
  ).bind(input.serviceId, input.viewId, input.eventId).first();
11620
11855
  if (receipt !== null && receipt !== void 0) {
11621
11856
  if (string2(receipt, "suid") !== input.suid) {
11622
- throw new UnsafeWindowMaterializedViewError("UNSAFE_SUID_CONTRADICTION", false, "Duplicate event identity has a contradictory SUID", { cause: error10 });
11857
+ throw new UnsafeWindowMaterializedViewError("UNSAFE_SUID_CONTRADICTION", false, "Duplicate event identity has a contradictory SUID", { cause: error11 });
11623
11858
  }
11624
11859
  if (this.options.beforeApplyBatch !== void 0) {
11625
- throw new UnsafeWindowMaterializedViewError("UNSAFE_DUPLICATE_RACE", false, "Concurrent unsafe receipt was committed by another delivery", { cause: error10 });
11860
+ throw new UnsafeWindowMaterializedViewError("UNSAFE_DUPLICATE_RACE", false, "Concurrent unsafe receipt was committed by another delivery", { cause: error11 });
11626
11861
  }
11627
11862
  return { outcome: "no-change", duplicate: true };
11628
11863
  }
11629
11864
  return this.apply(input, true);
11630
11865
  }
11631
- throw error10;
11866
+ throw error11;
11632
11867
  }
11633
11868
  const result2 = { outcome: "applied", duplicate: false };
11634
11869
  await this.options.afterApplyBatch?.(input, result2);
@@ -11761,13 +11996,13 @@ var UnsafeWindowMaterializedViewStore = class {
11761
11996
  await this.options.beforeApplyBatch?.(input, statements);
11762
11997
  try {
11763
11998
  await this.database.batch(statements);
11764
- } catch (error10) {
11765
- if (sameSuidContradiction) throw new UnsafeWindowMaterializedViewError("UNSAFE_SUID_CONTRADICTION", false, "Unsafe same-SUID payload contradiction", { cause: error10 });
11766
- if (rowCasMismatch) throw new UnsafeWindowMaterializedViewError("UNSAFE_ROW_CAS_MISMATCH", true, "Unsafe row version changed before atomic apply", { cause: error10 });
11767
- if (safeAhead) throw new UnsafeWindowMaterializedViewError("UNSAFE_SAFE_AHEAD", false, "Safe head already covers unsafe event", { cause: error10 });
11768
- const typed = errorFrom(error10);
11999
+ } catch (error11) {
12000
+ if (sameSuidContradiction) throw new UnsafeWindowMaterializedViewError("UNSAFE_SUID_CONTRADICTION", false, "Unsafe same-SUID payload contradiction", { cause: error11 });
12001
+ if (rowCasMismatch) throw new UnsafeWindowMaterializedViewError("UNSAFE_ROW_CAS_MISMATCH", true, "Unsafe row version changed before atomic apply", { cause: error11 });
12002
+ if (safeAhead) throw new UnsafeWindowMaterializedViewError("UNSAFE_SAFE_AHEAD", false, "Safe head already covers unsafe event", { cause: error11 });
12003
+ const typed = errorFrom(error11);
11769
12004
  if (typed !== void 0) throw typed;
11770
- throw error10;
12005
+ throw error11;
11771
12006
  }
11772
12007
  const result2 = { outcome, duplicate: false };
11773
12008
  await this.options.afterApplyBatch?.(input, result2);
@@ -11834,8 +12069,8 @@ var UnsafeWindowMaterializedViewStore = class {
11834
12069
  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),
11835
12070
  this.database.prepare("DELETE FROM mv_atomic_guards WHERE operation_id = ?").bind(operation2)
11836
12071
  ]);
11837
- } catch (error10) {
11838
- throw new UnsafeWindowMaterializedViewError("UNSAFE_KICK_LEASE_HELD", true, "Unsafe kick is held by another lease owner", { cause: error10 });
12072
+ } catch (error11) {
12073
+ throw new UnsafeWindowMaterializedViewError("UNSAFE_KICK_LEASE_HELD", true, "Unsafe kick is held by another lease owner", { cause: error11 });
11839
12074
  }
11840
12075
  const row = await this.database.prepare(`SELECT target_suid, dirty FROM mv_unsafe_kicks WHERE service_id = ? AND view_id = ?`).bind(serviceId, viewId).first();
11841
12076
  return row === null || row === void 0 ? void 0 : { targetSuid: string2(row, "target_suid"), dirty: integer(row, "dirty") === 1 };
@@ -11909,9 +12144,9 @@ var UnsafeWindowMaterializedViewStore = class {
11909
12144
  try {
11910
12145
  await this.database.batch(statements);
11911
12146
  return true;
11912
- } catch (error10) {
11913
- if (String(error10).includes("mv_atomic_guards") || String(error10).includes("checkpoint_match")) return false;
11914
- throw error10;
12147
+ } catch (error11) {
12148
+ if (String(error11).includes("mv_atomic_guards") || String(error11).includes("checkpoint_match")) return false;
12149
+ throw error11;
11915
12150
  }
11916
12151
  }
11917
12152
  /**
@@ -12077,12 +12312,12 @@ function indexValue(row, type) {
12077
12312
  function operationId2() {
12078
12313
  return `mv-${crypto.randomUUID()}`;
12079
12314
  }
12080
- function isCasFailure(error10) {
12081
- const message = String(error10);
12315
+ function isCasFailure(error11) {
12316
+ const message = String(error11);
12082
12317
  return message.includes("mv_atomic_guards.checkpoint_match") || message.includes("MV_CAS_MISMATCH");
12083
12318
  }
12084
- function isPatchFailure(error10) {
12085
- return String(error10).includes("CHECK constraint failed: checkpoint_match");
12319
+ function isPatchFailure(error11) {
12320
+ return String(error11).includes("CHECK constraint failed: checkpoint_match");
12086
12321
  }
12087
12322
  var D1MaterializedViewStore = class {
12088
12323
  constructor(database) {
@@ -12118,8 +12353,8 @@ var D1MaterializedViewStore = class {
12118
12353
  VALUES (?, ?, ?, ?)`
12119
12354
  ).bind(input.serviceId, input.viewId, generation, input.updatedAt)
12120
12355
  ]);
12121
- } catch (error10) {
12122
- throw new MaterializedViewStoreError("create-active", "MV_INSTANCE_EXISTS", `Active materialized view already exists: ${String(error10)}`, { cause: error10 });
12356
+ } catch (error11) {
12357
+ throw new MaterializedViewStoreError("create-active", "MV_INSTANCE_EXISTS", `Active materialized view already exists: ${String(error11)}`, { cause: error11 });
12123
12358
  }
12124
12359
  return this.readInstance(input.serviceId, input.viewId, generation);
12125
12360
  }
@@ -12140,8 +12375,8 @@ var D1MaterializedViewStore = class {
12140
12375
  input.definitionVersion,
12141
12376
  input.updatedAt
12142
12377
  ).run();
12143
- } catch (error10) {
12144
- throw new MaterializedViewStoreError("create-candidate", "MV_INSTANCE_EXISTS", `Candidate generation already exists: ${String(error10)}`, { cause: error10 });
12378
+ } catch (error11) {
12379
+ throw new MaterializedViewStoreError("create-candidate", "MV_INSTANCE_EXISTS", `Candidate generation already exists: ${String(error11)}`, { cause: error11 });
12145
12380
  }
12146
12381
  return this.readInstance(input.serviceId, input.viewId, input.generation);
12147
12382
  }
@@ -12279,10 +12514,10 @@ var D1MaterializedViewStore = class {
12279
12514
  */
12280
12515
  async readListPage(serviceId, viewId, options = {}) {
12281
12516
  this.ready("initialize");
12282
- const active = await this.readActive(serviceId, viewId);
12283
- if (active === void 0) return { rows: [], totalCount: 0, readHead: "" };
12284
- const selected = options.generation ?? active.generation;
12285
- const selectedInstance = selected === active.generation ? active : await this.readInstance(serviceId, viewId, selected);
12517
+ const active2 = await this.readActive(serviceId, viewId);
12518
+ if (active2 === void 0) return { rows: [], totalCount: 0, readHead: "" };
12519
+ const selected = options.generation ?? active2.generation;
12520
+ const selectedInstance = selected === active2.generation ? active2 : await this.readInstance(serviceId, viewId, selected);
12286
12521
  if (selectedInstance === void 0) {
12287
12522
  throw new MaterializedViewStoreError("initialize", "MV_INSTANCE_MISSING", "Requested materialized-view generation is unavailable");
12288
12523
  }
@@ -12799,10 +13034,10 @@ var D1MaterializedViewStore = class {
12799
13034
  ).bind(operation2, `${operation2}:%`));
12800
13035
  try {
12801
13036
  await this.database.batch(statements);
12802
- } catch (error10) {
12803
- if (isPatchFailure(error10)) throw new MaterializedViewPatchError();
12804
- if (isCasFailure(error10)) throw new MaterializedViewCasError();
12805
- throw new MaterializedViewStoreError("apply", "MV_STORE_OPERATION_FAILED", `Materialized-view atomic apply failed: ${String(error10)}`, { cause: error10 });
13037
+ } catch (error11) {
13038
+ if (isPatchFailure(error11)) throw new MaterializedViewPatchError();
13039
+ if (isCasFailure(error11)) throw new MaterializedViewCasError();
13040
+ throw new MaterializedViewStoreError("apply", "MV_STORE_OPERATION_FAILED", `Materialized-view atomic apply failed: ${String(error11)}`, { cause: error11 });
12806
13041
  }
12807
13042
  const instance = await this.readInstance(input.serviceId, input.viewId, input.generation);
12808
13043
  if (instance === void 0) throw new MaterializedViewStoreError("apply", "MV_INSTANCE_MISSING", "Materialized-view instance disappeared after apply");
@@ -12907,13 +13142,13 @@ var D1MaterializedViewStore = class {
12907
13142
  ];
12908
13143
  try {
12909
13144
  await this.database.batch(statements);
12910
- } catch (error10) {
12911
- if (isCasFailure(error10)) throw new MaterializedViewPromotionCasError();
12912
- throw new MaterializedViewStoreError("promote", "MV_STORE_OPERATION_FAILED", `Materialized-view promotion failed: ${String(error10)}`, { cause: error10 });
13145
+ } catch (error11) {
13146
+ if (isCasFailure(error11)) throw new MaterializedViewPromotionCasError();
13147
+ throw new MaterializedViewStoreError("promote", "MV_STORE_OPERATION_FAILED", `Materialized-view promotion failed: ${String(error11)}`, { cause: error11 });
12913
13148
  }
12914
- const active = await this.readActive(input.serviceId, input.viewId);
12915
- if (active === void 0) throw new MaterializedViewStoreError("promote", "MV_INSTANCE_MISSING", "Active generation disappeared after promotion");
12916
- return active;
13149
+ const active2 = await this.readActive(input.serviceId, input.viewId);
13150
+ if (active2 === void 0) throw new MaterializedViewStoreError("promote", "MV_INSTANCE_MISSING", "Active generation disappeared after promotion");
13151
+ return active2;
12917
13152
  }
12918
13153
  /** Short aliases make the port convenient for runtime composition and tests. */
12919
13154
  apply = this.applyMutationsAndAdvanceCheckpoint.bind(this);
@@ -12922,8 +13157,8 @@ var D1MaterializedViewStore = class {
12922
13157
  let value;
12923
13158
  try {
12924
13159
  value = assertJsonValue(JSON.parse(asString4(row.value_json, "value_json")), "state-persistence");
12925
- } catch (error10) {
12926
- throw new MaterializedViewStoreError("initialize", "MV_VALUE_INVALID", `Materialized-view row JSON was invalid: ${String(error10)}`, { cause: error10 });
13160
+ } catch (error11) {
13161
+ throw new MaterializedViewStoreError("initialize", "MV_VALUE_INVALID", `Materialized-view row JSON was invalid: ${String(error11)}`, { cause: error11 });
12927
13162
  }
12928
13163
  return {
12929
13164
  serviceId: asString4(row.service_id, "service_id"),
@@ -13047,8 +13282,8 @@ function stateFromCheckpoint(projector, checkpoint) {
13047
13282
  if (checkpoint === void 0) return projector.initialState();
13048
13283
  try {
13049
13284
  return projector.deserializeState(checkpoint.stateJson);
13050
- } catch (error10) {
13051
- throw new ProjectionCheckpointCorruption(error10);
13285
+ } catch (error11) {
13286
+ throw new ProjectionCheckpointCorruption(error11);
13052
13287
  }
13053
13288
  }
13054
13289
  function projectionEventFromStored(event) {
@@ -13279,8 +13514,8 @@ async function admitBootstrapRoute2(env, serviceId) {
13279
13514
  })).fetch(new Request(url, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ route: "projection-rebuild" }) }));
13280
13515
  if (!admitted.ok) throw new Error("bootstrap_route_rejected:projection-rebuild");
13281
13516
  }
13282
- function boundedErrorReason(error10) {
13283
- const value = error10 instanceof Error ? error10.message : String(error10);
13517
+ function boundedErrorReason(error11) {
13518
+ const value = error11 instanceof Error ? error11.message : String(error11);
13284
13519
  return value.length > 256 ? `${value.slice(0, 253)}...` : value;
13285
13520
  }
13286
13521
  async function notifyObserver(observer, callback, input) {
@@ -13293,7 +13528,7 @@ async function notifyObserver(observer, callback, input) {
13293
13528
  } catch {
13294
13529
  }
13295
13530
  }
13296
- async function notifyOutcomes(observer, serviceId, projectorIds, attemptedAt, results, maximumSuid, env, error10) {
13531
+ async function notifyOutcomes(observer, serviceId, projectorIds, attemptedAt, results, maximumSuid, env, error11) {
13297
13532
  if (observer?.onOutcome === void 0) return;
13298
13533
  const byProjector = /* @__PURE__ */ new Map();
13299
13534
  for (const result2 of results) {
@@ -13306,9 +13541,9 @@ async function notifyOutcomes(observer, serviceId, projectorIds, attemptedAt, re
13306
13541
  let outcome = "invoked-but-no-work";
13307
13542
  let reason = null;
13308
13543
  let advancedSourceEvents = 0;
13309
- if (error10 !== void 0) {
13544
+ if (error11 !== void 0) {
13310
13545
  outcome = "invoked-and-threw";
13311
- reason = boundedErrorReason(error10);
13546
+ reason = boundedErrorReason(error11);
13312
13547
  } else {
13313
13548
  advancedSourceEvents = projectorResults.reduce((total, result2) => total + result2.advancedSourceEvents, 0);
13314
13549
  if (advancedSourceEvents > 0) {
@@ -13410,9 +13645,9 @@ async function pollLiveProjections(env, options = {}) {
13410
13645
  const results = await runtime.pollRegistered(serviceId, attemptedAt, options.maximumSuid);
13411
13646
  await notifyOutcomes(options.observer, serviceId, projectorIds, attemptedAt, results, options.maximumSuid, env);
13412
13647
  return results;
13413
- } catch (error10) {
13414
- await notifyOutcomes(options.observer, serviceId, projectorIds, attemptedAt, [], options.maximumSuid, env, error10);
13415
- throw error10;
13648
+ } catch (error11) {
13649
+ await notifyOutcomes(options.observer, serviceId, projectorIds, attemptedAt, [], options.maximumSuid, env, error11);
13650
+ throw error11;
13416
13651
  }
13417
13652
  }
13418
13653
  async function handleProjectionLag(request, env, registry = DEPLOYED_PROJECTOR_REGISTRY, storeProvider, serviceIdentityProvider) {
@@ -14230,10 +14465,10 @@ var SerializedReadWorker = class {
14230
14465
  });
14231
14466
  }
14232
14467
  async ensureWindowDeterminate() {
14233
- if (this.storeProvider === void 0 || this.storeProvider.isConfigured?.(this.env) === false) {
14234
- return;
14235
- }
14236
14468
  try {
14469
+ if (this.storeProvider === void 0 || this.storeProvider.isConfigured?.(this.env) === false) {
14470
+ return;
14471
+ }
14237
14472
  const store = this.storeProvider.create(this.env);
14238
14473
  await store.initialize();
14239
14474
  const nowMs = Date.now();
@@ -14274,13 +14509,683 @@ async function handleSerializedRead(request, env, registry = DEPLOYED_PROJECTOR_
14274
14509
  }), registry, storeProvider).handle(request);
14275
14510
  }
14276
14511
 
14512
+ // src/completeness/IncidentLifecycle.ts
14513
+ var MAX_IDENTITY_BYTES = 256;
14514
+ var MAX_LONG_TEXT_BYTES = 2048;
14515
+ var SHA256_DIGEST = /^sha256:[0-9a-f]{64}$/;
14516
+ var IncidentLifecycleError = class extends Error {
14517
+ code;
14518
+ status;
14519
+ constructor(code, status, message) {
14520
+ super(message);
14521
+ this.name = "IncidentLifecycleError";
14522
+ this.code = code;
14523
+ this.status = status;
14524
+ }
14525
+ };
14526
+ function isObject11(value) {
14527
+ return typeof value === "object" && value !== null && !Array.isArray(value);
14528
+ }
14529
+ function hasOnlyKeys(value, keys) {
14530
+ const allowed = new Set(keys);
14531
+ return Object.keys(value).every((key) => allowed.has(key));
14532
+ }
14533
+ function bytes(value) {
14534
+ return new TextEncoder().encode(value).byteLength;
14535
+ }
14536
+ function boundedString(value, name, maximum, required = true) {
14537
+ if (typeof value !== "string") {
14538
+ throw new IncidentLifecycleError("incident_invalid_request", 400, `${name} must be a string`);
14539
+ }
14540
+ const normalized = value.trim();
14541
+ if (required && normalized.length === 0) {
14542
+ throw new IncidentLifecycleError("incident_invalid_request", 400, `${name} must be non-empty`);
14543
+ }
14544
+ if (bytes(normalized) > maximum) {
14545
+ throw new IncidentLifecycleError("incident_invalid_request", 400, `${name} is too long`);
14546
+ }
14547
+ return normalized.length === 0 ? null : normalized;
14548
+ }
14549
+ function normalizeIncidentIdentity(value) {
14550
+ const identity2 = boundedString(value, "incidentIdentity", MAX_IDENTITY_BYTES);
14551
+ if (identity2 === null) {
14552
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "incidentIdentity must be non-empty");
14553
+ }
14554
+ return identity2;
14555
+ }
14556
+ function safeInteger(value, name) {
14557
+ if (typeof value !== "number" || !Number.isSafeInteger(value)) {
14558
+ throw new IncidentLifecycleError("incident_invalid_request", 400, `${name} must be a safe integer`);
14559
+ }
14560
+ return value;
14561
+ }
14562
+ function normalizeCorrection(value) {
14563
+ if (!isObject11(value) || !hasOnlyKeys(value, ["kind", "reference", "digest"])) {
14564
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "correction has unknown or missing keys");
14565
+ }
14566
+ if (value.kind !== "event" && value.kind !== "receipt") {
14567
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "correction.kind must be event or receipt");
14568
+ }
14569
+ const reference = boundedString(value.reference, "correction.reference", MAX_LONG_TEXT_BYTES);
14570
+ const digest2 = boundedString(value.digest, "correction.digest", MAX_IDENTITY_BYTES);
14571
+ if (reference === null || digest2 === null || !SHA256_DIGEST.test(digest2)) {
14572
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "correction.digest must be lowercase sha256");
14573
+ }
14574
+ return { kind: value.kind, reference, digest: digest2 };
14575
+ }
14576
+ function normalizeRequest(value) {
14577
+ if (!isObject11(value) || !hasOnlyKeys(value, ["action", "incidentIdentity", "transitionKey", "expectedVersion", "reason", "ownerId", "deadlineAt", "correction", "resolution"])) {
14578
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "transition has unknown keys");
14579
+ }
14580
+ const action = value.action;
14581
+ if (typeof action !== "string" || !["ACKNOWLEDGE", "UPDATE_ASSIGNMENT", "RECORD_CORRECTION", "CLOSE", "REOPEN"].includes(action)) {
14582
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "transition action is invalid");
14583
+ }
14584
+ 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"];
14585
+ if (!hasOnlyKeys(value, actionKeys)) {
14586
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "transition has keys not valid for its action");
14587
+ }
14588
+ const base = {
14589
+ incidentIdentity: normalizeIncidentIdentity(value.incidentIdentity),
14590
+ transitionKey: boundedString(value.transitionKey, "transitionKey", MAX_IDENTITY_BYTES),
14591
+ expectedVersion: safeInteger(value.expectedVersion, "expectedVersion"),
14592
+ reason: boundedString(value.reason, "reason", MAX_LONG_TEXT_BYTES)
14593
+ };
14594
+ if (base.expectedVersion < 0) {
14595
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "expectedVersion must not be negative");
14596
+ }
14597
+ if (action === "ACKNOWLEDGE" || action === "UPDATE_ASSIGNMENT" || action === "REOPEN") {
14598
+ const ownerId = boundedString(value.ownerId, "ownerId", MAX_IDENTITY_BYTES);
14599
+ const deadlineAt = safeInteger(value.deadlineAt, "deadlineAt");
14600
+ if (ownerId === null) throw new IncidentLifecycleError("incident_invalid_request", 400, "ownerId must be non-empty");
14601
+ return { ...base, action, ownerId, deadlineAt };
14602
+ }
14603
+ if (action === "RECORD_CORRECTION") {
14604
+ return { ...base, action, correction: normalizeCorrection(value.correction) };
14605
+ }
14606
+ if (!isObject11(value.resolution) || !hasOnlyKeys(value.resolution, ["kind", "explanation"])) {
14607
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "resolution has unknown or missing keys");
14608
+ }
14609
+ if (value.resolution.kind === "CORRECTED") {
14610
+ if (value.resolution.explanation !== void 0) {
14611
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "CORRECTED resolution has unknown keys");
14612
+ }
14613
+ return { ...base, action, resolution: { kind: "CORRECTED" } };
14614
+ }
14615
+ if (value.resolution.kind === "ACCEPTED_AS_IS") {
14616
+ const explanation = boundedString(value.resolution.explanation, "resolution.explanation", MAX_LONG_TEXT_BYTES);
14617
+ if (explanation === null) throw new IncidentLifecycleError("incident_invalid_request", 400, "resolution.explanation is required");
14618
+ return { ...base, action, resolution: { kind: "ACCEPTED_AS_IS", explanation } };
14619
+ }
14620
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "resolution.kind is invalid");
14621
+ }
14622
+ function canonicalize(value) {
14623
+ if (Array.isArray(value)) return value.map(canonicalize);
14624
+ if (!isObject11(value)) return value;
14625
+ return Object.fromEntries(Object.keys(value).sort().map((key) => [key, canonicalize(value[key])]));
14626
+ }
14627
+ async function digestFor(request, actorId) {
14628
+ const envelope = canonicalize({ action: request, actor: actorId });
14629
+ const encoded = new TextEncoder().encode(JSON.stringify(envelope));
14630
+ const digest2 = await crypto.subtle.digest("SHA-256", encoded);
14631
+ return `sha256:${Array.from(new Uint8Array(digest2), (byte) => byte.toString(16).padStart(2, "0")).join("")}`;
14632
+ }
14633
+ function projectionFromRow(row, finding2) {
14634
+ if (row === null) {
14635
+ return {
14636
+ serviceId: finding2.service_id,
14637
+ incidentIdentity: finding2.incident_identity,
14638
+ lifecycleState: "OPEN",
14639
+ ownerId: null,
14640
+ deadlineAt: null,
14641
+ correction: null,
14642
+ closeResolution: null,
14643
+ closeReason: null,
14644
+ version: 0,
14645
+ lastTransitionKey: "",
14646
+ updatedAt: finding2.last_observed_at
14647
+ };
14648
+ }
14649
+ return {
14650
+ serviceId: row.service_id,
14651
+ incidentIdentity: row.incident_identity,
14652
+ lifecycleState: row.lifecycle_state,
14653
+ ownerId: row.owner_id,
14654
+ deadlineAt: row.deadline_at,
14655
+ correction: row.correction_kind === null ? null : {
14656
+ kind: row.correction_kind,
14657
+ reference: row.correction_reference,
14658
+ digest: row.correction_digest
14659
+ },
14660
+ closeResolution: row.close_resolution,
14661
+ closeReason: row.close_reason,
14662
+ version: row.version,
14663
+ lastTransitionKey: row.last_transition_key,
14664
+ updatedAt: row.updated_at
14665
+ };
14666
+ }
14667
+ function findingFromRow(row) {
14668
+ return {
14669
+ serviceId: row.service_id,
14670
+ incidentIdentity: row.incident_identity,
14671
+ incidentType: row.incident_type,
14672
+ partitionTag: row.partition_tag,
14673
+ obligationSequence: row.obligation_sequence,
14674
+ eventId: row.event_id,
14675
+ eventDigest: row.event_digest,
14676
+ state: row.finding_state,
14677
+ firstObservedAt: row.first_observed_at,
14678
+ lastObservedAt: row.last_observed_at
14679
+ };
14680
+ }
14681
+ function transitionFromRow(row) {
14682
+ const before = projectionFromAudit(row, "before");
14683
+ const after = projectionFromAudit(row, "after");
14684
+ return {
14685
+ transitionId: row.transition_id,
14686
+ serviceId: row.service_id,
14687
+ incidentIdentity: row.incident_identity,
14688
+ transitionKey: row.transition_key,
14689
+ requestDigest: row.request_digest,
14690
+ action: row.action,
14691
+ fromState: row.from_state,
14692
+ toState: row.to_state,
14693
+ fromVersion: row.from_version,
14694
+ toVersion: row.to_version,
14695
+ actorId: row.actor_id,
14696
+ before,
14697
+ after,
14698
+ reason: row.reason,
14699
+ occurredAt: row.occurred_at
14700
+ };
14701
+ }
14702
+ function projectionFromAudit(row, prefix) {
14703
+ const state = prefix === "before" ? row.from_state : row.to_state;
14704
+ const version = prefix === "before" ? row.from_version : row.to_version;
14705
+ const ownerId = row[`${prefix}_owner_id`];
14706
+ const correctionKind = row[`${prefix}_correction_kind`];
14707
+ return {
14708
+ serviceId: row.service_id,
14709
+ incidentIdentity: row.incident_identity,
14710
+ lifecycleState: state,
14711
+ ownerId,
14712
+ deadlineAt: row[`${prefix}_deadline_at`],
14713
+ correction: correctionKind === null ? null : {
14714
+ kind: correctionKind,
14715
+ reference: row[`${prefix}_correction_reference`],
14716
+ digest: row[`${prefix}_correction_digest`]
14717
+ },
14718
+ closeResolution: row[`${prefix}_close_resolution`],
14719
+ closeReason: row[`${prefix}_close_reason`],
14720
+ version,
14721
+ lastTransitionKey: prefix === "after" ? row.transition_key : "",
14722
+ updatedAt: row.occurred_at
14723
+ };
14724
+ }
14725
+ function active(state) {
14726
+ return state !== "CLOSED";
14727
+ }
14728
+ function compareItems(left, right) {
14729
+ if (left.overdue !== right.overdue) return left.overdue ? -1 : 1;
14730
+ if (left.unowned !== right.unowned) return left.unowned ? -1 : 1;
14731
+ if (left.finding.lastObservedAt !== right.finding.lastObservedAt) return right.finding.lastObservedAt - left.finding.lastObservedAt;
14732
+ return left.finding.incidentIdentity < right.finding.incidentIdentity ? -1 : left.finding.incidentIdentity > right.finding.incidentIdentity ? 1 : 0;
14733
+ }
14734
+ var IncidentLifecycle = class {
14735
+ constructor(database, now2 = () => Date.now()) {
14736
+ this.database = database;
14737
+ this.now = now2;
14738
+ }
14739
+ database;
14740
+ now;
14741
+ static parseTransition(value) {
14742
+ return normalizeRequest(value);
14743
+ }
14744
+ async finding(serviceId, incidentIdentity) {
14745
+ const row = await this.database.prepare(
14746
+ `SELECT service_id, incident_identity, incident_type, partition_tag,
14747
+ obligation_sequence, event_id, event_digest, state AS finding_state,
14748
+ first_observed_at, last_observed_at
14749
+ FROM serialized_dcb_completeness_findings
14750
+ WHERE service_id = ? AND incident_identity = ?`
14751
+ ).bind(serviceId, incidentIdentity).first();
14752
+ if (row === null || row === void 0) {
14753
+ throw new IncidentLifecycleError("incident_not_found", 404, "The completeness incident was not found");
14754
+ }
14755
+ return row;
14756
+ }
14757
+ async lifecycle(serviceId, incidentIdentity) {
14758
+ const row = await this.database.prepare(
14759
+ `SELECT service_id, incident_identity, lifecycle_state, owner_id, deadline_at,
14760
+ correction_kind, correction_reference, correction_digest,
14761
+ close_resolution, close_reason, version, last_transition_key, updated_at
14762
+ FROM serialized_dcb_incident_lifecycles
14763
+ WHERE service_id = ? AND incident_identity = ?`
14764
+ ).bind(serviceId, incidentIdentity).first();
14765
+ return row === void 0 ? null : row;
14766
+ }
14767
+ async transitions(serviceId, incidentIdentity) {
14768
+ const result2 = await this.database.prepare(
14769
+ `SELECT * FROM serialized_dcb_incident_transitions
14770
+ WHERE service_id = ? AND incident_identity = ?
14771
+ ORDER BY transition_id ASC`
14772
+ ).bind(serviceId, incidentIdentity).all();
14773
+ return result2.results.map(transitionFromRow);
14774
+ }
14775
+ async closeTime(serviceId, incidentIdentity) {
14776
+ const row = await this.database.prepare(
14777
+ `SELECT occurred_at FROM serialized_dcb_incident_transitions
14778
+ WHERE service_id = ? AND incident_identity = ? AND to_state = 'CLOSED'
14779
+ ORDER BY transition_id DESC LIMIT 1`
14780
+ ).bind(serviceId, incidentIdentity).first();
14781
+ return row?.occurred_at ?? null;
14782
+ }
14783
+ async item(finding2, row, at) {
14784
+ const lifecycle = projectionFromRow(row, finding2);
14785
+ const closeTime = lifecycle.lifecycleState === "OPEN" && row === null ? null : await this.closeTime(finding2.service_id, finding2.incident_identity);
14786
+ const observedAfterClose = closeTime !== null && finding2.last_observed_at > closeTime;
14787
+ const overdue = active(lifecycle.lifecycleState) && lifecycle.deadlineAt !== null && lifecycle.deadlineAt < at;
14788
+ return {
14789
+ finding: findingFromRow(finding2),
14790
+ lifecycle,
14791
+ overdue,
14792
+ unowned: lifecycle.ownerId === null,
14793
+ observedAfterClose
14794
+ };
14795
+ }
14796
+ async list(serviceId, filters = {}, at = this.now()) {
14797
+ const rows = await this.database.prepare(
14798
+ `SELECT service_id, incident_identity, incident_type, partition_tag,
14799
+ obligation_sequence, event_id, event_digest, state AS finding_state,
14800
+ first_observed_at, last_observed_at
14801
+ FROM serialized_dcb_completeness_findings
14802
+ WHERE service_id = ?`
14803
+ ).bind(serviceId).all();
14804
+ const items = [];
14805
+ for (const finding2 of rows.results) {
14806
+ const item = await this.item(finding2, await this.lifecycle(serviceId, finding2.incident_identity), at);
14807
+ if (filters.state !== void 0 && item.lifecycle.lifecycleState !== filters.state) continue;
14808
+ if (filters.owner !== void 0 && item.lifecycle.ownerId !== filters.owner) continue;
14809
+ if (filters.unowned === true && !item.unowned) continue;
14810
+ if (filters.overdue === true && !item.overdue) continue;
14811
+ if (filters.observedAfterClose === true && !item.observedAfterClose) continue;
14812
+ items.push(item);
14813
+ }
14814
+ items.sort(compareItems);
14815
+ const byState = {
14816
+ OPEN: 0,
14817
+ ACKNOWLEDGED: 0,
14818
+ CORRECTION_RECORDED: 0,
14819
+ CLOSED: 0,
14820
+ REOPENED: 0
14821
+ };
14822
+ for (const item of items) byState[item.lifecycle.lifecycleState] += 1;
14823
+ return {
14824
+ items,
14825
+ summary: {
14826
+ total: items.length,
14827
+ byState,
14828
+ unowned: items.filter((item) => item.unowned).length,
14829
+ overdue: items.filter((item) => item.overdue).length,
14830
+ observedAfterClose: items.filter((item) => item.observedAfterClose).length
14831
+ }
14832
+ };
14833
+ }
14834
+ async detail(serviceId, incidentIdentity, at = this.now()) {
14835
+ const finding2 = await this.finding(serviceId, incidentIdentity);
14836
+ const lifecycle = await this.lifecycle(serviceId, incidentIdentity);
14837
+ const item = await this.item(finding2, lifecycle, at);
14838
+ return {
14839
+ finding: item.finding,
14840
+ lifecycle: item.lifecycle,
14841
+ flags: { overdue: item.overdue, unowned: item.unowned, observedAfterClose: item.observedAfterClose },
14842
+ transitions: await this.transitions(serviceId, incidentIdentity)
14843
+ };
14844
+ }
14845
+ async transition(serviceId, value, actor) {
14846
+ const request = normalizeRequest(value);
14847
+ let actorId;
14848
+ try {
14849
+ actorId = boundedString(actor, "x-sdt-maintainer", MAX_IDENTITY_BYTES);
14850
+ } catch (caught) {
14851
+ if (caught instanceof IncidentLifecycleError && caught.code === "incident_invalid_request") {
14852
+ throw new IncidentLifecycleError("incident_invalid_actor", 400, caught.message);
14853
+ }
14854
+ throw caught;
14855
+ }
14856
+ if (actorId === null) throw new IncidentLifecycleError("incident_invalid_actor", 400, "x-sdt-maintainer must be non-empty");
14857
+ const finding2 = await this.finding(serviceId, request.incidentIdentity);
14858
+ const digest2 = await digestFor(request, actorId);
14859
+ const existing = await this.database.prepare(
14860
+ `SELECT * FROM serialized_dcb_incident_transitions
14861
+ WHERE service_id = ? AND incident_identity = ? AND transition_key = ?`
14862
+ ).bind(serviceId, request.incidentIdentity, request.transitionKey).first();
14863
+ if (existing !== null && existing !== void 0) {
14864
+ if (existing.request_digest !== digest2) {
14865
+ throw new IncidentLifecycleError("incident_idempotency_conflict", 409, "The transition key was already used with different content");
14866
+ }
14867
+ return { projection: transitionFromRow(existing).after, transition: transitionFromRow(existing), idempotent: true };
14868
+ }
14869
+ const priorRow = await this.lifecycle(serviceId, request.incidentIdentity);
14870
+ const before = projectionFromRow(priorRow, finding2);
14871
+ if (before.version !== request.expectedVersion) {
14872
+ throw new IncidentLifecycleError("incident_version_conflict", 409, "The incident version is stale");
14873
+ }
14874
+ const at = this.now();
14875
+ const after = this.nextProjection(before, request, at);
14876
+ const newVersion = before.version + 1;
14877
+ const occurredAt = at;
14878
+ const seed = this.database.prepare(
14879
+ `INSERT INTO serialized_dcb_incident_lifecycles
14880
+ (service_id, incident_identity, lifecycle_state, version, last_transition_key, updated_at)
14881
+ VALUES (?, ?, 'OPEN', 0, '', ?)
14882
+ ON CONFLICT (service_id, incident_identity) DO NOTHING`
14883
+ ).bind(serviceId, request.incidentIdentity, occurredAt);
14884
+ const update = this.database.prepare(
14885
+ `UPDATE serialized_dcb_incident_lifecycles
14886
+ SET lifecycle_state = ?, owner_id = ?, deadline_at = ?,
14887
+ correction_kind = ?, correction_reference = ?, correction_digest = ?,
14888
+ close_resolution = ?, close_reason = ?, version = ?,
14889
+ last_transition_key = ?, updated_at = ?
14890
+ WHERE service_id = ? AND incident_identity = ? AND version = ?
14891
+ AND last_transition_key <> ?`
14892
+ ).bind(
14893
+ after.lifecycleState,
14894
+ after.ownerId,
14895
+ after.deadlineAt,
14896
+ after.correction?.kind ?? null,
14897
+ after.correction?.reference ?? null,
14898
+ after.correction?.digest ?? null,
14899
+ after.closeResolution,
14900
+ after.closeReason,
14901
+ newVersion,
14902
+ request.transitionKey,
14903
+ occurredAt,
14904
+ serviceId,
14905
+ request.incidentIdentity,
14906
+ before.version,
14907
+ request.transitionKey
14908
+ );
14909
+ const audit = this.database.prepare(
14910
+ `INSERT INTO serialized_dcb_incident_transitions
14911
+ (service_id, incident_identity, transition_key, request_digest, action,
14912
+ from_state, to_state, from_version, to_version, actor_id,
14913
+ before_owner_id, before_deadline_at, before_correction_kind,
14914
+ before_correction_reference, before_correction_digest, before_close_resolution,
14915
+ before_close_reason, after_owner_id, after_deadline_at, after_correction_kind,
14916
+ after_correction_reference, after_correction_digest, after_close_resolution,
14917
+ after_close_reason, reason, occurred_at)
14918
+ SELECT ?, ?, ?, ?, ?, ?, lifecycle_state, ?, version, ?,
14919
+ ?, ?, ?, ?, ?, ?, ?, owner_id, deadline_at, correction_kind,
14920
+ correction_reference, correction_digest, close_resolution, close_reason, ?, ?
14921
+ FROM serialized_dcb_incident_lifecycles
14922
+ WHERE service_id = ? AND incident_identity = ? AND version = ? AND last_transition_key = ?`
14923
+ ).bind(
14924
+ serviceId,
14925
+ request.incidentIdentity,
14926
+ request.transitionKey,
14927
+ digest2,
14928
+ request.action,
14929
+ before.lifecycleState,
14930
+ before.version,
14931
+ actorId,
14932
+ before.ownerId,
14933
+ before.deadlineAt,
14934
+ before.correction?.kind ?? null,
14935
+ before.correction?.reference ?? null,
14936
+ before.correction?.digest ?? null,
14937
+ before.closeResolution,
14938
+ before.closeReason,
14939
+ request.reason,
14940
+ occurredAt,
14941
+ serviceId,
14942
+ request.incidentIdentity,
14943
+ newVersion,
14944
+ request.transitionKey
14945
+ );
14946
+ await this.database.batch([seed, update, audit]);
14947
+ const inserted = await this.database.prepare(
14948
+ `SELECT * FROM serialized_dcb_incident_transitions
14949
+ WHERE service_id = ? AND incident_identity = ? AND transition_key = ?`
14950
+ ).bind(serviceId, request.incidentIdentity, request.transitionKey).first();
14951
+ if (inserted === null || inserted === void 0) {
14952
+ const competing = await this.database.prepare(
14953
+ `SELECT * FROM serialized_dcb_incident_transitions
14954
+ WHERE service_id = ? AND incident_identity = ? AND transition_key = ?`
14955
+ ).bind(serviceId, request.incidentIdentity, request.transitionKey).first();
14956
+ if (competing !== null && competing !== void 0 && competing.request_digest !== digest2) {
14957
+ throw new IncidentLifecycleError("incident_idempotency_conflict", 409, "The transition key was already used with different content");
14958
+ }
14959
+ if (competing !== null && competing !== void 0) {
14960
+ const transition2 = transitionFromRow(competing);
14961
+ return { projection: transition2.after, transition: transition2, idempotent: true };
14962
+ }
14963
+ throw new IncidentLifecycleError("incident_version_conflict", 409, "The incident version is stale");
14964
+ }
14965
+ const transition = transitionFromRow(inserted);
14966
+ return { projection: transition.after, transition, idempotent: false };
14967
+ }
14968
+ nextProjection(before, request, at) {
14969
+ const laterDeadline = (deadlineAt2) => {
14970
+ if (deadlineAt2 <= at) throw new IncidentLifecycleError("incident_invalid_deadline", 400, "deadlineAt must be in the future");
14971
+ return deadlineAt2;
14972
+ };
14973
+ let lifecycleState;
14974
+ let ownerId = before.ownerId;
14975
+ let deadlineAt = before.deadlineAt;
14976
+ let correction = before.correction;
14977
+ let closeResolution = before.closeResolution;
14978
+ let closeReason = before.closeReason;
14979
+ if (request.action === "ACKNOWLEDGE") {
14980
+ if (before.lifecycleState !== "OPEN" && before.lifecycleState !== "REOPENED") {
14981
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "The incident cannot be acknowledged from its current state");
14982
+ }
14983
+ lifecycleState = "ACKNOWLEDGED";
14984
+ ownerId = request.ownerId;
14985
+ deadlineAt = laterDeadline(request.deadlineAt);
14986
+ correction = null;
14987
+ closeResolution = null;
14988
+ closeReason = null;
14989
+ } else if (request.action === "UPDATE_ASSIGNMENT") {
14990
+ if (before.lifecycleState !== "ACKNOWLEDGED" && before.lifecycleState !== "CORRECTION_RECORDED") {
14991
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "The incident cannot be reassigned from its current state");
14992
+ }
14993
+ lifecycleState = before.lifecycleState;
14994
+ ownerId = request.ownerId;
14995
+ deadlineAt = laterDeadline(request.deadlineAt);
14996
+ } else if (request.action === "RECORD_CORRECTION") {
14997
+ if (before.lifecycleState !== "ACKNOWLEDGED") {
14998
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "The incident must be acknowledged before correction evidence");
14999
+ }
15000
+ lifecycleState = "CORRECTION_RECORDED";
15001
+ correction = request.correction;
15002
+ } else if (request.action === "CLOSE") {
15003
+ if (before.ownerId === null || before.deadlineAt === null) {
15004
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "The incident must have an owner and deadline before closure");
15005
+ }
15006
+ if (request.resolution.kind === "CORRECTED") {
15007
+ if (before.lifecycleState !== "CORRECTION_RECORDED") {
15008
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "A corrected closure requires recorded correction evidence");
15009
+ }
15010
+ lifecycleState = "CLOSED";
15011
+ closeResolution = "CORRECTED";
15012
+ closeReason = request.reason;
15013
+ } else {
15014
+ if (before.lifecycleState !== "ACKNOWLEDGED") {
15015
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "Accepted-as-is closure requires an acknowledged incident");
15016
+ }
15017
+ lifecycleState = "CLOSED";
15018
+ closeResolution = "ACCEPTED_AS_IS";
15019
+ closeReason = request.resolution.explanation;
15020
+ correction = null;
15021
+ }
15022
+ } else {
15023
+ if (before.lifecycleState !== "CLOSED") {
15024
+ throw new IncidentLifecycleError("incident_invalid_transition", 409, "Only a closed incident can be reopened");
15025
+ }
15026
+ lifecycleState = "REOPENED";
15027
+ ownerId = request.ownerId;
15028
+ deadlineAt = laterDeadline(request.deadlineAt);
15029
+ correction = null;
15030
+ closeResolution = null;
15031
+ closeReason = null;
15032
+ }
15033
+ return {
15034
+ ...before,
15035
+ lifecycleState,
15036
+ ownerId,
15037
+ deadlineAt,
15038
+ correction,
15039
+ closeResolution,
15040
+ closeReason,
15041
+ version: before.version + 1,
15042
+ lastTransitionKey: request.transitionKey,
15043
+ updatedAt: at
15044
+ };
15045
+ }
15046
+ };
15047
+
15048
+ // src/http/IncidentMaintenance.ts
15049
+ function json10(body, status = 200) {
15050
+ return new Response(JSON.stringify(body), {
15051
+ status,
15052
+ headers: { "content-type": "application/json; charset=utf-8" }
15053
+ });
15054
+ }
15055
+ function error8(status, code, message) {
15056
+ return json10({ error: message, code }, status);
15057
+ }
15058
+ function configuredToken(value) {
15059
+ if (typeof value !== "string") return void 0;
15060
+ const token = value.trim();
15061
+ return token.length === 0 ? void 0 : token;
15062
+ }
15063
+ async function digest(value) {
15064
+ const bytes2 = new TextEncoder().encode(value);
15065
+ return new Uint8Array(await crypto.subtle.digest("SHA-256", bytes2));
15066
+ }
15067
+ function fixedLengthEqual(left, right) {
15068
+ let difference = left.length ^ right.length;
15069
+ const length = Math.max(left.length, right.length);
15070
+ for (let index = 0; index < length; index += 1) {
15071
+ difference |= (left[index] ?? 0) ^ (right[index] ?? 0);
15072
+ }
15073
+ return difference === 0;
15074
+ }
15075
+ async function authenticated(request, token) {
15076
+ const credential = request.headers.get("authorization") ?? "";
15077
+ const suppliedToken = credential.startsWith("Bearer ") ? credential.slice("Bearer ".length) : "";
15078
+ const [expectedDigest, suppliedDigest] = await Promise.all([digest(token), digest(suppliedToken)]);
15079
+ return fixedLengthEqual(expectedDigest, suppliedDigest);
15080
+ }
15081
+ function boolFilter(value, name) {
15082
+ if (value === null) return void 0;
15083
+ if (value === "true") return true;
15084
+ if (value === "false") return false;
15085
+ throw new IncidentLifecycleError("incident_invalid_filter", 400, `${name} must be true or false`);
15086
+ }
15087
+ function parseFilters(url) {
15088
+ const allowed = /* @__PURE__ */ new Set(["state", "owner", "unowned", "overdue", "observedAfterClose"]);
15089
+ let unknown = false;
15090
+ url.searchParams.forEach((_value, key) => {
15091
+ if (!allowed.has(key)) unknown = true;
15092
+ });
15093
+ if (unknown) throw new IncidentLifecycleError("incident_invalid_filter", 400, "Unknown incident list filter");
15094
+ const state = url.searchParams.get("state");
15095
+ if (state !== null && !["OPEN", "ACKNOWLEDGED", "CORRECTION_RECORDED", "CLOSED", "REOPENED"].includes(state)) {
15096
+ throw new IncidentLifecycleError("incident_invalid_filter", 400, "state is invalid");
15097
+ }
15098
+ const owner = url.searchParams.get("owner");
15099
+ if (owner !== null) {
15100
+ const normalizedOwner = owner.trim();
15101
+ if (normalizedOwner.length === 0) {
15102
+ throw new IncidentLifecycleError("incident_invalid_filter", 400, "owner must be non-empty");
15103
+ }
15104
+ if (new TextEncoder().encode(normalizedOwner).byteLength > 256) {
15105
+ throw new IncidentLifecycleError("incident_invalid_filter", 400, "owner is too long");
15106
+ }
15107
+ }
15108
+ const unowned = boolFilter(url.searchParams.get("unowned"), "unowned");
15109
+ const overdue = boolFilter(url.searchParams.get("overdue"), "overdue");
15110
+ const observedAfterClose = boolFilter(url.searchParams.get("observedAfterClose"), "observedAfterClose");
15111
+ return {
15112
+ ...state === null ? {} : { state },
15113
+ ...owner === null ? {} : { owner: owner.trim() },
15114
+ ...unowned === void 0 ? {} : { unowned },
15115
+ ...overdue === void 0 ? {} : { overdue },
15116
+ ...observedAfterClose === void 0 ? {} : { observedAfterClose }
15117
+ };
15118
+ }
15119
+ function incidentIdentityFromPath(pathname) {
15120
+ const encoded = pathname.slice("/maintenance/incidents/".length);
15121
+ if (encoded.length === 0 || encoded.includes("/")) {
15122
+ throw new IncidentLifecycleError("incident_route_not_found", 404, "Incident route not found");
15123
+ }
15124
+ try {
15125
+ return normalizeIncidentIdentity(decodeURIComponent(encoded));
15126
+ } catch {
15127
+ throw new IncidentLifecycleError("incident_invalid_request", 400, "Incident identity must be URI encoded");
15128
+ }
15129
+ }
15130
+ function isIncidentMaintenancePath(pathname) {
15131
+ return pathname === "/maintenance/incidents" || pathname.startsWith("/maintenance/incidents/");
15132
+ }
15133
+ async function handleIncidentMaintenance(request, env, serviceIdentityProvider) {
15134
+ const token = configuredToken(env.INCIDENT_MAINTAINER_TOKEN);
15135
+ if (token === void 0) {
15136
+ return error8(503, "incident_maintenance_unavailable", "Incident maintenance is not configured");
15137
+ }
15138
+ if (!await authenticated(request, token)) {
15139
+ return error8(401, "incident_auth_required", "A valid incident maintenance bearer token is required");
15140
+ }
15141
+ let serviceId;
15142
+ try {
15143
+ serviceId = requestServiceIdentity(request, serviceIdentityProvider, {
15144
+ allowG11Verification: env.G11_VERIFICATION_ENABLED === "true"
15145
+ });
15146
+ } catch {
15147
+ return error8(503, "scope.identity_missing", "A deployment service identity is required for this scope");
15148
+ }
15149
+ if (env.D1 === void 0) {
15150
+ return error8(503, "incident_maintenance_unavailable", "Incident maintenance storage is unavailable");
15151
+ }
15152
+ const lifecycle = new IncidentLifecycle(env.D1);
15153
+ const url = new URL(request.url);
15154
+ try {
15155
+ if (request.method === "GET" && url.pathname === "/maintenance/incidents") {
15156
+ return json10(await lifecycle.list(serviceId, parseFilters(url)));
15157
+ }
15158
+ if (request.method === "GET" && url.pathname.startsWith("/maintenance/incidents/")) {
15159
+ return json10(await lifecycle.detail(serviceId, incidentIdentityFromPath(url.pathname)));
15160
+ }
15161
+ if (request.method === "POST" && url.pathname === "/maintenance/incidents/transitions") {
15162
+ let body;
15163
+ try {
15164
+ body = await request.json();
15165
+ } catch {
15166
+ return error8(400, "incident_invalid_request", "Transition request must be JSON");
15167
+ }
15168
+ const requestValue = IncidentLifecycle.parseTransition(body);
15169
+ const actor = request.headers.get("x-sdt-maintainer");
15170
+ if (actor === null) {
15171
+ return error8(400, "incident_invalid_actor", "x-sdt-maintainer is required");
15172
+ }
15173
+ return json10(await lifecycle.transition(serviceId, requestValue, actor));
15174
+ }
15175
+ return error8(404, "incident_route_not_found", "Incident maintenance route not found");
15176
+ } catch (caught) {
15177
+ if (caught instanceof IncidentLifecycleError) return error8(caught.status, caught.code, caught.message);
15178
+ return error8(500, "incident_maintenance_failed", "Incident maintenance could not complete the request");
15179
+ }
15180
+ }
15181
+
14277
15182
  // src/downstream/Doorbell.ts
14278
15183
  var MAX_SERVICE_BINDING_INVOCATIONS_PER_REQUEST = 32;
14279
- function classifyDirectDoorbellFailure(error10) {
14280
- const structured = typeof error10 === "object" && error10 !== null ? error10 : {};
15184
+ function classifyDirectDoorbellFailure(error11) {
15185
+ const structured = typeof error11 === "object" && error11 !== null ? error11 : {};
14281
15186
  const status = typeof structured.status === "number" ? structured.status : typeof structured.statusCode === "number" ? structured.statusCode : void 0;
14282
15187
  if (status !== void 0 && (status < 200 || status >= 300)) return "non-2xx";
14283
- const value = String(error10).toLowerCase();
15188
+ const value = String(error11).toLowerCase();
14284
15189
  const code = `${String(structured.code ?? "")} ${String(structured.name ?? "")}`.toLowerCase();
14285
15190
  if (value.includes("timeout") || value.includes("deadline") || code.includes("timeout")) return "timeout";
14286
15191
  if (value.includes("cancel") || value.includes("abort") || code.includes("abort")) return "cancel";
@@ -14523,6 +15428,7 @@ var TAG_SQL_SCHEMA_DDL = `
14523
15428
  committed_event_count INTEGER NOT NULL,
14524
15429
  head_suid TEXT NOT NULL,
14525
15430
  reservation_confirmed INTEGER NOT NULL CHECK (reservation_confirmed IN (0, 1)),
15431
+ written_version INTEGER NOT NULL,
14526
15432
  PRIMARY KEY (attempt_id, epoch)
14527
15433
  );
14528
15434
 
@@ -14573,6 +15479,12 @@ var TAG_READ_AFTER_THROUGH_SQL = `
14573
15479
  `;
14574
15480
  function initializeTagSqlSchema(sql) {
14575
15481
  sql.exec(TAG_SQL_SCHEMA_DDL);
15482
+ ensureTagCommitReceiptWrittenVersion(sql);
15483
+ }
15484
+ function ensureTagCommitReceiptWrittenVersion(sql) {
15485
+ const columns = sql.exec("SELECT name FROM pragma_table_info('tag_commit_receipt')").toArray();
15486
+ if (columns.some((column) => column.name === "written_version")) return;
15487
+ sql.exec("ALTER TABLE tag_commit_receipt ADD COLUMN written_version INTEGER");
14576
15488
  }
14577
15489
  function hasTagSqlStorage(storage) {
14578
15490
  return typeof storage.sql?.exec === "function";
@@ -14699,14 +15611,14 @@ var TagIdentityConflict = class extends Error {
14699
15611
  this.name = "TagIdentityConflict";
14700
15612
  }
14701
15613
  };
14702
- function json10(body, status = 200) {
15614
+ function json11(body, status = 200) {
14703
15615
  return new Response(JSON.stringify(body), {
14704
15616
  status,
14705
15617
  headers: { "content-type": "application/json; charset=utf-8" }
14706
15618
  });
14707
15619
  }
14708
- function error8(status, code, message, retryable = false) {
14709
- return json10(retryable ? { error: message, code, retryable: true } : { error: message, code }, status);
15620
+ function error9(status, code, message, retryable = false) {
15621
+ return json11(retryable ? { error: message, code, retryable: true } : { error: message, code }, status);
14710
15622
  }
14711
15623
  function withGlobalAdmission2(response3, status) {
14712
15624
  response3.headers.set(G65_GLOBAL_ADMISSION_HEADER, status);
@@ -14725,7 +15637,7 @@ function repairRejected(reason, status = 409) {
14725
15637
  body: { code: "repair_operation_rejected", error: reason, reason }
14726
15638
  };
14727
15639
  }
14728
- function isObject11(value) {
15640
+ function isObject12(value) {
14729
15641
  return typeof value === "object" && value !== null && !Array.isArray(value);
14730
15642
  }
14731
15643
  function isNonEmptyString11(value) {
@@ -14770,8 +15682,8 @@ function sqlJson(value, column) {
14770
15682
  throw new Error(`Tag SQL column ${column} is not valid JSON`);
14771
15683
  }
14772
15684
  }
14773
- function copyArrayBuffer(bytes) {
14774
- return bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
15685
+ function copyArrayBuffer(bytes2) {
15686
+ return bytes2.buffer.slice(bytes2.byteOffset, bytes2.byteOffset + bytes2.byteLength);
14775
15687
  }
14776
15688
  function arrayBufferBase642(value) {
14777
15689
  let binary = "";
@@ -14782,7 +15694,7 @@ function nowIso() {
14782
15694
  return (/* @__PURE__ */ new Date()).toISOString();
14783
15695
  }
14784
15696
  function epochFrom(value) {
14785
- if (!isObject11(value) || !isNonEmptyString11(value.attemptId) || !isEpoch(value.epoch)) {
15697
+ if (!isObject12(value) || !isNonEmptyString11(value.attemptId) || !isEpoch(value.epoch)) {
14786
15698
  return { error: "attemptId and a non-negative safe-integer epoch are required" };
14787
15699
  }
14788
15700
  return { value: { attemptId: value.attemptId, epoch: value.epoch } };
@@ -14802,7 +15714,7 @@ function consistencyTagsFrom(value) {
14802
15714
  }
14803
15715
  const entries = [];
14804
15716
  for (const rawEntry of value) {
14805
- if (!isObject11(rawEntry) || !isNonEmptyString11(rawEntry.tag)) {
15717
+ if (!isObject12(rawEntry) || !isNonEmptyString11(rawEntry.tag)) {
14806
15718
  return { error: "each consistency tag needs a non-empty tag" };
14807
15719
  }
14808
15720
  if (!("lastSortableUniqueId" in rawEntry)) {
@@ -14830,7 +15742,7 @@ function consistencyTagsFrom(value) {
14830
15742
  }
14831
15743
  function acquireFrom(value, tag) {
14832
15744
  const epoch2 = epochFrom(value);
14833
- if (epoch2.value === void 0 || !isObject11(value)) {
15745
+ if (epoch2.value === void 0 || !isObject12(value)) {
14834
15746
  return { error: epoch2.error ?? "Invalid acquire request" };
14835
15747
  }
14836
15748
  const eventTags = stringArrayFrom(value.eventTags, "eventTags");
@@ -14853,7 +15765,7 @@ function acquireFrom(value, tag) {
14853
15765
  }
14854
15766
  function reservationFrom(value) {
14855
15767
  const epoch2 = epochFrom(value);
14856
- if (epoch2.value === void 0 || !isObject11(value)) {
15768
+ if (epoch2.value === void 0 || !isObject12(value)) {
14857
15769
  return { error: epoch2.error ?? "Invalid reservation request" };
14858
15770
  }
14859
15771
  if (value.reservationToken !== void 0 && !isNonEmptyString11(value.reservationToken)) {
@@ -14872,7 +15784,7 @@ function reservationFrom(value) {
14872
15784
  }
14873
15785
  function appendFrom(value, tag) {
14874
15786
  const reservation = reservationFrom(value);
14875
- if (reservation.value === void 0 || !isObject11(value) || !Array.isArray(value.candidates)) {
15787
+ if (reservation.value === void 0 || !isObject12(value) || !Array.isArray(value.candidates)) {
14876
15788
  return { error: reservation.error ?? "candidates must be an array" };
14877
15789
  }
14878
15790
  if (value.candidates.length === 0) {
@@ -14880,7 +15792,7 @@ function appendFrom(value, tag) {
14880
15792
  }
14881
15793
  const candidates = [];
14882
15794
  for (const rawCandidate of value.candidates) {
14883
- if (!isObject11(rawCandidate) || !isNonEmptyString11(rawCandidate.eventId) || !isNonEmptyString11(rawCandidate.suid) || typeof rawCandidate.payload !== "string") {
15795
+ if (!isObject12(rawCandidate) || !isNonEmptyString11(rawCandidate.eventId) || !isNonEmptyString11(rawCandidate.suid) || typeof rawCandidate.payload !== "string") {
14884
15796
  return { error: "each candidate needs eventId, suid, and payload" };
14885
15797
  }
14886
15798
  const eventTags = stringArrayFrom(rawCandidate.eventTags, "candidate eventTags");
@@ -14894,8 +15806,8 @@ function appendFrom(value, tag) {
14894
15806
  assertSortableUniqueId(rawCandidate.suid);
14895
15807
  if (!isUuidV7(rawCandidate.eventId)) return { error: "candidate eventId must be a UUID v7" };
14896
15808
  JSON.parse(rawCandidate.payload);
14897
- } catch (error10) {
14898
- return { error: error10 instanceof Error ? error10.message : "candidate identity or payload is invalid" };
15809
+ } catch (error11) {
15810
+ return { error: error11 instanceof Error ? error11.message : "candidate identity or payload is invalid" };
14899
15811
  }
14900
15812
  if (rawCandidate.provenance !== "g32") return { error: "candidate provenance must be g32" };
14901
15813
  if (!isNonEmptyString11(rawCandidate.allocatorLineageId)) return { error: "candidate allocatorLineageId is required" };
@@ -14929,10 +15841,10 @@ function appendFrom(value, tag) {
14929
15841
  return { value: { ...reservation.value, candidates: ordered, faultInjection } };
14930
15842
  }
14931
15843
  function bootstrapAppendFrom(value, tag) {
14932
- 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" };
15844
+ 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" };
14933
15845
  const candidates = [];
14934
15846
  for (const candidate of value.candidates) {
14935
- if (!isObject11(candidate) || !isNonEmptyString11(candidate.eventId) || !isNonEmptyString11(candidate.suid) || typeof candidate.payload !== "string") return { error: "bootstrap candidate is invalid" };
15847
+ if (!isObject12(candidate) || !isNonEmptyString11(candidate.eventId) || !isNonEmptyString11(candidate.suid) || typeof candidate.payload !== "string") return { error: "bootstrap candidate is invalid" };
14936
15848
  const tags = stringArrayFrom(candidate.eventTags, "bootstrap candidate eventTags");
14937
15849
  if (tags.value === void 0 || !tags.value.includes(tag) || !isNonEmptyString11(candidate.allocatorLineageId)) return { error: "bootstrap candidate must include this tag and lineage" };
14938
15850
  let eventType;
@@ -14942,8 +15854,8 @@ function bootstrapAppendFrom(value, tag) {
14942
15854
  assertSortableUniqueId(candidate.suid);
14943
15855
  if (!isRfc4122Uuid(candidate.eventId)) return { error: "bootstrap candidate eventId must be an RFC 4122 UUID" };
14944
15856
  JSON.parse(candidate.payload);
14945
- } catch (error10) {
14946
- return { error: error10 instanceof Error ? error10.message : "bootstrap candidate identity or payload is invalid" };
15857
+ } catch (error11) {
15858
+ return { error: error11 instanceof Error ? error11.message : "bootstrap candidate identity or payload is invalid" };
14947
15859
  }
14948
15860
  if (candidate.provenance !== "g32") return { error: "bootstrap candidate provenance must be g32" };
14949
15861
  if (!isNonEmptyString11(candidate.timestamp) || !CANONICAL_UTC_TIMESTAMP_PATTERN.test(candidate.timestamp)) return { error: "bootstrap candidate timestamp must be canonical UTC" };
@@ -14955,13 +15867,13 @@ function bootstrapAppendFrom(value, tag) {
14955
15867
  }
14956
15868
  function fenceFrom(value) {
14957
15869
  const epoch2 = epochFrom(value);
14958
- if (epoch2.value === void 0 || !isObject11(value) || !isNonEmptyString11(value.reason)) {
15870
+ if (epoch2.value === void 0 || !isObject12(value) || !isNonEmptyString11(value.reason)) {
14959
15871
  return { error: epoch2.error ?? "reason is required" };
14960
15872
  }
14961
15873
  return { value: { ...epoch2.value, reason: value.reason } };
14962
15874
  }
14963
15875
  function repairScopeItemFrom(value, tag) {
14964
- 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)) {
15876
+ 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)) {
14965
15877
  return { error: "each repair scope item needs attemptId, eventId, suid, and payload" };
14966
15878
  }
14967
15879
  const eventTags = stringArrayFrom(value.eventTags, "repair eventTags");
@@ -15009,13 +15921,13 @@ function repairScopeFrom(value, tag) {
15009
15921
  return { value: sortRepairScope(scope) };
15010
15922
  }
15011
15923
  function repairLeaseFrom(value) {
15012
- if (!isObject11(value) || !isNonEmptyString11(value.owner) || !isEpoch(value.epoch)) {
15924
+ if (!isObject12(value) || !isNonEmptyString11(value.owner) || !isEpoch(value.epoch)) {
15013
15925
  return { error: "repair owner and non-negative safe-integer epoch are required" };
15014
15926
  }
15015
15927
  return { value: { owner: value.owner, epoch: value.epoch } };
15016
15928
  }
15017
15929
  function repairAcquireFrom(value, tag) {
15018
- if (!isObject11(value) || !isNonEmptyString11(value.owner)) {
15930
+ if (!isObject12(value) || !isNonEmptyString11(value.owner)) {
15019
15931
  return { error: "repair owner is required" };
15020
15932
  }
15021
15933
  const leaseMs = value.leaseMs ?? DEFAULT_REPAIR_LEASE_MS;
@@ -15027,7 +15939,7 @@ function repairAcquireFrom(value, tag) {
15027
15939
  }
15028
15940
  function repairScopeUnionFrom(value, tag) {
15029
15941
  const lease = repairLeaseFrom(value);
15030
- if (lease.value === void 0 || !isObject11(value)) {
15942
+ if (lease.value === void 0 || !isObject12(value)) {
15031
15943
  return { error: lease.error };
15032
15944
  }
15033
15945
  const scope = repairScopeFrom(value.scope, tag);
@@ -15035,7 +15947,7 @@ function repairScopeUnionFrom(value, tag) {
15035
15947
  }
15036
15948
  function repairApplyFrom(value, tag) {
15037
15949
  const lease = repairLeaseFrom(value);
15038
- if (lease.value === void 0 || !isObject11(value)) {
15950
+ if (lease.value === void 0 || !isObject12(value)) {
15039
15951
  return { error: lease.error };
15040
15952
  }
15041
15953
  const item = repairScopeItemFrom(value.item, tag);
@@ -15043,20 +15955,20 @@ function repairApplyFrom(value, tag) {
15043
15955
  }
15044
15956
  function repairAuditFrom(value, tag) {
15045
15957
  const apply = repairApplyFrom(value, tag);
15046
- if (apply.value === void 0 || !isObject11(value) || !isNonEmptyString11(value.actor)) {
15958
+ if (apply.value === void 0 || !isObject12(value) || !isNonEmptyString11(value.actor)) {
15047
15959
  return { error: apply.error ?? "audit actor is required" };
15048
15960
  }
15049
15961
  return { value: { ...apply.value, actor: value.actor } };
15050
15962
  }
15051
15963
  function repairClearFrom(value) {
15052
15964
  const lease = repairLeaseFrom(value);
15053
- if (lease.value === void 0 || !isObject11(value) || !isNonEmptyString11(value.attemptId) || !isNonNegativeInteger4(value.scopeVersion)) {
15965
+ if (lease.value === void 0 || !isObject12(value) || !isNonEmptyString11(value.attemptId) || !isNonNegativeInteger4(value.scopeVersion)) {
15054
15966
  return { error: lease.error ?? "attemptId and scopeVersion are required" };
15055
15967
  }
15056
15968
  return { value: { ...lease.value, attemptId: value.attemptId, scopeVersion: value.scopeVersion } };
15057
15969
  }
15058
15970
  function outboxPendingFrom(value) {
15059
- if (!isObject11(value)) {
15971
+ if (!isObject12(value)) {
15060
15972
  return { error: "outbox pending request must be an object" };
15061
15973
  }
15062
15974
  const nowMs = value.nowMs ?? Date.now();
@@ -15074,22 +15986,22 @@ function outboxPendingFrom(value) {
15074
15986
  return { value: { nowMs, limit, force } };
15075
15987
  }
15076
15988
  function outboxMarkFrom(value) {
15077
- if (!isObject11(value) || !Array.isArray(value.deliveries) || value.deliveries.length === 0) {
15989
+ if (!isObject12(value) || !Array.isArray(value.deliveries) || value.deliveries.length === 0) {
15078
15990
  return { error: "deliveries must be a non-empty array" };
15079
15991
  }
15080
15992
  const deliveries = [];
15081
15993
  for (const raw of value.deliveries) {
15082
- if (!isObject11(raw) || !isNonEmptyString11(raw.attemptId) || !isNonEmptyString11(raw.eventId) || !isNonEmptyString11(raw.suid) || typeof raw.payload !== "string" || !isSafeInteger(raw.enqueuedAt)) {
15994
+ if (!isObject12(raw) || !isNonEmptyString11(raw.attemptId) || !isNonEmptyString11(raw.eventId) || !isNonEmptyString11(raw.suid) || typeof raw.payload !== "string" || !isSafeInteger(raw.enqueuedAt)) {
15083
15995
  return { error: "each delivery needs attemptId, eventId, suid, payload, and enqueuedAt" };
15084
15996
  }
15085
15997
  if (!isNonEmptyString11(raw.eventType) || raw.provenance !== "g32" || !isNonEmptyString11(raw.timestamp) || !isNonEmptyString11(raw.allocatorLineageId)) return { error: "delivery must carry the complete G32 identity" };
15086
- if (!isObject11(raw.completeness)) {
15998
+ if (!isObject12(raw.completeness)) {
15087
15999
  return { error: "delivery must carry a readable global receipt/membership join proof" };
15088
16000
  }
15089
16001
  const completeness = raw.completeness;
15090
16002
  const obligationSequence = completeness.obligationSequence;
15091
16003
  const memberships = completeness.localCommittedMembership;
15092
- 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") {
16004
+ 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") {
15093
16005
  return { error: "delivery must carry a readable global receipt/membership join proof" };
15094
16006
  }
15095
16007
  const membership = memberships[0];
@@ -15128,7 +16040,7 @@ function outboxMarkFrom(value) {
15128
16040
  return { value: { deliveries, nowMs } };
15129
16041
  }
15130
16042
  function g44SourceScanFrom(value) {
15131
- 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) {
16043
+ 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) {
15132
16044
  return { error: "source scan needs serviceId, tag, and a bounded compound cursor" };
15133
16045
  }
15134
16046
  return {
@@ -15142,7 +16054,7 @@ function g44SourceScanFrom(value) {
15142
16054
  };
15143
16055
  }
15144
16056
  function g46TagStateSourceFrom(value) {
15145
- 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") {
16057
+ 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") {
15146
16058
  return { error: "G46 source read needs tag, cursor, optional through, and a bounded limit" };
15147
16059
  }
15148
16060
  try {
@@ -15316,8 +16228,8 @@ function logicalNow(record) {
15316
16228
  return record.clockNowMs ?? Date.now() + record.clockOffsetMs;
15317
16229
  }
15318
16230
  function expireReservation(record) {
15319
- const active = record.activeReservation;
15320
- if (active === null || active.expiresAt > logicalNow(record)) {
16231
+ const active2 = record.activeReservation;
16232
+ if (active2 === null || active2.expiresAt > logicalNow(record)) {
15321
16233
  return { record, expired: false };
15322
16234
  }
15323
16235
  return {
@@ -15435,7 +16347,7 @@ var TagDurableObject = class {
15435
16347
  const url = new URL(request.url);
15436
16348
  const tag = url.searchParams.get("__tag");
15437
16349
  if (!isNonEmptyString11(tag)) {
15438
- return error8(400, "tag_identity_required", "Tag identity is required");
16350
+ return error9(400, "tag_identity_required", "Tag identity is required");
15439
16351
  }
15440
16352
  const serviceId = url.searchParams.get("__serviceId");
15441
16353
  if (request.method === "GET" && url.pathname === "/head-facts") {
@@ -15443,10 +16355,10 @@ var TagDurableObject = class {
15443
16355
  observation.markFirstStorageRead();
15444
16356
  try {
15445
16357
  const facts = this.readHeadFacts(tag);
15446
- return facts === void 0 ? error8(404, "tag_not_found", "Tag has no durable state yet") : json10(facts);
16358
+ return facts === void 0 ? error9(404, "tag_not_found", "Tag has no durable state yet") : json11(facts);
15447
16359
  } catch (caught) {
15448
16360
  if (caught instanceof TagIdentityConflict) {
15449
- return error8(409, "tag_identity_conflict", "Tag Durable Object identity changed");
16361
+ return error9(409, "tag_identity_conflict", "Tag Durable Object identity changed");
15450
16362
  }
15451
16363
  throw caught;
15452
16364
  }
@@ -15457,9 +16369,9 @@ var TagDurableObject = class {
15457
16369
  observation.markFirstStorageRead();
15458
16370
  const record = this.readStoredRecord(tag);
15459
16371
  if (record === void 0) {
15460
- return error8(404, "tag_not_found", "Tag has no durable state yet");
16372
+ return error9(404, "tag_not_found", "Tag has no durable state yet");
15461
16373
  }
15462
- return record.tag === tag ? json10(requireG32TagRecord(record)) : error8(409, "tag_identity_conflict", "Tag Durable Object identity changed");
16374
+ return record.tag === tag ? json11(requireG32TagRecord(record)) : error9(409, "tag_identity_conflict", "Tag Durable Object identity changed");
15463
16375
  });
15464
16376
  }
15465
16377
  if (request.method === "GET" && url.pathname === "/repair/facts") {
@@ -15467,7 +16379,7 @@ var TagDurableObject = class {
15467
16379
  }
15468
16380
  if (request.method === "POST" && url.pathname === "/debug/alarm") {
15469
16381
  const record = await this.runAlarm();
15470
- return record === void 0 ? error8(404, "tag_not_found", "Tag has no durable state yet") : json10(record);
16382
+ return record === void 0 ? error9(404, "tag_not_found", "Tag has no durable state yet") : json11(record);
15471
16383
  }
15472
16384
  if (request.method === "POST" && url.pathname === "/acquire") {
15473
16385
  return this.traceCommitActor(request, tag, serviceId, activation2, observation, (body2) => this.acquire(tag, body2, observation));
@@ -15490,37 +16402,37 @@ var TagDurableObject = class {
15490
16402
  }
15491
16403
  const body = await this.jsonBody(request);
15492
16404
  if (body === void 0) {
15493
- return error8(400, "malformed_tag_request", "Request body must be JSON");
16405
+ return error9(400, "malformed_tag_request", "Request body must be JSON");
15494
16406
  }
15495
16407
  if (request.method === "POST" && url.pathname === "/__internal/g46/tag-state-incremental") {
15496
16408
  if (request.headers.get("x-sdt-g46-source-read") !== "1") {
15497
- return error8(403, "g46_source_read_forbidden", "G46 source reads require the TagState adapter");
16409
+ return error9(403, "g46_source_read_forbidden", "G46 source reads require the TagState adapter");
15498
16410
  }
15499
16411
  const parsed = g46TagStateSourceFrom(body);
15500
16412
  if (parsed.value === void 0 || parsed.value.tag !== tag) {
15501
- return error8(400, "g46_source_read_invalid", parsed.error ?? "G46 source read is invalid");
16413
+ return error9(400, "g46_source_read_invalid", parsed.error ?? "G46 source read is invalid");
15502
16414
  }
15503
16415
  try {
15504
- return json10(await this.g43TagStateIncrementalCatchUp(parsed.value));
16416
+ return json11(await this.g43TagStateIncrementalCatchUp(parsed.value));
15505
16417
  } catch (caught) {
15506
16418
  if (caught instanceof TagIdentityConflict) {
15507
- return error8(409, "tag_identity_conflict", "Tag Durable Object identity changed");
16419
+ return error9(409, "tag_identity_conflict", "Tag Durable Object identity changed");
15508
16420
  }
15509
- return error8(503, "g46_source_read_unavailable", caught instanceof Error ? caught.message : "G46 source read is unavailable");
16421
+ return error9(503, "g46_source_read_unavailable", caught instanceof Error ? caught.message : "G46 source read is unavailable");
15510
16422
  }
15511
16423
  }
15512
16424
  if (request.method === "POST" && url.pathname === "/__internal/g44/source-obligations") {
15513
16425
  if (request.headers.get("x-sdt-g44-source-scan") !== "1") {
15514
- return error8(403, "g44_source_scan_forbidden", "G44 source scan requires the internal scanner seam");
16426
+ return error9(403, "g44_source_scan_forbidden", "G44 source scan requires the internal scanner seam");
15515
16427
  }
15516
16428
  const parsed = g44SourceScanFrom(body);
15517
16429
  if (parsed.value === void 0 || parsed.value.tag !== tag || parsed.value.serviceId !== serviceId) {
15518
- return error8(400, "g44_source_scan_invalid", parsed.error ?? "G44 source scan identity is invalid");
16430
+ return error9(400, "g44_source_scan_invalid", parsed.error ?? "G44 source scan identity is invalid");
15519
16431
  }
15520
16432
  try {
15521
- return json10(await this.g44ReadSourceObligations(parsed.value));
16433
+ return json11(await this.g44ReadSourceObligations(parsed.value));
15522
16434
  } catch (failure3) {
15523
- return error8(503, "g44_source_scan_unavailable", failure3 instanceof Error ? failure3.message : "G44 source scan is unavailable");
16435
+ return error9(503, "g44_source_scan_unavailable", failure3 instanceof Error ? failure3.message : "G44 source scan is unavailable");
15524
16436
  }
15525
16437
  }
15526
16438
  if (request.method === "POST" && url.pathname === "/bootstrap/admit") {
@@ -15567,7 +16479,7 @@ var TagDurableObject = class {
15567
16479
  }
15568
16480
  if (request.method === "POST" && url.pathname === "/__internal/g77/inspect-target") {
15569
16481
  if (!isNonEmptyString11(serviceId)) {
15570
- return error8(400, "service_identity_required", "Service identity is required");
16482
+ return error9(400, "service_identity_required", "Service identity is required");
15571
16483
  }
15572
16484
  return this.inspectG77Target(serviceId, tag, body);
15573
16485
  }
@@ -15575,28 +16487,28 @@ var TagDurableObject = class {
15575
16487
  return this.fenceAbsentG77Target(tag, body);
15576
16488
  }
15577
16489
  if (request.method === "POST" && url.pathname === "/__internal/g77/capabilities") {
15578
- return json10({ inspectTarget: true, fenceAbsentTarget: true });
16490
+ return json11({ inspectTarget: true, fenceAbsentTarget: true });
15579
16491
  }
15580
- return error8(404, "tag_route_not_found", "Tag route was not found");
16492
+ return error9(404, "tag_route_not_found", "Tag route was not found");
15581
16493
  }
15582
16494
  /** Identity-bound installed/absent inspection for G77 issuance reconciliation. */
15583
16495
  inspectG77Target(serviceId, tag, body) {
15584
- if (!isObject11(body) || !isNonEmptyString11(body.eventId) || !isNonEmptyString11(body.suid)) {
15585
- return error8(400, "invalid_inspect_target", "eventId and suid are required");
16496
+ if (!isObject12(body) || !isNonEmptyString11(body.eventId) || !isNonEmptyString11(body.suid)) {
16497
+ return error9(400, "invalid_inspect_target", "eventId and suid are required");
15586
16498
  }
15587
16499
  const pinnedWriterEpoch = isNonNegativeInteger4(body.pinnedWriterEpoch) ? body.pinnedWriterEpoch : 0;
15588
16500
  const attemptId = isNonEmptyString11(body.attemptId) ? body.attemptId : void 0;
15589
16501
  const sql = this.sqlStorage();
15590
- if (sql === void 0) return error8(503, "tag_sql_unavailable", "Tag SQL storage is unavailable");
16502
+ if (sql === void 0) return error9(503, "tag_sql_unavailable", "Tag SQL storage is unavailable");
15591
16503
  const identity2 = sql.exec("SELECT tag FROM tag_identity WHERE singleton = 1").toArray()[0];
15592
16504
  if (identity2 === void 0) {
15593
16505
  if (attemptId !== void 0) {
15594
- return json10({ inspectionStatus: "absent-never-contacted" });
16506
+ return json11({ inspectionStatus: "absent-never-contacted" });
15595
16507
  }
15596
- return error8(409, "target_not_terminal", "Target is not terminal under pinned writer authority");
16508
+ return error9(409, "target_not_terminal", "Target is not terminal under pinned writer authority");
15597
16509
  }
15598
16510
  if (sqlString(identity2.tag, "tag_identity.tag") !== tag) {
15599
- return error8(409, "tag_identity_mismatch", "Tag identity does not match the inspected tag");
16511
+ return error9(409, "tag_identity_mismatch", "Tag identity does not match the inspected tag");
15600
16512
  }
15601
16513
  const event = sql.exec(`
15602
16514
  SELECT attempt_id, event_id, suid FROM tag_event
@@ -15609,41 +16521,41 @@ var TagDurableObject = class {
15609
16521
  `, serviceId, body.eventId).toArray()[0];
15610
16522
  if (obligation !== void 0) {
15611
16523
  const obligationDigest = sqlString(obligation.event_digest, "tag_outbox_obligation.event_digest");
15612
- return json10({
16524
+ return json11({
15613
16525
  terminalStatus: "installed-and-covered",
15614
16526
  eventId: body.eventId,
15615
16527
  obligationDigest
15616
16528
  });
15617
16529
  }
15618
- return error8(409, "target_not_terminal", "Target append is in flight under pinned writer authority");
16530
+ return error9(409, "target_not_terminal", "Target append is in flight under pinned writer authority");
15619
16531
  }
15620
16532
  if (attemptId !== void 0) {
15621
16533
  const tombstone = sql.exec("SELECT epoch FROM tag_tombstone WHERE attempt_id = ?", attemptId).toArray()[0];
15622
16534
  const tombstoneEpoch = tombstone === void 0 ? void 0 : sqlNumber(tombstone.epoch, "tag_tombstone.epoch");
15623
16535
  if (tombstoneEpoch !== void 0 && pinnedWriterEpoch <= tombstoneEpoch) {
15624
- return json10({ terminalStatus: "absent-and-irrevocably-fenced", tombstoneEpoch });
16536
+ return json11({ terminalStatus: "absent-and-irrevocably-fenced", tombstoneEpoch });
15625
16537
  }
15626
16538
  const reservation = sql.exec("SELECT attempt_id, expires_at FROM tag_reservation WHERE singleton = 1").toArray()[0];
15627
16539
  if (reservation !== void 0 && sqlString(reservation.attempt_id, "tag_reservation.attempt_id") === attemptId) {
15628
- return error8(409, "target_not_terminal", "Active reservation holds writer authority");
16540
+ return error9(409, "target_not_terminal", "Active reservation holds writer authority");
15629
16541
  }
15630
16542
  const epoch2 = sql.exec("SELECT attempt_id FROM tag_epoch WHERE attempt_id = ?", attemptId).toArray()[0];
15631
16543
  if (epoch2 !== void 0) {
15632
- return json10({ inspectionStatus: "absent-but-unfenced" });
16544
+ return json11({ inspectionStatus: "absent-but-unfenced" });
15633
16545
  }
15634
- return json10({ inspectionStatus: "absent-never-contacted" });
16546
+ return json11({ inspectionStatus: "absent-never-contacted" });
15635
16547
  }
15636
- return error8(409, "target_not_terminal", "Target is not terminal under pinned writer authority");
16548
+ return error9(409, "target_not_terminal", "Target is not terminal under pinned writer authority");
15637
16549
  }
15638
16550
  /** Reconciler-only fence for never-contacted targets; creates durable tombstone state. */
15639
16551
  async fenceAbsentG77Target(tag, body) {
15640
16552
  const parsed = reservationFrom(body);
15641
16553
  if (parsed.value === void 0) {
15642
- return error8(400, "invalid_fence_target", parsed.error ?? "attemptId and epoch are required");
16554
+ return error9(400, "invalid_fence_target", parsed.error ?? "attemptId and epoch are required");
15643
16555
  }
15644
16556
  this.ensureSqlTag(tag);
15645
16557
  const result2 = await this.cancelSql(tag, { ...parsed.value, forceTombstone: true });
15646
- return result2.status >= 200 && result2.status < 300 ? json10(result2.body) : error8(result2.status, "fence_target_rejected", "Absent target fence was rejected");
16558
+ return result2.status >= 200 && result2.status < 300 ? json11(result2.body) : error9(result2.status, "fence_target_rejected", "Absent target fence was rejected");
15647
16559
  }
15648
16560
  async alarm() {
15649
16561
  this.activation.beginHandler();
@@ -15990,21 +16902,21 @@ var TagDurableObject = class {
15990
16902
  const result2 = await authority;
15991
16903
  g44GlobalArrayAuthorityResultByD1.set(database, result2);
15992
16904
  return result2;
15993
- } catch (error10) {
16905
+ } catch (error11) {
15994
16906
  if (g44GlobalArrayAuthorityByD1.get(database) === authority) {
15995
16907
  g44GlobalArrayAuthorityByD1.delete(database);
15996
16908
  }
15997
- throw error10;
16909
+ throw error11;
15998
16910
  }
15999
16911
  }
16000
16912
  async readG44GlobalArrayAuthority(database) {
16001
16913
  try {
16002
16914
  await database.prepare('SELECT "EventDigest" FROM dcb_events WHERE 1 = 0').all();
16003
16915
  return true;
16004
- } catch (error10) {
16005
- const message = error10 instanceof Error ? error10.message : String(error10);
16916
+ } catch (error11) {
16917
+ const message = error11 instanceof Error ? error11.message : String(error11);
16006
16918
  if (/no such (?:table|column):\s*(?:dcb_events|EventDigest)/i.test(message)) return false;
16007
- throw error10;
16919
+ throw error11;
16008
16920
  }
16009
16921
  }
16010
16922
  async traceCommitActor(request, tag, serviceId, activation2, observation, callback) {
@@ -16014,10 +16926,10 @@ var TagDurableObject = class {
16014
16926
  { actorClass: "TAG", actorKey: `tag:${serviceId}:${tag}`, activation: activation2, observation },
16015
16927
  async () => {
16016
16928
  body = await this.jsonBody(request);
16017
- const attemptId = isObject11(body) && isNonEmptyString11(body.attemptId) ? body.attemptId : void 0;
16929
+ const attemptId = isObject12(body) && isNonEmptyString11(body.attemptId) ? body.attemptId : void 0;
16018
16930
  return attemptId === void 0 || !isNonEmptyString11(serviceId) ? void 0 : { attemptId, serviceId };
16019
16931
  },
16020
- async () => body === void 0 ? error8(400, "malformed_tag_request", "Request body must be JSON") : callback(body)
16932
+ async () => body === void 0 ? error9(400, "malformed_tag_request", "Request body must be JSON") : callback(body)
16021
16933
  );
16022
16934
  }
16023
16935
  /**
@@ -16231,6 +17143,7 @@ var TagDurableObject = class {
16231
17143
  ensureSqlTag(tag) {
16232
17144
  const sql = this.sqlStorage();
16233
17145
  if (sql === void 0) throw new Error("Tag SQL storage is unavailable");
17146
+ ensureTagCommitReceiptWrittenVersion(sql);
16234
17147
  const existing = sql.exec("SELECT tag FROM tag_identity WHERE singleton = 1").toArray()[0];
16235
17148
  if (existing !== void 0) {
16236
17149
  if (sqlString(existing.tag, "tag_identity.tag") !== tag) throw new Error("Tag Durable Object identity changed");
@@ -16343,17 +17256,18 @@ var TagDurableObject = class {
16343
17256
  sql.exec("UPDATE tag_control SET head_suid = ?, version = ?, updated_at = ? WHERE singleton = 1", head, version, committedAt);
16344
17257
  sql.exec("UPDATE tag_head SET service_id = ?, head_suid = ? WHERE singleton = 1", serviceId, head);
16345
17258
  }
16346
- writeCommittedSqlReceipt(sql, input, committedAt, eventCount, head, confirmsReservation) {
17259
+ writeCommittedSqlReceipt(sql, input, committedAt, eventCount, head, confirmsReservation, writtenVersion) {
16347
17260
  sql.exec(`
16348
17261
  INSERT INTO tag_commit_receipt
16349
- (attempt_id, epoch, committed_at, committed_event_count, head_suid, reservation_confirmed)
16350
- VALUES (?, ?, ?, ?, ?, ?)
17262
+ (attempt_id, epoch, committed_at, committed_event_count, head_suid, reservation_confirmed, written_version)
17263
+ VALUES (?, ?, ?, ?, ?, ?, ?)
16351
17264
  ON CONFLICT(attempt_id, epoch) DO UPDATE SET
16352
17265
  committed_at = excluded.committed_at,
16353
17266
  committed_event_count = excluded.committed_event_count,
16354
17267
  head_suid = excluded.head_suid,
16355
- reservation_confirmed = excluded.reservation_confirmed
16356
- `, input.attemptId, input.epoch, committedAt, eventCount, head, confirmsReservation ? 1 : 0);
17268
+ reservation_confirmed = excluded.reservation_confirmed,
17269
+ written_version = excluded.written_version
17270
+ `, input.attemptId, input.epoch, committedAt, eventCount, head, confirmsReservation ? 1 : 0, writtenVersion);
16357
17271
  }
16358
17272
  /**
16359
17273
  * The normal append path deliberately probes only the indexed rows it needs
@@ -16395,11 +17309,29 @@ var TagDurableObject = class {
16395
17309
  return { event, obligation, exact };
16396
17310
  });
16397
17311
  if (existingCandidates.every(({ exact }) => exact)) {
16398
- return { status: 200, body: { status: "duplicate", version } };
17312
+ const receipts = sql.exec(`
17313
+ SELECT epoch, committed_at, written_version, head_suid FROM tag_commit_receipt
17314
+ WHERE attempt_id = ?
17315
+ `, input.attemptId).toArray();
17316
+ const sameEpoch = receipts.find((row) => sqlNumber(row.epoch, "tag_commit_receipt.epoch") === input.epoch);
17317
+ const replayHead = input.candidates.at(-1)?.suid;
17318
+ const byHead = replayHead === void 0 ? [] : receipts.filter((row) => sqlString(row.head_suid, "tag_commit_receipt.head_suid") === replayHead);
17319
+ const receipt = sameEpoch ?? (byHead.length === 1 ? byHead[0] : void 0) ?? (receipts.length === 1 ? receipts[0] : void 0);
17320
+ if (receipt === void 0) {
17321
+ await this.rearmScheduler(txn);
17322
+ return { ...rejected("duplicate_receipt_missing"), body: { ...rejected("duplicate_receipt_missing").body, version } };
17323
+ }
17324
+ const storedAt = sqlNullableString(receipt.committed_at, "tag_commit_receipt.committed_at");
17325
+ const storedVersion = sqlNullableNumber(receipt.written_version, "tag_commit_receipt.written_version");
17326
+ if (storedAt === null || storedVersion === null) {
17327
+ await this.rearmScheduler(txn);
17328
+ return { ...rejected("duplicate_receipt_unknown"), body: { ...rejected("duplicate_receipt_unknown").body, version } };
17329
+ }
17330
+ return { status: 200, body: { status: "duplicate", version: storedVersion, updatedAt: storedAt } };
16399
17331
  }
16400
- const active = sql.exec("SELECT * FROM tag_reservation WHERE singleton = 1").toArray()[0];
17332
+ const active2 = sql.exec("SELECT * FROM tag_reservation WHERE singleton = 1").toArray()[0];
16401
17333
  const now2 = sqlNullableNumber(control.clock_now_ms, "tag_control.clock_now_ms") ?? Date.now() + sqlNumber(control.clock_offset_ms, "tag_control.clock_offset_ms");
16402
- let reservation = active;
17334
+ let reservation = active2;
16403
17335
  if (reservation !== void 0 && sqlNumber(reservation.expires_at, "tag_reservation.expires_at") <= now2) {
16404
17336
  sql.exec("DELETE FROM tag_reservation WHERE singleton = 1");
16405
17337
  version += 1;
@@ -16492,7 +17424,7 @@ var TagDurableObject = class {
16492
17424
  if (input.faultInjection === "after-append-before-confirm") {
16493
17425
  throw new AppendTransactionFault("Simulated interruption before atomic commit receipt");
16494
17426
  }
16495
- this.writeCommittedSqlReceipt(sql, input, committedAt, events.length, head, confirmsReservation);
17427
+ this.writeCommittedSqlReceipt(sql, input, committedAt, events.length, head, confirmsReservation, version + 1);
16496
17428
  if (confirmsReservation) sql.exec("DELETE FROM tag_reservation WHERE singleton = 1");
16497
17429
  await this.rearmScheduler(txn);
16498
17430
  return {
@@ -16500,7 +17432,8 @@ var TagDurableObject = class {
16500
17432
  body: {
16501
17433
  status: "appended",
16502
17434
  fenceGate: { checked: true, activeFenceCount: 0 },
16503
- version: version + 1
17435
+ version: version + 1,
17436
+ updatedAt: committedAt
16504
17437
  },
16505
17438
  hopFacts
16506
17439
  };
@@ -16901,18 +17834,20 @@ var TagDurableObject = class {
16901
17834
  );
16902
17835
  this.upsertSourcePartitionRegistration(sql, eventServiceId, record.tag, outbox.eventId);
16903
17836
  }
17837
+ ensureTagCommitReceiptWrittenVersion(sql);
16904
17838
  for (const confirmation of record.confirmations) {
16905
17839
  sql.exec(
16906
17840
  `
16907
17841
  INSERT OR IGNORE INTO tag_commit_receipt
16908
- (attempt_id, epoch, committed_at, committed_event_count, head_suid, reservation_confirmed)
16909
- VALUES (?, ?, ?, ?, ?, 1)
17842
+ (attempt_id, epoch, committed_at, committed_event_count, head_suid, reservation_confirmed, written_version)
17843
+ VALUES (?, ?, ?, ?, ?, 1, ?)
16910
17844
  `,
16911
17845
  confirmation.attemptId,
16912
17846
  confirmation.epoch,
16913
17847
  record.updatedAt,
16914
17848
  record.events.filter((event) => event.attemptId === confirmation.attemptId).length,
16915
- record.head
17849
+ record.head,
17850
+ record.version
16916
17851
  );
16917
17852
  }
16918
17853
  }
@@ -16961,13 +17896,13 @@ var TagDurableObject = class {
16961
17896
  async acquire(tag, body, observation) {
16962
17897
  const parsed = acquireFrom(body, tag);
16963
17898
  if (parsed.value === void 0) {
16964
- return error8(400, "invalid_tag_acquire", parsed.error ?? "Invalid acquire request");
17899
+ return error9(400, "invalid_tag_acquire", parsed.error ?? "Invalid acquire request");
16965
17900
  }
16966
17901
  const input = parsed.value;
16967
17902
  observation?.markFirstStorageRead();
16968
17903
  if (this.sqlStorage() !== void 0) {
16969
17904
  const result3 = await this.acquireSql(tag, input);
16970
- return json10(result3.body, result3.status);
17905
+ return json11(result3.body, result3.status);
16971
17906
  }
16972
17907
  const result2 = await this.ctx.storage.transaction(async (txn) => {
16973
17908
  const loaded = await this.recordFor(txn, tag);
@@ -17002,9 +17937,9 @@ var TagDurableObject = class {
17002
17937
  body: { ...rejected("consistency_head_mismatch").body, version: record.version }
17003
17938
  };
17004
17939
  }
17005
- const active = record.activeReservation;
17006
- if (active !== null) {
17007
- if (active.attemptId === input.attemptId && active.epoch === input.epoch) {
17940
+ const active2 = record.activeReservation;
17941
+ if (active2 !== null) {
17942
+ if (active2.attemptId === input.attemptId && active2.epoch === input.epoch) {
17008
17943
  return {
17009
17944
  status: 200,
17010
17945
  body: {
@@ -17049,18 +17984,18 @@ var TagDurableObject = class {
17049
17984
  body: { status: "reserved", reservation, fenceGate, version: updated.version }
17050
17985
  };
17051
17986
  });
17052
- return json10(result2.body, result2.status);
17987
+ return json11(result2.body, result2.status);
17053
17988
  }
17054
17989
  async cancel(tag, body, observation) {
17055
17990
  const parsed = reservationFrom(body);
17056
17991
  if (parsed.value === void 0) {
17057
- return error8(400, "invalid_tag_cancel", parsed.error ?? "Invalid cancel request");
17992
+ return error9(400, "invalid_tag_cancel", parsed.error ?? "Invalid cancel request");
17058
17993
  }
17059
17994
  const input = parsed.value;
17060
17995
  observation?.markFirstStorageRead();
17061
17996
  if (this.sqlStorage() !== void 0) {
17062
17997
  const result3 = await this.cancelSql(tag, input);
17063
- return json10(result3.body, result3.status);
17998
+ return json11(result3.body, result3.status);
17064
17999
  }
17065
18000
  const result2 = await this.ctx.storage.transaction(async (txn) => {
17066
18001
  const loaded = await this.recordFor(txn, tag);
@@ -17095,8 +18030,8 @@ var TagDurableObject = class {
17095
18030
  record = await this.commitExpiryIfNeeded(txn, expiry);
17096
18031
  return { ...rejected(epochError), body: { ...rejected(epochError).body, version: record.version } };
17097
18032
  }
17098
- const active = record.activeReservation;
17099
- if (active === null || active.attemptId !== input.attemptId || active.epoch !== input.epoch || active.token !== input.reservationToken) {
18033
+ const active2 = record.activeReservation;
18034
+ if (active2 === null || active2.attemptId !== input.attemptId || active2.epoch !== input.epoch || active2.token !== input.reservationToken) {
17100
18035
  record = await this.commitExpiryIfNeeded(txn, expiry);
17101
18036
  return {
17102
18037
  ...rejected("reservation_token_required"),
@@ -17111,12 +18046,12 @@ var TagDurableObject = class {
17111
18046
  });
17112
18047
  return { status: 200, body: { status: "cancelled", idempotent: false, version: updated.version } };
17113
18048
  });
17114
- return json10(result2.body, result2.status);
18049
+ return json11(result2.body, result2.status);
17115
18050
  }
17116
18051
  async seal(tag, body, observation) {
17117
18052
  const parsed = epochFrom(body);
17118
18053
  if (parsed.value === void 0) {
17119
- return error8(400, "invalid_tag_seal", parsed.error ?? "Invalid seal request");
18054
+ return error9(400, "invalid_tag_seal", parsed.error ?? "Invalid seal request");
17120
18055
  }
17121
18056
  const input = parsed.value;
17122
18057
  observation?.markFirstStorageRead();
@@ -17151,7 +18086,7 @@ var TagDurableObject = class {
17151
18086
  });
17152
18087
  return { status: 200, body: { status: "sealed", highestEpoch: input.epoch, version: updated.version } };
17153
18088
  });
17154
- return json10(result2.body, result2.status);
18089
+ return json11(result2.body, result2.status);
17155
18090
  }
17156
18091
  /**
17157
18092
  * Coordinator-only import admission. This is deliberately not a flag on
@@ -17160,8 +18095,8 @@ var TagDurableObject = class {
17160
18095
  */
17161
18096
  async bootstrapAppend(tag, body, serviceId) {
17162
18097
  const parsed = bootstrapAppendFrom(body, tag);
17163
- if (parsed.value === void 0) return error8(400, "invalid_bootstrap_admission", parsed.error ?? "Invalid bootstrap admission");
17164
- if (serviceId !== parsed.value.targetServiceId) return error8(409, "bootstrap_service_scope_mismatch", "Bootstrap target service does not match tag scope");
18098
+ if (parsed.value === void 0) return error9(400, "invalid_bootstrap_admission", parsed.error ?? "Invalid bootstrap admission");
18099
+ if (serviceId !== parsed.value.targetServiceId) return error9(409, "bootstrap_service_scope_mismatch", "Bootstrap target service does not match tag scope");
17165
18100
  const input = parsed.value;
17166
18101
  const result2 = await this.ctx.storage.transaction(async (txn) => {
17167
18102
  const loaded = await this.recordFor(txn, tag);
@@ -17182,10 +18117,10 @@ var TagDurableObject = class {
17182
18117
  );
17183
18118
  return { status: 201, body: { status: "bootstrap_admitted", version: updated.version } };
17184
18119
  });
17185
- return json10(result2.body, result2.status);
18120
+ return json11(result2.body, result2.status);
17186
18121
  }
17187
18122
  async closeBootstrap(tag, body) {
17188
- if (!isObject11(body) || !isNonEmptyString11(body.importId) || !isEpoch(body.leaseEpoch)) return error8(400, "invalid_bootstrap_close", "bootstrap importId and leaseEpoch are required");
18123
+ if (!isObject12(body) || !isNonEmptyString11(body.importId) || !isEpoch(body.leaseEpoch)) return error9(400, "invalid_bootstrap_close", "bootstrap importId and leaseEpoch are required");
17189
18124
  const result2 = await this.ctx.storage.transaction(async (txn) => {
17190
18125
  const loaded = await this.recordFor(txn, tag);
17191
18126
  const record = loaded.record;
@@ -17195,7 +18130,7 @@ var TagDurableObject = class {
17195
18130
  const updated = await this.commit(txn, record, { bootstrapAdmission: { ...admission, closed: true } });
17196
18131
  return { status: 200, body: { status: "closed", version: updated.version } };
17197
18132
  });
17198
- return json10(result2.body, result2.status);
18133
+ return json11(result2.body, result2.status);
17199
18134
  }
17200
18135
  directDoorbellPreflight(domainDeliveryClass) {
17201
18136
  const domainClass = domainDeliveryClass === void 0 ? void 0 : readDomainDeliveryClass({ DOMAIN_DELIVERY_CLASS: domainDeliveryClass });
@@ -17214,7 +18149,7 @@ var TagDurableObject = class {
17214
18149
  async append(tag, body, serviceId, domainDeliveryClass, observation) {
17215
18150
  const parsed = appendFrom(body, tag);
17216
18151
  if (parsed.value === void 0) {
17217
- return error8(400, "invalid_tag_append", parsed.error ?? "Invalid append request");
18152
+ return error9(400, "invalid_tag_append", parsed.error ?? "Invalid append request");
17218
18153
  }
17219
18154
  const input = parsed.value;
17220
18155
  try {
@@ -17252,7 +18187,7 @@ var TagDurableObject = class {
17252
18187
  if ((result3.status === 201 || result3.status === 200) && serviceId !== null && serviceId.length > 0 && sourcePartitionRegistration !== "unconfigured") {
17253
18188
  this.scheduleSourcePartitionWatermark(tag, serviceId);
17254
18189
  }
17255
- const response4 = json10(result3.body, result3.status);
18190
+ const response4 = json11(result3.body, result3.status);
17256
18191
  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)) {
17257
18192
  const directRows = doorbellPreflight.status === "ready" && this.env.DOWNSTREAM_DOORBELL !== void 0 ? await this.directDeliveryBeforeResponse(tag, serviceId) : void 0;
17258
18193
  if (sourcePartitionRegistration !== "unconfigured" || sourcePartitionWasRegistered) {
@@ -17269,7 +18204,19 @@ var TagDurableObject = class {
17269
18204
  const loaded = await this.recordFor(txn, tag);
17270
18205
  let record = loaded.record;
17271
18206
  if (batchIsExactDuplicate(record, input)) {
17272
- return { status: 200, body: { status: "duplicate", version: record.version } };
18207
+ const receipts = record.writeReceipts ?? {};
18208
+ const sameEpoch = receipts[`${input.attemptId}:${input.epoch}`];
18209
+ const forAttempt = Object.entries(receipts).filter(([key]) => key.startsWith(`${input.attemptId}:`));
18210
+ const replayHead = input.candidates.at(-1)?.suid;
18211
+ const byHead = replayHead === void 0 ? [] : forAttempt.filter(([, value]) => value.headSuid === replayHead);
18212
+ const receipt = sameEpoch ?? (byHead.length === 1 ? byHead[0]?.[1] : void 0) ?? (forAttempt.length === 1 ? forAttempt[0]?.[1] : void 0);
18213
+ if (receipt === void 0) {
18214
+ return {
18215
+ ...rejected("duplicate_receipt_unknown"),
18216
+ body: { ...rejected("duplicate_receipt_unknown").body, version: record.version }
18217
+ };
18218
+ }
18219
+ return { status: 200, body: { status: "duplicate", version: receipt.version, updatedAt: receipt.updatedAt } };
17273
18220
  }
17274
18221
  const expiry = expireReservation(record);
17275
18222
  record = expiry.record;
@@ -17282,9 +18229,9 @@ var TagDurableObject = class {
17282
18229
  await this.commitExpiryIfNeeded(txn, expiry);
17283
18230
  return fenceGateRejected();
17284
18231
  }
17285
- const active = record.activeReservation;
17286
- const confirmsReservation = active !== null && active.attemptId === input.attemptId && active.epoch === input.epoch && active.token === input.reservationToken;
17287
- if (active !== null && (active.attemptId !== input.attemptId || active.epoch !== input.epoch || active.token !== input.reservationToken)) {
18232
+ const active2 = record.activeReservation;
18233
+ const confirmsReservation = active2 !== null && active2.attemptId === input.attemptId && active2.epoch === input.epoch && active2.token === input.reservationToken;
18234
+ if (active2 !== null && (active2.attemptId !== input.attemptId || active2.epoch !== input.epoch || active2.token !== input.reservationToken)) {
17288
18235
  record = await this.commitExpiryIfNeeded(txn, expiry);
17289
18236
  return {
17290
18237
  ...rejected("reservation_token_required"),
@@ -17346,13 +18293,20 @@ var TagDurableObject = class {
17346
18293
  alarmDueAt: null,
17347
18294
  confirmations: confirmsReservation ? withMaxEpoch(record.confirmations, input.attemptId, input.epoch) : record.confirmations
17348
18295
  });
17349
- await this.write(txn, updated, serviceId ?? "");
18296
+ const recorded = {
18297
+ ...updated,
18298
+ writeReceipts: {
18299
+ ...record.writeReceipts ?? {},
18300
+ [`${input.attemptId}:${input.epoch}`]: { version: updated.version, updatedAt: updated.updatedAt, headSuid: updated.head }
18301
+ }
18302
+ };
18303
+ await this.write(txn, recorded, serviceId ?? "");
17350
18304
  return {
17351
18305
  status: 201,
17352
- body: { status: "appended", fenceGate, version: updated.version }
18306
+ body: { status: "appended", fenceGate, version: recorded.version, updatedAt: recorded.updatedAt }
17353
18307
  };
17354
18308
  });
17355
- const response3 = json10(result2.body, result2.status);
18309
+ const response3 = json11(result2.body, result2.status);
17356
18310
  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)) {
17357
18311
  const directRows = doorbellPreflight.status === "ready" && this.env.DOWNSTREAM_DOORBELL !== void 0 ? await this.directDeliveryBeforeResponse(tag, serviceId) : void 0;
17358
18312
  withGlobalAdmission2(
@@ -17364,16 +18318,16 @@ var TagDurableObject = class {
17364
18318
  return response3;
17365
18319
  } catch (failure3) {
17366
18320
  if (failure3 instanceof PartitionRegistrationUnavailableError) {
17367
- return error8(503, "partition_registration_unavailable", "Source partition registration is unavailable; retry the commit.", true);
18321
+ return error9(503, "partition_registration_unavailable", "Source partition registration is unavailable; retry the commit.", true);
17368
18322
  }
17369
18323
  if (failure3 instanceof AppendTransactionFault) {
17370
- return error8(
18324
+ return error9(
17371
18325
  503,
17372
18326
  "simulated_append_crash",
17373
18327
  "Simulated interruption before atomic append and confirmation commit"
17374
18328
  );
17375
18329
  }
17376
- return error8(500, "tag_append_failure", "Tag append could not be persisted");
18330
+ return error9(500, "tag_append_failure", "Tag append could not be persisted");
17377
18331
  }
17378
18332
  }
17379
18333
  /**
@@ -17489,7 +18443,7 @@ var TagDurableObject = class {
17489
18443
  let timer;
17490
18444
  const operationResult = Promise.resolve().then(operation2).then(
17491
18445
  (value) => ({ status: "completed", value }),
17492
- (error10) => ({ status: "failed", error: error10 })
18446
+ (error11) => ({ status: "failed", error: error11 })
17493
18447
  );
17494
18448
  const timeout = new Promise((resolve) => {
17495
18449
  timer = setTimeout(() => resolve({ status: "timeout" }), budgetMs);
@@ -17540,14 +18494,14 @@ var TagDurableObject = class {
17540
18494
  envelopeBytes,
17541
18495
  status: "success"
17542
18496
  });
17543
- } catch (error10) {
18497
+ } catch (error11) {
17544
18498
  console.warn("direct_doorbell_status", {
17545
18499
  status: "queued-degraded",
17546
18500
  reason: "direct_doorbell_delivery_failed",
17547
18501
  correlationId,
17548
18502
  envelopeBytes,
17549
- failureKind: classifyDirectDoorbellFailure(error10),
17550
- error: String(error10)
18503
+ failureKind: classifyDirectDoorbellFailure(error11),
18504
+ error: String(error11)
17551
18505
  });
17552
18506
  }
17553
18507
  }
@@ -17608,7 +18562,7 @@ var TagDurableObject = class {
17608
18562
  async confirm(tag, body) {
17609
18563
  const parsed = reservationFrom(body);
17610
18564
  if (parsed.value === void 0) {
17611
- return error8(400, "invalid_tag_confirm", parsed.error ?? "Invalid confirm request");
18565
+ return error9(400, "invalid_tag_confirm", parsed.error ?? "Invalid confirm request");
17612
18566
  }
17613
18567
  const input = parsed.value;
17614
18568
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -17624,8 +18578,8 @@ var TagDurableObject = class {
17624
18578
  record = await this.commitExpiryIfNeeded(txn, expiry);
17625
18579
  return { ...rejected(epochError), body: { ...rejected(epochError).body, version: record.version } };
17626
18580
  }
17627
- const active = record.activeReservation;
17628
- if (active !== null && active.attemptId === input.attemptId && active.epoch === input.epoch && active.token === input.reservationToken) {
18581
+ const active2 = record.activeReservation;
18582
+ if (active2 !== null && active2.attemptId === input.attemptId && active2.epoch === input.epoch && active2.token === input.reservationToken) {
17629
18583
  record = await this.commitExpiryIfNeeded(txn, expiry);
17630
18584
  return {
17631
18585
  ...rejected("append_required_for_confirmation"),
@@ -17638,12 +18592,12 @@ var TagDurableObject = class {
17638
18592
  body: { ...rejected("confirmation_not_found").body, version: record.version }
17639
18593
  };
17640
18594
  });
17641
- return json10(result2.body, result2.status);
18595
+ return json11(result2.body, result2.status);
17642
18596
  }
17643
18597
  async installFence(tag, body) {
17644
18598
  const parsed = fenceFrom(body);
17645
18599
  if (parsed.value === void 0) {
17646
- return error8(400, "invalid_tag_fence", parsed.error ?? "Invalid fence request");
18600
+ return error9(400, "invalid_tag_fence", parsed.error ?? "Invalid fence request");
17647
18601
  }
17648
18602
  const input = parsed.value;
17649
18603
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -17680,12 +18634,12 @@ var TagDurableObject = class {
17680
18634
  });
17681
18635
  return { status: 201, body: { status: "fence-installed", idempotent: false, version: updated.version } };
17682
18636
  });
17683
- return json10(result2.body, result2.status);
18637
+ return json11(result2.body, result2.status);
17684
18638
  }
17685
18639
  async clearFence(tag, body) {
17686
18640
  const parsed = fenceFrom(body);
17687
18641
  if (parsed.value === void 0) {
17688
- return error8(400, "invalid_tag_fence", parsed.error ?? "Invalid fence request");
18642
+ return error9(400, "invalid_tag_fence", parsed.error ?? "Invalid fence request");
17689
18643
  }
17690
18644
  const input = parsed.value;
17691
18645
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -17711,7 +18665,7 @@ var TagDurableObject = class {
17711
18665
  });
17712
18666
  return { status: 200, body: { status: "fence-cleared", idempotent: false, version: updated.version } };
17713
18667
  });
17714
- return json10(result2.body, result2.status);
18668
+ return json11(result2.body, result2.status);
17715
18669
  }
17716
18670
  /**
17717
18671
  * Returns Tag-side repair facts only. Journal observations are deliberately
@@ -17747,7 +18701,7 @@ var TagDurableObject = class {
17747
18701
  }
17748
18702
  };
17749
18703
  });
17750
- return json10(result2.body, result2.status);
18704
+ return json11(result2.body, result2.status);
17751
18705
  }
17752
18706
  /**
17753
18707
  * Internal outbox handoff: enqueuedAt is persisted before any Queue send so
@@ -17757,10 +18711,10 @@ var TagDurableObject = class {
17757
18711
  async pendingOutbox(tag, serviceId, body) {
17758
18712
  const parsed = outboxPendingFrom(body);
17759
18713
  if (parsed.value === void 0) {
17760
- return error8(400, "invalid_outbox_pending", parsed.error ?? "Invalid outbox pending request");
18714
+ return error9(400, "invalid_outbox_pending", parsed.error ?? "Invalid outbox pending request");
17761
18715
  }
17762
18716
  if (!isNonEmptyString11(serviceId)) {
17763
- return error8(400, "outbox_service_identity_required", "Outbox delivery requires a service identity");
18717
+ return error9(400, "outbox_service_identity_required", "Outbox delivery requires a service identity");
17764
18718
  }
17765
18719
  const input = parsed.value;
17766
18720
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -17836,7 +18790,7 @@ var TagDurableObject = class {
17836
18790
  }
17837
18791
  return { status: 200, body: { rows } };
17838
18792
  });
17839
- return json10(result2.body, result2.status);
18793
+ return json11(result2.body, result2.status);
17840
18794
  }
17841
18795
  /**
17842
18796
  * Source-side obligation scanner. It deliberately does not call the Queue,
@@ -17906,7 +18860,7 @@ var TagDurableObject = class {
17906
18860
  }
17907
18861
  };
17908
18862
  });
17909
- return json10(result2.body, result2.status);
18863
+ return json11(result2.body, result2.status);
17910
18864
  }
17911
18865
  /** Record a retry or terminal poison disposition without changing the source event. */
17912
18866
  async recordOutboxFailure(tag, delivery, failure3) {
@@ -17960,16 +18914,16 @@ var TagDurableObject = class {
17960
18914
  async markOutboxDelivered(tag, body) {
17961
18915
  const parsed = outboxMarkFrom(body);
17962
18916
  if (parsed.value === void 0) {
17963
- return error8(400, "invalid_outbox_delivery_mark", parsed.error ?? "Invalid outbox delivery mark");
18917
+ return error9(400, "invalid_outbox_delivery_mark", parsed.error ?? "Invalid outbox delivery mark");
17964
18918
  }
17965
18919
  const input = parsed.value;
17966
18920
  try {
17967
18921
  const joined = await Promise.all(input.deliveries.map((delivery) => this.globalReceiptMatches(delivery)));
17968
18922
  if (joined.some((value) => !value)) {
17969
- return error8(409, "outbox_global_receipt_unverified", "Global receipt and membership must be read back before source acknowledgement");
18923
+ return error9(409, "outbox_global_receipt_unverified", "Global receipt and membership must be read back before source acknowledgement");
17970
18924
  }
17971
18925
  } catch {
17972
- return error8(503, "outbox_global_receipt_unavailable", "Global receipt verification is unavailable");
18926
+ return error9(503, "outbox_global_receipt_unavailable", "Global receipt verification is unavailable");
17973
18927
  }
17974
18928
  const result2 = await this.ctx.storage.transaction(async (txn) => {
17975
18929
  if (this.sqlStorage() !== void 0) {
@@ -18008,7 +18962,7 @@ var TagDurableObject = class {
18008
18962
  }
18009
18963
  return { status: 200, body: { marked, idempotent: marked === 0 } };
18010
18964
  });
18011
- return json10(result2.body, result2.status);
18965
+ return json11(result2.body, result2.status);
18012
18966
  }
18013
18967
  /**
18014
18968
  * The delivery handoff reads its universe from `tag_outbox_obligation`.
@@ -18147,7 +19101,7 @@ var TagDurableObject = class {
18147
19101
  async acquireRepairLease(tag, body) {
18148
19102
  const parsed = repairAcquireFrom(body, tag);
18149
19103
  if (parsed.value === void 0) {
18150
- return error8(400, "invalid_repair_acquire", parsed.error ?? "Invalid repair acquire request");
19104
+ return error9(400, "invalid_repair_acquire", parsed.error ?? "Invalid repair acquire request");
18151
19105
  }
18152
19106
  const input = parsed.value;
18153
19107
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -18193,12 +19147,12 @@ var TagDurableObject = class {
18193
19147
  }
18194
19148
  };
18195
19149
  });
18196
- return json10(result2.body, result2.status);
19150
+ return json11(result2.body, result2.status);
18197
19151
  }
18198
19152
  async renewRepairLease(tag, body) {
18199
19153
  const parsed = repairLeaseFrom(body);
18200
19154
  if (parsed.value === void 0) {
18201
- return error8(400, "invalid_repair_renew", parsed.error ?? "Invalid repair renew request");
19155
+ return error9(400, "invalid_repair_renew", parsed.error ?? "Invalid repair renew request");
18202
19156
  }
18203
19157
  const input = parsed.value;
18204
19158
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -18222,12 +19176,12 @@ var TagDurableObject = class {
18222
19176
  }
18223
19177
  };
18224
19178
  });
18225
- return json10(result2.body, result2.status);
19179
+ return json11(result2.body, result2.status);
18226
19180
  }
18227
19181
  async unionRepairScope(tag, body) {
18228
19182
  const parsed = repairScopeUnionFrom(body, tag);
18229
19183
  if (parsed.value === void 0) {
18230
- return error8(400, "invalid_repair_scope_union", parsed.error ?? "Invalid repair scope union request");
19184
+ return error9(400, "invalid_repair_scope_union", parsed.error ?? "Invalid repair scope union request");
18231
19185
  }
18232
19186
  const input = parsed.value;
18233
19187
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -18263,12 +19217,12 @@ var TagDurableObject = class {
18263
19217
  body: { status: "repair-scope-unioned", scopeVersion: updated.repairScopeVersion, scope: updated.repairScope }
18264
19218
  };
18265
19219
  });
18266
- return json10(result2.body, result2.status);
19220
+ return json11(result2.body, result2.status);
18267
19221
  }
18268
19222
  async applyRepair(tag, body) {
18269
19223
  const parsed = repairApplyFrom(body, tag);
18270
19224
  if (parsed.value === void 0) {
18271
- return error8(400, "invalid_repair_apply", parsed.error ?? "Invalid repair apply request");
19225
+ return error9(400, "invalid_repair_apply", parsed.error ?? "Invalid repair apply request");
18272
19226
  }
18273
19227
  const input = parsed.value;
18274
19228
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -18349,12 +19303,12 @@ var TagDurableObject = class {
18349
19303
  body: { status: branch, idempotent: false, head: (updatedRecord ?? record).head, version: (updatedRecord ?? record).version }
18350
19304
  };
18351
19305
  });
18352
- return json10(result2.body, result2.status);
19306
+ return json11(result2.body, result2.status);
18353
19307
  }
18354
19308
  async auditRepair(tag, body) {
18355
19309
  const parsed = repairAuditFrom(body, tag);
18356
19310
  if (parsed.value === void 0) {
18357
- return error8(400, "invalid_repair_audit", parsed.error ?? "Invalid repair audit request");
19311
+ return error9(400, "invalid_repair_audit", parsed.error ?? "Invalid repair audit request");
18358
19312
  }
18359
19313
  const input = parsed.value;
18360
19314
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -18391,12 +19345,12 @@ var TagDurableObject = class {
18391
19345
  await txn.put(REPAIR_FACTS_KEY, { ...facts, audits: [...facts.audits, audit] });
18392
19346
  return { status: 200, body: { status: "repair-audited", idempotent: false, branch: audit.branch } };
18393
19347
  });
18394
- return json10(result2.body, result2.status);
19348
+ return json11(result2.body, result2.status);
18395
19349
  }
18396
19350
  async clearRepairFence(tag, body) {
18397
19351
  const parsed = repairClearFrom(body);
18398
19352
  if (parsed.value === void 0) {
18399
- return error8(400, "invalid_repair_clear", parsed.error ?? "Invalid repair clear request");
19353
+ return error9(400, "invalid_repair_clear", parsed.error ?? "Invalid repair clear request");
18400
19354
  }
18401
19355
  const input = parsed.value;
18402
19356
  const result2 = await this.ctx.storage.transaction(async (txn) => {
@@ -18427,16 +19381,16 @@ var TagDurableObject = class {
18427
19381
  });
18428
19382
  return { status: 200, body: { status: "repair-fence-cleared", idempotent: false, version: updated.version } };
18429
19383
  });
18430
- return json10(result2.body, result2.status);
19384
+ return json11(result2.body, result2.status);
18431
19385
  }
18432
19386
  async setClockOffset(tag, body) {
18433
- if (!isObject11(body)) {
18434
- return error8(400, "invalid_tag_clock", "offsetMs or nowMs must be a safe integer");
19387
+ if (!isObject12(body)) {
19388
+ return error9(400, "invalid_tag_clock", "offsetMs or nowMs must be a safe integer");
18435
19389
  }
18436
19390
  const nowMs = body.nowMs;
18437
19391
  const offsetMs = body.offsetMs;
18438
19392
  if (!isSafeInteger(nowMs) && !isSafeInteger(offsetMs)) {
18439
- return error8(400, "invalid_tag_clock", "offsetMs or nowMs must be a safe integer");
19393
+ return error9(400, "invalid_tag_clock", "offsetMs or nowMs must be a safe integer");
18440
19394
  }
18441
19395
  const result2 = await this.ctx.storage.transaction(async (txn) => {
18442
19396
  const loaded = await this.recordFor(txn, tag);
@@ -18454,7 +19408,7 @@ var TagDurableObject = class {
18454
19408
  }
18455
19409
  };
18456
19410
  });
18457
- return json10(result2.body, result2.status);
19411
+ return json11(result2.body, result2.status);
18458
19412
  }
18459
19413
  async runAlarm() {
18460
19414
  const due = await this.ctx.storage.transaction(async (txn) => {
@@ -18573,16 +19527,16 @@ var TagStateCheckpointFault = class extends Error {
18573
19527
  this.name = "TagStateCheckpointFault";
18574
19528
  }
18575
19529
  };
18576
- function json11(body, status = 200) {
19530
+ function json12(body, status = 200) {
18577
19531
  return new Response(JSON.stringify(body), {
18578
19532
  status,
18579
19533
  headers: { "content-type": "application/json; charset=utf-8" }
18580
19534
  });
18581
19535
  }
18582
- function error9(status, code, message) {
18583
- return json11({ code, error: message }, status);
19536
+ function error10(status, code, message) {
19537
+ return json12({ code, error: message }, status);
18584
19538
  }
18585
- function isObject12(value) {
19539
+ function isObject13(value) {
18586
19540
  return typeof value === "object" && value !== null && !Array.isArray(value);
18587
19541
  }
18588
19542
  function isNonEmptyString12(value) {
@@ -18597,7 +19551,7 @@ function sqlNullableString2(value, column) {
18597
19551
  return sqlString2(value, column);
18598
19552
  }
18599
19553
  function parseIdentity(value) {
18600
- if (!isObject12(value) || !isNonEmptyString12(value.serviceId) || !isNonEmptyString12(value.tag) || !isNonEmptyString12(value.projectorId)) {
19554
+ if (!isObject13(value) || !isNonEmptyString12(value.serviceId) || !isNonEmptyString12(value.tag) || !isNonEmptyString12(value.projectorId)) {
18601
19555
  return void 0;
18602
19556
  }
18603
19557
  return { serviceId: value.serviceId, tag: value.tag, projectorId: value.projectorId };
@@ -18659,17 +19613,17 @@ var TagStateDurableObject = class {
18659
19613
  async fetch(request) {
18660
19614
  const url = new URL(request.url);
18661
19615
  if (request.method !== "POST" || url.pathname !== "/read") {
18662
- return error9(404, "tag_state_route_not_found", "TagState route was not found");
19616
+ return error10(404, "tag_state_route_not_found", "TagState route was not found");
18663
19617
  }
18664
19618
  let body;
18665
19619
  try {
18666
19620
  body = await request.json();
18667
19621
  } catch {
18668
- return error9(400, "tag_state_validation_error", "TagState request must be JSON");
19622
+ return error10(400, "tag_state_validation_error", "TagState request must be JSON");
18669
19623
  }
18670
19624
  const identity2 = parseIdentity(body);
18671
19625
  if (identity2 === void 0) {
18672
- return error9(400, "tag_state_validation_error", "TagState identity requires serviceId, tag, and projectorId");
19626
+ return error10(400, "tag_state_validation_error", "TagState identity requires serviceId, tag, and projectorId");
18673
19627
  }
18674
19628
  return await this.read(identity2);
18675
19629
  }
@@ -18691,16 +19645,16 @@ var TagStateDurableObject = class {
18691
19645
  return await this.continueRebuild(identity2, projector, cache);
18692
19646
  } catch (caught) {
18693
19647
  if (caught instanceof TagStateIdentityConflict) {
18694
- return error9(409, "tag_state_identity_conflict", "TagState Durable Object identity changed");
19648
+ return error10(409, "tag_state_identity_conflict", "TagState Durable Object identity changed");
18695
19649
  }
18696
19650
  if (caught instanceof TagStateUnknownProjector) {
18697
- return error9(404, "tag_state_unknown_projector", "TagState projector is not registered");
19651
+ return error10(404, "tag_state_unknown_projector", "TagState projector is not registered");
18698
19652
  }
18699
19653
  if (caught instanceof TagStateRegistryFailure) {
18700
- return error9(503, "tag_state_projector_registry_failure", "TagState projector registry is unavailable");
19654
+ return error10(503, "tag_state_projector_registry_failure", "TagState projector registry is unavailable");
18701
19655
  }
18702
19656
  if (caught instanceof TagStateSourceFailure) {
18703
- return error9(caught.status, "tag_state_source_frontier_failure", "TagState source frontier could not be read");
19657
+ return error10(caught.status, "tag_state_source_frontier_failure", "TagState source frontier could not be read");
18704
19658
  }
18705
19659
  if (caught instanceof TagStateCacheCorruption) {
18706
19660
  try {
@@ -18708,21 +19662,21 @@ var TagStateDurableObject = class {
18708
19662
  this.beginRebuild(projector, "cache-corrupt");
18709
19663
  } catch (rebuildFailure) {
18710
19664
  if (rebuildFailure instanceof TagStateRegistryFailure) {
18711
- return error9(503, "tag_state_projector_registry_failure", "TagState projector registry is unavailable");
19665
+ return error10(503, "tag_state_projector_registry_failure", "TagState projector registry is unavailable");
18712
19666
  }
18713
19667
  }
18714
- return error9(409, "tag_state_cache_corrupt", "TagState cache is corrupt and is rebuilding");
19668
+ return error10(409, "tag_state_cache_corrupt", "TagState cache is corrupt and is rebuilding");
18715
19669
  }
18716
19670
  if (caught instanceof TagStateCheckpointFault) {
18717
- return error9(503, "tag_state_rebuild_interrupted", "TagState replay checkpoint was interrupted");
19671
+ return error10(503, "tag_state_rebuild_interrupted", "TagState replay checkpoint was interrupted");
18718
19672
  }
18719
- return error9(503, "tag_state_unavailable", "TagState cache is unavailable");
19673
+ return error10(503, "tag_state_unavailable", "TagState cache is unavailable");
18720
19674
  }
18721
19675
  }
18722
19676
  async beginDeltaOrRespondReady(identity2, projector, cache) {
18723
19677
  const page = await this.readSource(identity2, cache.lastSuid, void 0);
18724
19678
  if (page.events.length === 0 && page.completeThrough !== null) {
18725
- return json11(this.success(projector, cache.stateJson, cache.lastSuid));
19679
+ return json12(this.success(projector, cache.stateJson, cache.lastSuid));
18726
19680
  }
18727
19681
  const rebuild = this.beginRebuild(projector, "normal-delta", {
18728
19682
  cursor: cache.lastSuid,
@@ -18771,9 +19725,9 @@ var TagStateDurableObject = class {
18771
19725
  });
18772
19726
  if (this.g46CheckpointFault === "after-checkpoint") throw new TagStateCheckpointFault();
18773
19727
  if (!complete) {
18774
- return error9(503, "tag_state_rebuild_in_progress", "TagState replay is rebuilding to its frozen frontier");
19728
+ return error10(503, "tag_state_rebuild_in_progress", "TagState replay is rebuilding to its frozen frontier");
18775
19729
  }
18776
- return json11(this.success(projector, accumulatorJson, page.completeThrough));
19730
+ return json12(this.success(projector, accumulatorJson, page.completeThrough));
18777
19731
  }
18778
19732
  success(projector, stateJson, lastSortedUniqueId) {
18779
19733
  try {
@@ -18830,7 +19784,7 @@ var TagStateDurableObject = class {
18830
19784
  }
18831
19785
  }
18832
19786
  assertSourcePage(cursor, expectedThrough, page) {
18833
- if (!isObject12(page) || !Array.isArray(page.events) || typeof page.lastSortableUniqueId !== "string" || typeof page.through !== "string" || page.completeThrough !== null && typeof page.completeThrough !== "string") {
19787
+ if (!isObject13(page) || !Array.isArray(page.events) || typeof page.lastSortableUniqueId !== "string" || typeof page.through !== "string" || page.completeThrough !== null && typeof page.completeThrough !== "string") {
18834
19788
  throw new TagStateSourceFailure(503, new Error("TagState source response was malformed"));
18835
19789
  }
18836
19790
  if (expectedThrough !== void 0 && expectedThrough !== null && page.through !== expectedThrough) {
@@ -19029,12 +19983,12 @@ function encodedCommitSnapshotLogBytes(record) {
19029
19983
  function assertCommitSnapshotLogSize(record) {
19030
19984
  const encodedBytes2 = encodedCommitSnapshotLogBytes(record);
19031
19985
  if (encodedBytes2 > COMMIT_SNAPSHOT_LOG_BYTE_BUDGET) {
19032
- const error10 = new Error(
19986
+ const error11 = new Error(
19033
19987
  `Commit snapshot log is ${encodedBytes2} bytes; budget is ${COMMIT_SNAPSHOT_LOG_BYTE_BUDGET} bytes`
19034
19988
  );
19035
- error10.code = "commit-snapshot-log-size";
19036
- error10.encodedBytes = encodedBytes2;
19037
- throw error10;
19989
+ error11.code = "commit-snapshot-log-size";
19990
+ error11.encodedBytes = encodedBytes2;
19991
+ throw error11;
19038
19992
  }
19039
19993
  return encodedBytes2;
19040
19994
  }
@@ -19053,8 +20007,8 @@ function createCommitTraceConsoleSink(options = {}) {
19053
20007
  if (record === void 0) return;
19054
20008
  try {
19055
20009
  assertCommitSnapshotLogSize(record);
19056
- } catch (error10) {
19057
- const encodedBytes2 = typeof error10 === "object" && error10 !== null && "encodedBytes" in error10 && typeof error10.encodedBytes === "number" ? error10.encodedBytes : encodedCommitSnapshotLogBytes(record);
20010
+ } catch (error11) {
20011
+ const encodedBytes2 = typeof error11 === "object" && error11 !== null && "encodedBytes" in error11 && typeof error11.encodedBytes === "number" ? error11.encodedBytes : encodedCommitSnapshotLogBytes(record);
19058
20012
  reportRejectedSize(Object.freeze({
19059
20013
  schema: COMMIT_SNAPSHOT_LOG_SCHEMA,
19060
20014
  event: "commit.snapshot-size-rejected",
@@ -19063,43 +20017,13 @@ function createCommitTraceConsoleSink(options = {}) {
19063
20017
  encodedBytes: encodedBytes2,
19064
20018
  byteBudget: COMMIT_SNAPSHOT_LOG_BYTE_BUDGET
19065
20019
  }));
19066
- throw error10;
20020
+ throw error11;
19067
20021
  }
19068
20022
  log(record);
19069
20023
  }
19070
20024
  });
19071
20025
  }
19072
20026
 
19073
- // src/scope/ControlRouteScope.ts
19074
- function response2(status, code, error10) {
19075
- return new Response(JSON.stringify({ code, error: error10 }), {
19076
- status,
19077
- headers: { "content-type": "application/json; charset=utf-8" }
19078
- });
19079
- }
19080
- function scopeIdentityMissingResponse() {
19081
- return response2(503, "scope.identity_missing", "A deployment service identity is required for this scope");
19082
- }
19083
- function enforceControlRouteScope(input) {
19084
- let actual;
19085
- try {
19086
- actual = input.provider.forRequest(input.request, input.requestOptions).serviceId;
19087
- } catch (caught) {
19088
- if (caught instanceof ServiceIdentityMissingError) {
19089
- console.error({ schema: "sdt.scope/v1", code: "scope.identity_missing", route: input.route });
19090
- return { response: scopeIdentityMissingResponse() };
19091
- }
19092
- throw caught;
19093
- }
19094
- if (input.pathServiceId !== actual) {
19095
- console.warn({ schema: "sdt.scope/v1", code: "scope.mismatch", route: input.route });
19096
- return {
19097
- response: response2(403, "scope.mismatch", "The path service identity is not authorized for this deployment")
19098
- };
19099
- }
19100
- return { serviceId: actual };
19101
- }
19102
-
19103
20027
  // src/diagnostics/G65DirectRing.ts
19104
20028
  var G65_DIRECT_RING_BUDGET_MS = 100;
19105
20029
  var G65_DIRECT_RING_CLOCK_ORIGIN = "Date.now epoch ms";
@@ -19165,7 +20089,7 @@ async function markG65DirectApplyStarted(database, message, observedAt) {
19165
20089
  WHERE service_id = ? AND event_id = ? AND attempt_id = ?
19166
20090
  `).bind(observedAt, message.serviceId, message.eventId, message.attemptId).run();
19167
20091
  }
19168
- async function markG65DirectApplyFinished(database, message, observedAt, outcome, error10) {
20092
+ async function markG65DirectApplyFinished(database, message, observedAt, outcome, error11) {
19169
20093
  validateTimestamp(observedAt, "apply finish");
19170
20094
  if (outcome.length === 0) throw new Error("G65 direct apply outcome must be non-empty");
19171
20095
  await database.prepare(`
@@ -19177,13 +20101,109 @@ async function markG65DirectApplyFinished(database, message, observedAt, outcome
19177
20101
  `).bind(
19178
20102
  observedAt,
19179
20103
  outcome,
19180
- error10 ?? null,
20104
+ error11 ?? null,
19181
20105
  message.serviceId,
19182
20106
  message.eventId,
19183
20107
  message.attemptId
19184
20108
  ).run();
19185
20109
  }
19186
20110
 
20111
+ // src/shard/ShardRotation.ts
20112
+ var ShardRotationError = class extends Error {
20113
+ diagnostic;
20114
+ constructor(diagnostic) {
20115
+ super(diagnostic.code);
20116
+ this.name = "ShardRotationError";
20117
+ this.diagnostic = diagnostic;
20118
+ }
20119
+ };
20120
+ function fail(code, path, reason) {
20121
+ throw new ShardRotationError({ code, path, reason });
20122
+ }
20123
+ function createRotationState(active2) {
20124
+ if (typeof active2 !== "string" || active2.length === 0) fail("ACTIVE_COUNT", "active", "active-missing");
20125
+ return { sealed: [], active: active2, ledger: [] };
20126
+ }
20127
+ function assertStrictlyBefore(lastD1_1, firstD1_2) {
20128
+ assertSortableUniqueId(lastD1_1);
20129
+ assertSortableUniqueId(firstD1_2);
20130
+ if (compareSortableUniqueId(lastD1_1, firstD1_2) >= 0) {
20131
+ fail("ORDER_INVARIANT", "last(D1-1)<first(D1-2)", "order-invariant");
20132
+ }
20133
+ }
20134
+ function maxSortableUniqueId(values) {
20135
+ if (values.length === 0) fail("SEAL_MAX_MISSING", "d1-1", "seal-max-missing");
20136
+ let max = assertSortableUniqueId(values[0]).value;
20137
+ for (let i = 1; i < values.length; i += 1) {
20138
+ const next = assertSortableUniqueId(values[i]).value;
20139
+ if (next > max) max = next;
20140
+ }
20141
+ return max;
20142
+ }
20143
+ function rotateAppend(state, sealedId, shardSuids, nextActiveId) {
20144
+ if (sealedId !== state.active) fail("UNKNOWN_SHARD", sealedId, "unknown-shard");
20145
+ if (typeof nextActiveId !== "string" || nextActiveId.length === 0 || nextActiveId === sealedId) {
20146
+ fail("ACTIVE_COUNT", "active", "active-count");
20147
+ }
20148
+ if (state.sealed.some((entry) => entry.id === nextActiveId)) {
20149
+ fail("ACTIVE_COUNT", nextActiveId, "active-already-sealed");
20150
+ }
20151
+ if (state.sealed.some((entry) => entry.id === sealedId)) fail("IDENTITY_SWAP", sealedId, "identity-swap");
20152
+ const lastSuid = maxSortableUniqueId(shardSuids);
20153
+ return {
20154
+ sealed: [...state.sealed, { id: sealedId, lastSuid }],
20155
+ active: nextActiveId,
20156
+ ledger: state.ledger
20157
+ };
20158
+ }
20159
+ function replaceSealedIdentity(state, index, nextId) {
20160
+ if (index < 0 || index >= state.sealed.length) fail("UNKNOWN_SHARD", "sealed", "unknown-shard");
20161
+ fail("IDENTITY_SWAP", state.sealed[index].id, `identity-swap:${nextId}`);
20162
+ }
20163
+ function refuseSealedWrite(state, shardId) {
20164
+ if (state.sealed.some((entry) => entry.id === shardId)) fail("SEALED_WRITE", shardId, "sealed-write");
20165
+ }
20166
+ function admitActiveWrite(state, shardId, firstOrNextSuid) {
20167
+ assertSortableUniqueId(firstOrNextSuid);
20168
+ refuseSealedWrite(state, shardId);
20169
+ if (shardId !== state.active) fail("UNKNOWN_SHARD", shardId, "unknown-shard");
20170
+ if (state.sealed.length === 0) return;
20171
+ const previous = state.sealed[state.sealed.length - 1];
20172
+ assertStrictlyBefore(previous.lastSuid, firstOrNextSuid);
20173
+ }
20174
+ function recordLateArrival(state, sealedShardId, suid) {
20175
+ assertSortableUniqueId(suid);
20176
+ const sealed = state.sealed.find((entry) => entry.id === sealedShardId);
20177
+ if (sealed === void 0) fail("UNKNOWN_SHARD", sealedShardId, "unknown-shard");
20178
+ if (compareSortableUniqueId(suid, sealed.lastSuid) > 0) {
20179
+ fail("ORDER_INVARIANT", sealedShardId, "not-late-arrival");
20180
+ }
20181
+ return {
20182
+ ...state,
20183
+ ledger: [...state.ledger, { shardId: sealed.id, suid, reason: "sealed-range" }]
20184
+ };
20185
+ }
20186
+ var SILENT_MERGE_TOKENS = [
20187
+ ["merge", "Ledger", "Into", "Sealed"],
20188
+ ["merge", "OnRead", "Sealed"],
20189
+ ["silent", "Merge", "Ledger"],
20190
+ ["ledger", ".concat(", "sealed"],
20191
+ ["sealed", ".concat(", "ledger"]
20192
+ ];
20193
+ function assertNoSilentLedgerMerge(source) {
20194
+ const lowered = source.toLowerCase();
20195
+ for (const token of SILENT_MERGE_TOKENS) {
20196
+ const needle = token.join("").toLowerCase();
20197
+ if (lowered.includes(needle)) fail("SILENT_MERGE", "ledger", "silent-merge");
20198
+ }
20199
+ }
20200
+ function refuseSilentLedgerMerge() {
20201
+ fail("SILENT_MERGE", "ledger", "silent-merge");
20202
+ }
20203
+ function refuseSafeWindowSeal() {
20204
+ fail("SAFEWINDOW_SEAL", "safe-window", "safewindow-seal");
20205
+ }
20206
+
19187
20207
  // src/cloudflare.ts
19188
20208
  function cloudflareCommitTraceProvider(request, env) {
19189
20209
  const versionId = env.WORKER_VERSION?.id;
@@ -19224,6 +20244,10 @@ function createCloudflareOnlyRuntimeWorker(options = {}) {
19224
20244
  const storeProvider = createD1StoreProvider();
19225
20245
  return {
19226
20246
  async fetch(request, env, ctx) {
20247
+ const url = new URL(request.url);
20248
+ if (isIncidentMaintenancePath(url.pathname)) {
20249
+ return handleIncidentMaintenance(request, env, options.serviceIdentityProvider ?? envServiceIdentity(env));
20250
+ }
19227
20251
  const serviceIdentity = options.serviceIdentityProvider ?? envServiceIdentity(env);
19228
20252
  const requestIdentityOptions = { allowG11Verification: env.G11_VERIFICATION_ENABLED === "true" };
19229
20253
  let requestServiceId;
@@ -19233,7 +20257,6 @@ function createCloudflareOnlyRuntimeWorker(options = {}) {
19233
20257
  return scopeIdentityMissingResponse();
19234
20258
  }
19235
20259
  const durableHopObserver = createG60DurableHopObserver(env.D1, (promise) => ctx.waitUntil(promise));
19236
- const url = new URL(request.url);
19237
20260
  if (url.pathname === "/api/sekiban/serialized/commit") {
19238
20261
  return handleSerializedCommit(request, env, {
19239
20262
  domainDeliveryClass: options.config?.deliveryClass,
@@ -19287,9 +20310,16 @@ function createCloudflareOnlyRuntimeWorker(options = {}) {
19287
20310
  }
19288
20311
  if (url.pathname === "/internal/downstream/drain" && request.method === "POST") {
19289
20312
  if (durableHopObserver === void 0) {
19290
- return handleOutboxDrainRequest(request, env, { acknowledgement: "global-receipt" });
20313
+ return handleOutboxDrainRequest(request, env, {
20314
+ acknowledgement: "global-receipt",
20315
+ serviceIdentityProvider: serviceIdentity
20316
+ });
19291
20317
  }
19292
- return handleOutboxDrainRequest(request, env, { acknowledgement: "global-receipt", durableHopObserver });
20318
+ return handleOutboxDrainRequest(request, env, {
20319
+ acknowledgement: "global-receipt",
20320
+ durableHopObserver,
20321
+ serviceIdentityProvider: serviceIdentity
20322
+ });
19293
20323
  }
19294
20324
  if (url.pathname === "/internal/projection/lag") {
19295
20325
  return handleProjectionLag(request, env, composition.projectors, storeProvider, serviceIdentity);
@@ -19440,14 +20470,19 @@ export {
19440
20470
  MAX_SERVICE_BINDING_INVOCATIONS_PER_REQUEST,
19441
20471
  ScopeNameError,
19442
20472
  ServiceIdentityMissingError,
20473
+ ShardRotationError,
19443
20474
  TEST_SERVICE_ID_HEADER,
19444
20475
  TagDurableObject2 as TagDurableObject,
19445
20476
  TagStateDurableObject2 as TagStateDurableObject,
20477
+ admitActiveWrite,
20478
+ assertNoSilentLedgerMerge,
20479
+ assertStrictlyBefore,
19446
20480
  buildScopeName,
19447
20481
  classifyDirectDoorbellFailure,
19448
20482
  cleanupG42JournalProbeTrial,
19449
20483
  createCloudflareOnlyRuntimeWorker,
19450
20484
  createG60DurableHopObserver,
20485
+ createRotationState,
19451
20486
  cloudflare_default as default,
19452
20487
  deliveryCorrelationId,
19453
20488
  downstreamEnvelopeBytes,
@@ -19460,6 +20495,7 @@ export {
19460
20495
  isScopeServiceId,
19461
20496
  markG65DirectApplyFinished,
19462
20497
  markG65DirectApplyStarted,
20498
+ maxSortableUniqueId,
19463
20499
  measureG42JournalProbeTrial,
19464
20500
  observeFaultBarrier,
19465
20501
  observeG60UnsafeWriter,
@@ -19477,8 +20513,14 @@ export {
19477
20513
  recordDurableUnsafeWriterBoundary,
19478
20514
  recordFirstUnsafeVisibleRead,
19479
20515
  recordG65DirectRing,
20516
+ recordLateArrival,
20517
+ refuseSafeWindowSeal,
20518
+ refuseSealedWrite,
20519
+ refuseSilentLedgerMerge,
20520
+ replaceSealedIdentity,
19480
20521
  requestServiceIdentity,
19481
20522
  requireServiceIdentity,
20523
+ rotateAppend,
19482
20524
  runG42JournalProbeTrial,
19483
20525
  scheduledLiveProjectionMaximumSuid,
19484
20526
  scopeIdFor,