@cmmd-center/forge 0.13.116 → 0.13.118

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 (35) hide show
  1. package/dist/bin.cjs +246 -10
  2. package/dist/bin.mjs +273 -35
  3. package/dist/client/assets/CanvasPanel-BOh2xUZv.js +441 -0
  4. package/dist/client/assets/{CompositeItem-B299hxbI.js → CompositeItem-DNVaubQt.js} +2 -2
  5. package/dist/client/assets/DiffPanel-DUNnxsQq.js +64 -0
  6. package/dist/client/assets/{DiffPanel.logic-CIKSbFr7.js → DiffPanel.logic-B5u-aRQa.js} +2 -2
  7. package/dist/client/assets/{DiffWorkerPoolProvider-D0KelzWk.js → DiffWorkerPoolProvider-CACmXsZU.js} +53 -53
  8. package/dist/client/assets/PullRequestCodePanel-QgCd7SjY.js +5 -0
  9. package/dist/client/assets/ThemeEditorPanel-v2mnY18G.js +2 -0
  10. package/dist/client/assets/Virtualizer-DIbjvGwY.js +2 -0
  11. package/dist/client/assets/WorkerPoolContext-DR8-tB5e.js +2538 -0
  12. package/dist/client/assets/canvasStateStore-xaZAenqH.js +2 -0
  13. package/dist/client/assets/debouncer-BmyJL8Gi.js +2 -0
  14. package/dist/client/assets/index-DbDT5T6P.js +169 -0
  15. package/dist/client/assets/index-DcAyKQAA.css +1 -0
  16. package/dist/client/assets/popover-Cxnw5kve.js +2 -0
  17. package/dist/client/assets/scroll-area-DDcW71H4.js +2 -0
  18. package/dist/client/assets/switch-Wi-2Dkh9.js +2 -0
  19. package/dist/client/assets/themePalette-eOA8OvYM.js +5 -0
  20. package/dist/client/assets/toggle-group-Cqh7gA8I.js +2 -0
  21. package/dist/client/assets/{toggle-C__ZPx5_.js → toggle-m8ncTpRB.js} +2 -2
  22. package/dist/client/assets/useOpenInteractionType-CN3hnnfp.js +2 -0
  23. package/dist/client/index.html +15 -9
  24. package/dist/forge-build.json +1 -1
  25. package/dist/{open-2-reBrpv.mjs → open-yHTUkd2Y.mjs} +3 -3
  26. package/package.json +1 -1
  27. package/dist/client/assets/CanvasPanel-DfDGOzVI.js +0 -441
  28. package/dist/client/assets/DiffPanel-CvrMUMq8.js +0 -64
  29. package/dist/client/assets/PullRequestCodePanel-CnW8NFMv.js +0 -5
  30. package/dist/client/assets/Virtualizer-BG7EhGpB.js +0 -2
  31. package/dist/client/assets/WorkerPoolContext-Dfz6dLLM.js +0 -2541
  32. package/dist/client/assets/canvasStateStore-Zj9xTxOR.js +0 -2
  33. package/dist/client/assets/index-CzefmTbf.js +0 -169
  34. package/dist/client/assets/index-Xrh_Zyox.css +0 -1
  35. package/dist/client/assets/popover-BSkrir4t.js +0 -2
package/dist/bin.cjs CHANGED
@@ -66337,7 +66337,7 @@ function normalizeNumberish(value) {
66337
66337
  }
66338
66338
  //#endregion
66339
66339
  //#region package.json
66340
- var version$1 = "0.13.116";
66340
+ var version$1 = "0.13.118";
66341
66341
  //#endregion
66342
66342
  //#region src/sentry.ts
66343
66343
  const SERVER_APP_NAME = "forge-server";
@@ -95424,6 +95424,16 @@ var RuntimeReplicationClient = class extends require_Schema$1.Service()("forge/r
95424
95424
  * from the retry cap and registration can outlast the cap.
95425
95425
  */
95426
95426
  const RUNTIME_NOT_REGISTERED_CODE = "RUNTIME_NOT_REGISTERED";
95427
+ /**
95428
+ * CMMD returned 409 THREAD_STREAM_PAYLOAD_CONFLICT or THREAD_STREAM_HEAD_MISMATCH:
95429
+ * its canonical history for a thread generation has diverged from the batch
95430
+ * Forge just sent (forge#3620). Exported so `processRuntimeReplicationOutboxItem`
95431
+ * can tell when a recorded `fail()` may have deferred the actual repair to a
95432
+ * full re-projection instead of finishing it inline -- see
95433
+ * `RuntimeReplicationOutbox.ts`'s `fail()`/`repairThreadStreamFromRemoteConflict`
95434
+ * for the repair itself.
95435
+ */
95436
+ const THREAD_STREAM_REMOTE_CONFLICT_CODES = new Set(["THREAD_STREAM_PAYLOAD_CONFLICT", "THREAD_STREAM_HEAD_MISMATCH"]);
95427
95437
  const retryableCodes = new Set([
95428
95438
  "RUNTIME_NOT_READY",
95429
95439
  "RUNTIME_THREAD_NOT_READY",
@@ -300397,7 +300407,7 @@ function resolveBuildCommitFromEnv(env) {
300397
300407
  * environment descriptor down instead of reporting an honest "unknown".
300398
300408
  */
300399
300409
  function readBakedBuildCommit() {
300400
- return "b758fc443098891193c447a97051962c12fdbee2";
300410
+ return "1de5f431edc763d9146f9be86885d18e191ea9f7";
300401
300411
  }
300402
300412
  async function resolveServerBuildCommit(input) {
300403
300413
  if (isFullCommitSha(input.baked)) return input.baked;
@@ -314744,6 +314754,33 @@ function applyPendingThreadArchives(input) {
314744
314754
  }
314745
314755
  //#endregion
314746
314756
  //#region src/runtimeReplication/processOutboxItem.ts
314757
+ /** The thread id a `thread:<id>` outbox stream key was minted from. */
314758
+ function threadIdFromStreamKey(streamKey) {
314759
+ return ThreadId.make(streamKey.slice(7));
314760
+ }
314761
+ /**
314762
+ * Attempts `enqueueThread` gets for one outbox item before this gives up and
314763
+ * logs loudly. `dependencies.enqueueThread` is the closure RuntimeReplication.ts
314764
+ * builds for `processItem` specifically -- unlike the swallowing variant it
314765
+ * hands to the domain-event reactor and the 5-minute heartbeat (which retry
314766
+ * on their own cadence regardless), a Cause escaping this one is visible
314767
+ * here. Right after `fail()` parks a thread-events row under
314768
+ * THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING_CODE, this call is the
314769
+ * corrective re-projection that clears it; without a retry here, one failed
314770
+ * attempt left the row silently blocked until the next heartbeat, a later
314771
+ * domain event, or a manual retry (forge#3621 finding 2). A transient
314772
+ * failure gets a few immediate retries; one that survives them all is logged
314773
+ * loudly instead of disappearing.
314774
+ */
314775
+ const ENQUEUE_THREAD_RETRY_ATTEMPTS = 3;
314776
+ function enqueueThreadWithBoundedRetry(enqueueThread, threadId, context, attemptsRemaining = ENQUEUE_THREAD_RETRY_ATTEMPTS) {
314777
+ return enqueueThread(threadId).pipe(require_Schema$1.catchCause((cause) => attemptsRemaining > 1 ? enqueueThreadWithBoundedRetry(enqueueThread, threadId, context, attemptsRemaining - 1) : require_Schema$1.logError("Runtime replication thread re-projection failed after retrying; it will run again on the next heartbeat, domain event, or manual retry.", {
314778
+ ...context,
314779
+ threadId,
314780
+ cause,
314781
+ attempts: ENQUEUE_THREAD_RETRY_ATTEMPTS
314782
+ })));
314783
+ }
314747
314784
  function publicationMetricAttributes(item, outcome, failure) {
314748
314785
  return {
314749
314786
  operation: item.operation,
@@ -314781,7 +314818,12 @@ function processRuntimeReplicationOutboxItem(item, dependencies) {
314781
314818
  failureKind: failure.kind,
314782
314819
  errorCode: failure.code
314783
314820
  });
314821
+ return;
314784
314822
  }
314823
+ if (item.operation === "thread-events" && THREAD_STREAM_REMOTE_CONFLICT_CODES.has(failure.code)) yield* enqueueThreadWithBoundedRetry(dependencies.enqueueThread, threadIdFromStreamKey(item.streamKey), {
314824
+ runtimeId: item.runtimeId,
314825
+ streamKey: item.streamKey
314826
+ });
314785
314827
  });
314786
314828
  return require_Schema$1.gen(function* () {
314787
314829
  const payload = yield* require_Schema$1.sync(() => {
@@ -314822,7 +314864,10 @@ function processRuntimeReplicationOutboxItem(item, dependencies) {
314822
314864
  return require_Schema$1.all([
314823
314865
  increment(runtimeReplicationPublicationAttemptsTotal, publicationMetricAttributes(item, "success")),
314824
314866
  require_Schema$1.update(require_Schema$1.withAttributes(runtimeReplicationPublicationLatency, metricAttributes({ operation: item.operation })), require_Schema$1.millis(publicationLatency)),
314825
- item.operation === "thread-events" ? dependencies.enqueueThread(ThreadId.make(item.streamKey.slice(7))) : require_Schema$1.void_
314867
+ item.operation === "thread-events" ? enqueueThreadWithBoundedRetry(dependencies.enqueueThread, threadIdFromStreamKey(item.streamKey), {
314868
+ runtimeId: item.runtimeId,
314869
+ streamKey: item.streamKey
314870
+ }) : require_Schema$1.void_
314826
314871
  ]).pipe(require_Schema$1.asVoid);
314827
314872
  }))
314828
314873
  }));
@@ -314899,15 +314944,16 @@ const RuntimeReplicationLive = require_Schema$1.effect(RuntimeReplication, requi
314899
314944
  operation: "inventory",
314900
314945
  payload
314901
314946
  }) : require_Schema$1.void_;
314902
- const enqueueThread = (threadId) => runtimeId ? snapshots.getThreadDetailById(threadId).pipe(require_Schema$1.flatMap((thread) => require_Schema$1.isSome(thread) ? logTurnsMissingModelSelection(threadId, thread.value).pipe(require_Schema$1.andThen(outbox.enqueueThread({
314947
+ const enqueueThreadUnsafe = (threadId) => runtimeId ? snapshots.getThreadDetailById(threadId).pipe(require_Schema$1.flatMap((thread) => require_Schema$1.isSome(thread) ? logTurnsMissingModelSelection(threadId, thread.value).pipe(require_Schema$1.andThen(outbox.enqueueThread({
314903
314948
  runtimeId,
314904
314949
  streamKey: `thread:${threadId}`,
314905
314950
  events: serializeRuntimeThreadEvents(thread.value),
314906
314951
  historyFinalized: thread.value.archivedAt != null
314907
- }))) : outbox.remove(runtimeId, `thread:${threadId}`)), require_Schema$1.catchCause((cause) => require_Schema$1.logError("Runtime replication thread projection failed.", {
314952
+ }))) : outbox.remove(runtimeId, `thread:${threadId}`)), require_Schema$1.orDie) : require_Schema$1.void_;
314953
+ const enqueueThread = (threadId) => enqueueThreadUnsafe(threadId).pipe(require_Schema$1.catchCause((cause) => require_Schema$1.logError("Runtime replication thread projection failed.", {
314908
314954
  cause,
314909
314955
  threadId
314910
- }))) : require_Schema$1.void_;
314956
+ })));
314911
314957
  const projectEvent = (event) => runtimeId ? activeHourMeter.markAwake(runtimeId).pipe(require_Schema$1.andThen(require_Schema$1.all([snapshots.getShellSnapshot(), providerRegistry.getProviders])), require_Schema$1.flatMap(([snapshot, providers]) => {
314912
314958
  const inventory = serializeRuntimeInventory(snapshot, providers);
314913
314959
  const threadId = event.aggregateKind === "thread" ? ThreadId.make(event.aggregateId) : null;
@@ -314920,7 +314966,7 @@ const RuntimeReplicationLive = require_Schema$1.effect(RuntimeReplication, requi
314920
314966
  const processItem = (item) => processRuntimeReplicationOutboxItem(item, {
314921
314967
  outbox,
314922
314968
  client,
314923
- enqueueThread
314969
+ enqueueThread: enqueueThreadUnsafe
314924
314970
  });
314925
314971
  const drain = outbox.claim(BATCH_SIZE).pipe(require_Schema$1.flatMap((items) => require_Schema$1.forEach(items, processItem, { concurrency: 1 })), require_Schema$1.catchCause((cause) => require_Schema$1.logError("Runtime replication outbox drain failed.", { cause })));
314926
314972
  const start = () => {
@@ -315016,7 +315062,14 @@ const RuntimeReplicationLive = require_Schema$1.effect(RuntimeReplication, requi
315016
315062
  observeOutbox
315017
315063
  ]).pipe(require_Schema$1.asVoid);
315018
315064
  };
315019
- return RuntimeReplication.of({ start });
315065
+ const retryReprojectionPending = (streamKeys) => require_Schema$1.forEach(streamKeys, (streamKey) => enqueueThread(threadIdFromStreamKey(streamKey)), {
315066
+ concurrency: 1,
315067
+ discard: true
315068
+ });
315069
+ return RuntimeReplication.of({
315070
+ start,
315071
+ retryReprojectionPending
315072
+ });
315020
315073
  }));
315021
315074
  //#endregion
315022
315075
  //#region src/runtimeReplication/activeHourProtocol.ts
@@ -315315,6 +315368,100 @@ const RUNTIME_REPLICATION_RETRY_EXHAUSTED_CODE = "RUNTIME_REPLICATION_RETRY_EXHA
315315
315368
  * claims it; only `recover()` and the manual retry endpoint do.
315316
315369
  */
315317
315370
  const THREAD_STREAM_PAYLOAD_HASH_MISMATCH_CODE = "THREAD_STREAM_PAYLOAD_HASH_MISMATCH";
315371
+ /**
315372
+ * CMMD returned 409 THREAD_STREAM_PAYLOAD_CONFLICT or THREAD_STREAM_HEAD_MISMATCH:
315373
+ * its canonical history for this generation has diverged from the batch Forge
315374
+ * just sent (forge#3620). The common trigger is CMMD's own reclaim job
315375
+ * replacing the Sprite (CMMD-Center/CMMD#5865) mid-turn, which wipes this
315376
+ * runtime's local `runtime_replication_streams` cursor; Forge then rebuilds a
315377
+ * batch from sequence 1 that CMMD, still holding the old generation's
315378
+ * acknowledged history, refuses. `fail()` recovers by starting a brand-new
315379
+ * repair generation from sequence 1 with an empty previous head -- the one
315380
+ * shape CMMD's `validateRuntimeThreadAppend` accepts unconditionally as a
315381
+ * reset -- rather than blocking the thread forever.
315382
+ *
315383
+ * The refused batch's own `events` are never safe to rebuild that repair from
315384
+ * directly, regardless of `fromSequence`. A batch is capped at `batchSize`
315385
+ * (500, see `buildRuntimeThreadBatch` in protocol.ts) and `isFinalBatch` is
315386
+ * computed relative to whatever array it was handed -- so re-running
315387
+ * `buildRuntimeThreadBatch` on a refused batch's own, already-truncated
315388
+ * `events` array makes an 800-event thread's 500-event suffix look like a
315389
+ * complete 500-event history all over again, `isFinalBatch: true` included.
315390
+ * CMMD accepts that as this generation's full canonical history on the reset
315391
+ * rule and events 501 onward are gone for good (CodeRabbit finding on
315392
+ * forge#3621, forge#3620 finding 1). This holds even at `fromSequence === 1`:
315393
+ * a fresh generation's very first batch is truncated exactly the same way
315394
+ * once the thread has more events than `batchSize`.
315395
+ *
315396
+ * `fail()` instead always resets the local cursor to a new repair generation
315397
+ * and parks the row blocked under
315398
+ * `THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING_CODE` until
315399
+ * `processRuntimeReplicationOutboxItem` re-derives the FULL thread history
315400
+ * through the same `enqueueThread` projection path the success path already
315401
+ * runs after every publish (see `processOutboxItem.ts`) and overwrites this
315402
+ * row with a correctly full batch. That re-projection reads the domain
315403
+ * model's complete event list, not a persisted batch's truncated `events`,
315404
+ * so it is safe to rebuild from no matter how many events the thread holds.
315405
+ *
315406
+ * The reset is bounded to one per distinct conflict, keyed on whether the
315407
+ * reset itself has made any progress: see `refusedResetIsStuck` below. The
315408
+ * re-projection failing to land promptly does not strand the row forever --
315409
+ * `processRuntimeReplicationOutboxItem` retries it a bounded number of times
315410
+ * before giving up for this cycle, the 5-minute replication heartbeat and any
315411
+ * later domain event on this thread call `enqueueThread` again regardless,
315412
+ * and the manual `/api/runtime-replication/retry` endpoint calls it directly
315413
+ * for rows parked under this code (see `RuntimeReplication.ts`'s
315414
+ * `retryReprojectionPending`).
315415
+ */
315416
+ const THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING_CODE = "THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING";
315417
+ /**
315418
+ * Whether a refused batch is the exact canonical reset shape (`fromSequence
315419
+ * === 1`, empty previous head, deterministic content) under a generation the
315420
+ * local cursor already holds with zero acknowledged progress -- i.e. this
315421
+ * exact reset was already sent once and CMMD refused it again, which makes
315422
+ * it genuinely corrupt local history rather than a race to retry. Applies to
315423
+ * any non-base generation (both the `:repair:` suffix this file mints and
315424
+ * the `:final:` suffix `runtimeThreadFinalGenerationId` mints for an
315425
+ * archived thread's first post-transition batch -- both always start a fresh
315426
+ * generation at sequence 1 from an empty head the same way).
315427
+ *
315428
+ * The base generation is exempt unconditionally: its own first-sequence
315429
+ * conflict is the original, always-eligible incident trigger (Forge's local
315430
+ * cursor was wiped and it resent from scratch), not a repeat of an
315431
+ * already-attempted reset. A repair or final generation that already made
315432
+ * progress (`fromSequence > 1` under it) is exempt too -- CMMD acknowledged
315433
+ * it at least once, so a later refusal is a new, unrelated conflict and
315434
+ * earns its own fresh reset (forge#3620 finding 2); the bound must not key
315435
+ * on a generation id merely containing `:repair:`/`:final:`, or a thread
315436
+ * repaired once could never recover from a later, unrelated conflict.
315437
+ */
315438
+ function refusedResetIsStuck(input) {
315439
+ if (input.refusedGenerationId === input.baseGenerationId) return false;
315440
+ if (input.refusedFromSequence !== 1) return false;
315441
+ return input.cursor === void 0 || input.cursor.generationId !== input.refusedGenerationId || input.cursor.acknowledgedSequence === 0;
315442
+ }
315443
+ /**
315444
+ * The generation id, starting sequence, and raw source events out of a
315445
+ * persisted thread batch, read straight off the JSON rather than through
315446
+ * `decodeThreadBatch` -- that schema only keeps `sequence`/`payloadHash` per
315447
+ * event, and a repair needs the full canonical fields to re-hash from
315448
+ * scratch. Extra fields (the old `sequence`/`payloadHash`) are harmless:
315449
+ * `buildRuntimeThreadBatch` overwrites both and its hasher reads only the
315450
+ * named canonical fields.
315451
+ */
315452
+ function parseThreadBatchForRepair(payloadJson) {
315453
+ try {
315454
+ const parsed = JSON.parse(payloadJson);
315455
+ if (typeof parsed.generationId !== "string" || typeof parsed.fromSequence !== "number" || !Array.isArray(parsed.events)) return null;
315456
+ return {
315457
+ generationId: parsed.generationId,
315458
+ fromSequence: parsed.fromSequence,
315459
+ events: parsed.events
315460
+ };
315461
+ } catch {
315462
+ return null;
315463
+ }
315464
+ }
315318
315465
  const STARTUP_RECOVERABLE_BLOCKED_CODES = [
315319
315466
  ...CLAIMABLE_BLOCKED_CODES,
315320
315467
  "RUNTIME_NOT_READY",
@@ -315525,6 +315672,26 @@ const retryBlockedRuntimeReplicationOutbox = require_Schema$1.gen(function* () {
315525
315672
  RETURNING stream_key AS "streamKey"
315526
315673
  `).length;
315527
315674
  }).pipe(require_Schema$1.orDie);
315675
+ /**
315676
+ * Thread streams parked under THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING_CODE,
315677
+ * for the manual `/api/runtime-replication/retry` endpoint. This code is deliberately
315678
+ * absent from MANUALLY_RECOVERABLE_BLOCKED_CODES: flipping the row back to `pending`
315679
+ * the way `retryBlockedRuntimeReplicationOutbox` does for other blocked codes would
315680
+ * requeue the same truncated payload `fail()` already refused, undoing the very repair
315681
+ * it just started. `http.ts`'s retry handler passes these to `RuntimeReplication`'s
315682
+ * `retryReprojectionPending`, which re-runs `enqueueThread` for each -- the same
315683
+ * corrective re-projection that already clears this code after every publish and after
315684
+ * every conflict (forge#3621 finding 2). No `runtimeId` filter, matching
315685
+ * `retryBlockedRuntimeReplicationOutbox` above: this outbox table belongs to one Forge
315686
+ * server.
315687
+ */
315688
+ const readReprojectionPendingThreadStreamKeys = require_Schema$1.gen(function* () {
315689
+ return (yield* (yield* require_SqlError.SqlClient)`
315690
+ SELECT stream_key AS "streamKey" FROM runtime_replication_outbox
315691
+ WHERE operation = 'thread-events' AND status = 'blocked'
315692
+ AND last_error_code = ${THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING_CODE}
315693
+ `).map((row) => row.streamKey);
315694
+ }).pipe(require_Schema$1.orDie);
315528
315695
  const RuntimeReplicationOutboxLive = require_Schema$1.effect(RuntimeReplicationOutbox, require_Schema$1.gen(function* () {
315529
315696
  const sql = yield* require_SqlError.SqlClient;
315530
315697
  const upsertPayload = (input) => {
@@ -316052,7 +316219,69 @@ const RuntimeReplicationOutboxLive = require_Schema$1.effect(RuntimeReplicationO
316052
316219
  discard: true
316053
316220
  });
316054
316221
  })).pipe(require_Schema$1.orDie);
316055
- const fail = (item, failure) => {
316222
+ /**
316223
+ * Recovers from a CMMD-reported thread stream conflict (see
316224
+ * THREAD_STREAM_REMOTE_CONFLICT_CODES). Returns `null` when this item is
316225
+ * not eligible (its payload does not decode, or `refusedResetIsStuck`
316226
+ * says the exact reset shape already failed once -- in which case the
316227
+ * caller falls back to blocking) and `false` when the row was superseded
316228
+ * before this could apply, mirroring `fail`'s own supersession signal.
316229
+ * Otherwise replaces the local cursor with a brand-new repair generation
316230
+ * from sequence 1, empty previous head -- the shape CMMD's reset rule
316231
+ * accepts unconditionally -- and parks the row blocked under
316232
+ * `THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING_CODE`, deferring the
316233
+ * actual rebuild to the caller's next full re-projection regardless of
316234
+ * `fromSequence` (see the big comment above
316235
+ * `THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING_CODE`): the refused
316236
+ * batch's own `events` are truncated at `batchSize` the same way whether
316237
+ * this was its first batch or its tenth, so rebuilding from them directly
316238
+ * can silently drop everything past the cap.
316239
+ */
316240
+ const repairThreadStreamFromRemoteConflict = (item, failure) => require_Schema$1.gen(function* () {
316241
+ const parsedBatch = parseThreadBatchForRepair(item.payloadJson);
316242
+ if (!parsedBatch) return null;
316243
+ const baseGenerationId = runtimeThreadGenerationId(item.runtimeId, item.streamKey);
316244
+ const cursor = yield* readThreadCursor({
316245
+ runtimeId: item.runtimeId,
316246
+ streamKey: item.streamKey
316247
+ });
316248
+ if (refusedResetIsStuck({
316249
+ baseGenerationId,
316250
+ refusedGenerationId: parsedBatch.generationId,
316251
+ refusedFromSequence: parsedBatch.fromSequence,
316252
+ cursor
316253
+ })) return null;
316254
+ const now = (/* @__PURE__ */ new Date()).toISOString();
316255
+ const repairGenerationId = `${baseGenerationId}:repair:${node_crypto.randomUUID()}`;
316256
+ const message = `Runtime replication conflict (${failure.code}) refused a thread-events batch; deferring to a full-history re-projection under a new repair generation.`;
316257
+ if (!(yield* sql.withTransaction(require_Schema$1.gen(function* () {
316258
+ if ((yield* sql`
316259
+ UPDATE runtime_replication_outbox SET
316260
+ status = 'blocked', next_attempt_at = '9999-12-31T23:59:59.999Z',
316261
+ last_error_code = ${"THREAD_STREAM_REMOTE_CONFLICT_REPROJECTION_PENDING"},
316262
+ last_error = ${message}, updated_at = ${now}
316263
+ WHERE runtime_id = ${item.runtimeId} AND stream_key = ${item.streamKey}
316264
+ AND payload_hash = ${item.payloadHash}
316265
+ RETURNING runtime_id AS "runtimeId"
316266
+ `).length !== 1) return false;
316267
+ yield* replaceThreadCursor({
316268
+ runtimeId: item.runtimeId,
316269
+ streamKey: item.streamKey,
316270
+ generationId: repairGenerationId,
316271
+ now
316272
+ });
316273
+ return true;
316274
+ })))) return false;
316275
+ yield* require_Schema$1.logWarning("Runtime replication deferred a thread-stream repair to a full re-projection after a remote conflict.", {
316276
+ runtimeId: item.runtimeId,
316277
+ streamKey: item.streamKey,
316278
+ errorCode: failure.code,
316279
+ previousGenerationId: parsedBatch.generationId,
316280
+ repairGenerationId
316281
+ });
316282
+ return true;
316283
+ }).pipe(require_Schema$1.orDie);
316284
+ const failGeneric = (item, failure) => {
316056
316285
  const attempts = item.attemptCount + 1;
316057
316286
  const exhausted = failure.kind === "retryable" && attempts >= 8 && failure.code !== "RUNTIME_NOT_REGISTERED";
316058
316287
  const retryable = failure.kind === "retryable" && !exhausted;
@@ -316067,6 +316296,10 @@ const RuntimeReplicationOutboxLive = require_Schema$1.effect(RuntimeReplicationO
316067
316296
  RETURNING runtime_id AS "runtimeId"
316068
316297
  `.pipe(require_Schema$1.map((rows) => rows.length === 1), require_Schema$1.orDie);
316069
316298
  };
316299
+ const fail = (item, failure) => {
316300
+ if (item.operation !== "thread-events" || !THREAD_STREAM_REMOTE_CONFLICT_CODES.has(failure.code)) return failGeneric(item, failure);
316301
+ return repairThreadStreamFromRemoteConflict(item, failure).pipe(require_Schema$1.flatMap((repaired) => repaired === null ? failGeneric(item, failure) : require_Schema$1.succeed(repaired)));
316302
+ };
316070
316303
  const retryBlocked = () => retryBlockedRuntimeReplicationOutbox.pipe(require_Schema$1.provideService(require_SqlError.SqlClient, sql));
316071
316304
  const recover = () => sql`
316072
316305
  UPDATE runtime_replication_outbox SET status = 'pending',
@@ -316245,10 +316478,13 @@ const statusHandler = require_Schema$1.gen(function* () {
316245
316478
  const retryHandler = require_Schema$1.gen(function* () {
316246
316479
  const request = yield* require_HttpServer.HttpServerRequest;
316247
316480
  yield* (yield* ServerAuth).authenticateHttpRequest(request);
316481
+ const replication = yield* require_Schema$1.serviceOption(RuntimeReplication);
316248
316482
  const requeued = yield* retryBlockedRuntimeReplicationOutbox;
316483
+ const reprojectionPendingStreamKeys = yield* readReprojectionPendingThreadStreamKeys;
316484
+ if (require_Schema$1.isSome(replication)) yield* replication.value.retryReprojectionPending(reprojectionPendingStreamKeys);
316249
316485
  const status = yield* readRuntimeReplicationOutboxStatus;
316250
316486
  return require_HttpServer.jsonUnsafe({
316251
- requeued,
316487
+ requeued: requeued + (require_Schema$1.isSome(replication) ? reprojectionPendingStreamKeys.length : 0),
316252
316488
  ...responseFromStatus(status)
316253
316489
  });
316254
316490
  }).pipe(require_Schema$1.catchTag("AuthError", respondToAuthError));