gencow 0.1.214 → 0.1.216

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.
@@ -16,7 +16,14 @@ const APP_DELETE_ACTIVE_STATES = new Set([
16
16
  "failed_tenant_db_cleanup",
17
17
  "failed_catalog_cleanup",
18
18
  ]);
19
- const APP_DELETE_TERMINAL_FAILURE_STATES = new Set(["blocked_catalog_outcome_unknown"]);
19
+ const APP_DELETE_TERMINAL_FAILURE_STATES = new Set([
20
+ "blocked_catalog_outcome_unknown",
21
+ "failed_delete_recovery_required",
22
+ ]);
23
+ const APP_DELETE_RESPONSE_STATES = new Set([
24
+ ...APP_DELETE_ACTIVE_STATES,
25
+ ...APP_DELETE_TERMINAL_FAILURE_STATES,
26
+ ]);
20
27
  const CORRELATION_ID_PATTERN = /^[A-Za-z0-9_-]{8,128}$/u;
21
28
  const DIAGNOSTIC_CODE_PATTERN = /^[A-Za-z][A-Za-z0-9_]{2,127}$/u;
22
29
  const APP_ID_PATTERN = /^(?=.{3,63}$)[a-z][a-z0-9]*(?:-[a-z0-9]+){2,7}$/u;
@@ -44,7 +51,7 @@ export function parseAppDeleteOperationEnvelope(value, expectedAppId) {
44
51
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
45
52
  if (value.success !== undefined && value.success !== false) return null;
46
53
  if (!APP_DELETE_OPERATION_PATTERN.test(value.operationId ?? "")) return null;
47
- if (!APP_DELETE_ACTIVE_STATES.has(value.state)) return null;
54
+ if (!APP_DELETE_RESPONSE_STATES.has(value.state)) return null;
48
55
  if (
49
56
  !CORRELATION_ID_PATTERN.test(value.correlationId ?? "") ||
50
57
  (value.deleted !== undefined && value.deleted !== expectedAppId) ||
@@ -164,6 +164,19 @@ export async function deployBackendPackage({
164
164
  }
165
165
 
166
166
  if (!deployed) return null;
167
+ // Persist the production target before finalize. Finalize is a separate durable
168
+ // release effect; if it fails, the next customer retry must reuse this exact
169
+ // app instead of creating a second production child.
170
+ if (envTarget === "prod") {
171
+ writeProjectMetadata({
172
+ appId: deployed.appId,
173
+ displayName,
174
+ envTarget,
175
+ platformUrl: creds.platformUrl,
176
+ gencowJsonPath,
177
+ writeFileSyncImpl,
178
+ });
179
+ }
167
180
  if (releaseAttempt && finalizeReleaseAttempt) {
168
181
  try {
169
182
  await finalizeReleaseAttempt({ appId: deployed.appId, attemptId: releaseAttempt.attemptId });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gencow",
3
- "version": "0.1.214",
3
+ "version": "0.1.216",
4
4
  "description": "Gencow — AI Backend Engine",
5
5
  "type": "module",
6
6
  "bin": {
@@ -33,8 +33,8 @@
33
33
  "devDependencies": {
34
34
  "@types/node": "^25.9.5",
35
35
  "better-auth": "^1.6.23",
36
- "@gencow/client": "0.2.7",
37
36
  "@gencow/core": "0.1.43",
37
+ "@gencow/client": "0.2.7",
38
38
  "@gencow/react": "0.2.7"
39
39
  },
40
40
  "scripts": {
@@ -110824,9 +110824,14 @@ function registerPlatformSlotPromotionRoute(params) {
110824
110824
  }
110825
110825
  state2 = "promoting";
110826
110826
  const approval = routeProjectionDegradedApprovalFromRequest(c);
110827
- const currentEvidence = await params.assertTenantRouteParity?.(approval);
110828
- if (!currentEvidence || currentEvidence.bindingCount !== preparedEvidence.bindingCount || currentEvidence.evidenceDigest !== preparedEvidence.evidenceDigest)
110829
- throw new Error("PLATFORM_TENANT_ROUTE_PARITY_EVIDENCE_CHANGED");
110827
+ let currentEvidence = await params.assertTenantRouteParity?.(approval);
110828
+ if (!currentEvidence || currentEvidence.bindingCount !== preparedEvidence.bindingCount || currentEvidence.evidenceDigest !== preparedEvidence.evidenceDigest) {
110829
+ await params.autoRecoveryRuntime.promote();
110830
+ currentEvidence = await params.assertTenantRouteParity?.(approval);
110831
+ if (!currentEvidence || currentEvidence.bindingCount !== preparedEvidence.bindingCount || currentEvidence.evidenceDigest !== preparedEvidence.evidenceDigest) {
110832
+ throw new Error("PLATFORM_TENANT_ROUTE_PARITY_EVIDENCE_CHANGED");
110833
+ }
110834
+ }
110830
110835
  params.setCandidateMode(false);
110831
110836
  state2 = "active";
110832
110837
  logger3.log("[platform] standby candidate promoted to active runtime mode");
@@ -149200,6 +149205,7 @@ async function bootstrapRuntimeRouteProjectionForPlatform(input) {
149200
149205
  return {
149201
149206
  convergeServingFleet: runtime.convergeServingFleet,
149202
149207
  isAppProjectionBlocked: runtime.isAppProjectionBlocked,
149208
+ resolveExistingOnlyRoute: runtime.resolveExistingOnlyRoute,
149203
149209
  setAbsentRouteConverger: runtime.setAbsentRouteConverger,
149204
149210
  startAfter,
149205
149211
  startAfterRecovery
@@ -152045,13 +152051,55 @@ function rejectNodeMismatch(c, enabled, currentNodeId, homeNodeId) {
152045
152051
  code: "APP_RUNTIME_EXISTING_ROUTE_NODE_MISMATCH"
152046
152052
  }, 409);
152047
152053
  }
152048
- function routeUnavailable(c) {
152054
+ function routeResolutionUnavailable(c, result2) {
152049
152055
  return c.json({
152050
- error: "Exact serving runtime is not mapped on this platform candidate",
152051
- code: "APP_RUNTIME_EXISTING_ROUTE_UNAVAILABLE",
152052
- status: "unavailable"
152056
+ error: "Exact serving runtime is not available on this platform slot",
152057
+ code: result2.code,
152058
+ status: result2.status
152053
152059
  }, 503);
152054
152060
  }
152061
+ async function proxyResolvedExistingOnlyRoute(input) {
152062
+ const route = await input.resolveRoute?.(input.appId);
152063
+ if (!route || route.kind !== "ready") {
152064
+ return routeResolutionUnavailable(input.c, route ?? { code: "APP_RUNTIME_EXISTING_ROUTE_UNAVAILABLE", status: "unavailable" });
152065
+ }
152066
+ try {
152067
+ return await input.proxyRequest({
152068
+ c: input.c,
152069
+ host: input.host,
152070
+ appName: input.appName,
152071
+ port: route.port,
152072
+ url: input.url,
152073
+ requestBody: input.requestBody,
152074
+ addProxyMetric: input.addProxyMetric
152075
+ });
152076
+ } catch {
152077
+ return routeResolutionUnavailable(input.c, {
152078
+ code: "APP_RUNTIME_EXISTING_ROUTE_UNAVAILABLE",
152079
+ status: "unavailable"
152080
+ });
152081
+ }
152082
+ }
152083
+ async function resolveExistingOnlyRoutePort(input) {
152084
+ const route = await input.resolveRoute?.(input.appId);
152085
+ if (!route || route.kind !== "ready") {
152086
+ return routeResolutionUnavailable(input.c, route ?? { code: "APP_RUNTIME_EXISTING_ROUTE_UNAVAILABLE", status: "unavailable" });
152087
+ }
152088
+ return route.port;
152089
+ }
152090
+ async function resolveWebsocketPort(input) {
152091
+ if (input.existingOnly) {
152092
+ return resolveExistingOnlyRoutePort({
152093
+ c: input.c,
152094
+ appId: input.appRow.id,
152095
+ resolveRoute: input.resolveRoute
152096
+ });
152097
+ }
152098
+ const runtime = await input.recover();
152099
+ if (runtime.kind === "unavailable")
152100
+ return input.c.json(runtime, runtime.httpStatus);
152101
+ return runtime.port;
152102
+ }
152055
152103
  async function acquireRuntimeActivity(params) {
152056
152104
  if (params.existingOnlyRuntimeProbe)
152057
152105
  return void 0;
@@ -153315,12 +153363,12 @@ var init_server_serving_plane_dependency_metrics = __esm({
153315
153363
  }
153316
153364
  });
153317
153365
 
153318
- // ../server/dist/server-platform-app-proxy.js
153366
+ // ../server/dist/server-platform-app-proxy-routing.js
153319
153367
  function isPublicAppBackendRoute(pathname) {
153320
153368
  return /^\/(api|platform|internal|ws)\b/.test(pathname);
153321
153369
  }
153322
153370
  function isDeniedPublicAppSystemPath(pathname) {
153323
- return /^\/(_admin|_dashboard)\b/.test(pathname);
153371
+ return /^\/(?:_admin|_dashboard)\b/.test(pathname);
153324
153372
  }
153325
153373
  function classifyServingPlaneRequest(pathname, upgradeHeader) {
153326
153374
  if (pathname.startsWith("/_gencow/analytics"))
@@ -153334,6 +153382,13 @@ function classifyServingPlaneRequest(pathname, upgradeHeader) {
153334
153382
  return "backend_http";
153335
153383
  return "static_candidate";
153336
153384
  }
153385
+ var init_server_platform_app_proxy_routing = __esm({
153386
+ "../server/dist/server-platform-app-proxy-routing.js"() {
153387
+ "use strict";
153388
+ }
153389
+ });
153390
+
153391
+ // ../server/dist/server-platform-app-proxy.js
153337
153392
  async function proxyToBackendWithRecoveryInternal(params) {
153338
153393
  if (params.appRow.status === "memory_exceeded") {
153339
153394
  const unavailable2 = params.buildAppRuntimeUnavailableResult(params.appRow.name, params.appRow.status, params.appRow.statusReason);
@@ -153364,7 +153419,17 @@ async function proxyToBackendWithRecoveryInternal(params) {
153364
153419
  }
153365
153420
  }
153366
153421
  if (params.existingOnlyRuntimeProbe)
153367
- return routeUnavailable(params.c);
153422
+ return proxyResolvedExistingOnlyRoute({
153423
+ c: params.c,
153424
+ host: params.host,
153425
+ appName: params.appRow.name,
153426
+ appId: params.appRow.id,
153427
+ url: params.url,
153428
+ requestBody: replayPlan.initialBody,
153429
+ addProxyMetric: params.addProxyMetric,
153430
+ proxyRequest,
153431
+ resolveRoute: params.resolveExistingOnlyRoute
153432
+ });
153368
153433
  let runtime;
153369
153434
  try {
153370
153435
  runtime = await params.ensureAppRuntimeReady(params.appRow, buildPlatformRuntimeRecoveryDeps({
@@ -153374,6 +153439,7 @@ async function proxyToBackendWithRecoveryInternal(params) {
153374
153439
  } catch (error51) {
153375
153440
  const message = error51 instanceof Error ? error51.message : String(error51);
153376
153441
  params.logger.error(`[platform] ${params.appRow.name}: runtime recovery failed: ${message}`);
153442
+ params.c.header("Retry-After", "2");
153377
153443
  return params.c.json(buildTransientProxyFailureBody(), 503);
153378
153444
  }
153379
153445
  if (runtime.kind === "unavailable") {
@@ -153400,6 +153466,7 @@ async function proxyToBackendWithRecoveryInternal(params) {
153400
153466
  } catch (error51) {
153401
153467
  const message = error51 instanceof Error ? error51.message : String(error51);
153402
153468
  params.logger.error(`[platform] ${params.appRow.name}: retry proxy failed on :${runtime.port} ${requestLabel}: ${message}`);
153469
+ params.c.header("Retry-After", "2");
153403
153470
  return params.c.json(buildTransientProxyFailureBody(), 502);
153404
153471
  }
153405
153472
  }
@@ -153622,18 +153689,23 @@ function registerPlatformAppProxy(params) {
153622
153689
  });
153623
153690
  let websocketPort = params.getLivePort(appName) || appRow.port;
153624
153691
  if (appRow.runtimeAuthorityMode === "enforce") {
153625
- const runtime = await params.ensureAppRuntimeReady(appRow, buildPlatformRuntimeRecoveryDeps({
153626
- ...params,
153627
- logger: logger3,
153628
- probePort: async (_appName, port) => probeAppPort(port)
153629
- }), {
153630
- stalePort: params.getLivePort(appName) ?? null,
153631
- currentNodeId: params.currentNodeId
153692
+ const resolvedPort = await resolveWebsocketPort({
153693
+ c,
153694
+ appRow,
153695
+ existingOnly: existingOnlyRuntimeProbe,
153696
+ resolveRoute: params.resolveExistingOnlyRoute,
153697
+ recover: async () => params.ensureAppRuntimeReady(appRow, buildPlatformRuntimeRecoveryDeps({
153698
+ ...params,
153699
+ logger: logger3,
153700
+ probePort: async (_appName, port) => probeAppPort(port)
153701
+ }), {
153702
+ stalePort: params.getLivePort(appName) ?? null,
153703
+ currentNodeId: params.currentNodeId
153704
+ })
153632
153705
  });
153633
- if (runtime.kind === "unavailable") {
153634
- return c.json(buildRuntimeUnavailableBody(runtime), runtime.httpStatus);
153635
- }
153636
- websocketPort = runtime.port;
153706
+ if (resolvedPort instanceof Response)
153707
+ return resolvedPort;
153708
+ websocketPort = resolvedPort;
153637
153709
  }
153638
153710
  let runtimeActivityLease;
153639
153711
  try {
@@ -153720,6 +153792,7 @@ function registerPlatformAppProxy(params) {
153720
153792
  addProxyMetric: params.addProxyMetric,
153721
153793
  beginRuntimeActivity: params.beginRuntimeActivity,
153722
153794
  admitRuntimeActivity: params.admitRuntimeActivity,
153795
+ resolveExistingOnlyRoute: params.resolveExistingOnlyRoute,
153723
153796
  existingOnlyRuntimeProbe
153724
153797
  });
153725
153798
  }
@@ -153761,6 +153834,7 @@ function registerPlatformAppProxy(params) {
153761
153834
  addProxyMetric: params.addProxyMetric,
153762
153835
  beginRuntimeActivity: params.beginRuntimeActivity,
153763
153836
  admitRuntimeActivity: params.admitRuntimeActivity,
153837
+ resolveExistingOnlyRoute: params.resolveExistingOnlyRoute,
153764
153838
  existingOnlyRuntimeProbe
153765
153839
  });
153766
153840
  }
@@ -153797,6 +153871,8 @@ var init_server_platform_app_proxy = __esm({
153797
153871
  init_server_platform_app_proxy_responses();
153798
153872
  init_server_platform_hosted_analytics();
153799
153873
  init_server_serving_plane_dependency_metrics();
153874
+ init_server_platform_app_proxy_routing();
153875
+ init_server_platform_app_proxy_routing();
153800
153876
  init_static_file_routing();
153801
153877
  init_server_platform_app_proxy_domain();
153802
153878
  init_server_realtime_connection_limit();
@@ -170732,7 +170808,8 @@ var init_schema_app_lifecycle_operation = __esm({
170732
170808
  'accepted', 'stopping_children', 'draining_runtime', 'stop_dispatched',
170733
170809
  'runtime_absent', 'tenant_db_drop_pending', 'catalog_delete_pending', 'completed',
170734
170810
  'blocked_ownership_ambiguous', 'blocked_active_work', 'blocked_runtime_outcome_unknown',
170735
- 'blocked_catalog_outcome_unknown', 'failed_tenant_db_cleanup', 'failed_catalog_cleanup'
170811
+ 'blocked_catalog_outcome_unknown', 'failed_tenant_db_cleanup', 'failed_catalog_cleanup',
170812
+ 'failed_delete_recovery_required'
170736
170813
  )`
170737
170814
  )
170738
170815
  ]
@@ -184114,6 +184191,12 @@ function clearCandidateCleanupFailureCode(error51) {
184114
184191
  } catch {
184115
184192
  }
184116
184193
  }
184194
+ function getDeploymentFailureCause(error51) {
184195
+ if (!error51 || typeof error51 !== "object" && typeof error51 !== "function") return null;
184196
+ const direct = error51.deploymentFailureCause;
184197
+ if (typeof direct === "string" && DEPLOYMENT_FAILURE_CAUSE_PATTERN.test(direct)) return direct;
184198
+ return DEPLOYMENT_FAILURE_CAUSE_BY_ERROR.get(error51) ?? null;
184199
+ }
184117
184200
  function attachDeploymentFailureStage(error51, stage) {
184118
184201
  if (!error51 || typeof error51 !== "object" && typeof error51 !== "function") return error51;
184119
184202
  const existing = error51.deploymentFailureStage;
@@ -184199,7 +184282,8 @@ function retry(code, message) {
184199
184282
  }
184200
184283
  function resolveGenericDeploymentFailurePolicy(input) {
184201
184284
  const explicitCode = getStableDeploymentFailureCode(input.error);
184202
- const code = explicitCode ?? (input.stage === "candidate" ? classifyCandidateFailure(input.error, input.crashLogs) : defaultFailureCode(input.stage));
184285
+ const typedArtifactCause = getDeploymentFailureCause(input.error)?.startsWith("DEPLOY_ARTIFACT_");
184286
+ const code = (typedArtifactCause ? "DEPLOY_ARTIFACT_MATERIALIZE_FAILED" : explicitCode) ?? (input.stage === "candidate" ? classifyCandidateFailure(input.error, input.crashLogs) : defaultFailureCode(input.stage));
184203
184287
  if (getCandidateCleanupFailureCode(input.error)) {
184204
184288
  return {
184205
184289
  status: 503,
@@ -184281,7 +184365,7 @@ function resolveStoredDeploymentFailurePolicy(stage, code) {
184281
184365
  error: Object.assign(new Error(code), { code })
184282
184366
  });
184283
184367
  }
184284
- var DEPLOYMENT_FAILURE_STAGE_FIELD, STABLE_CONTROL_PLANE_CODE, DEPLOYMENT_FAILURE_STAGE_SET, DEPLOYMENT_FAILURE_STAGE_BY_ERROR, CANDIDATE_CLEANUP_FAILURES, RETRYABLE_CODES, PLATFORM_OWNED_CODES, PLATFORM_OWNED_PREFIXES;
184368
+ var DEPLOYMENT_FAILURE_STAGE_FIELD, STABLE_CONTROL_PLANE_CODE, DEPLOYMENT_FAILURE_STAGE_SET, DEPLOYMENT_FAILURE_STAGE_BY_ERROR, CANDIDATE_CLEANUP_FAILURES, DEPLOYMENT_FAILURE_CAUSE_BY_ERROR, DEPLOYMENT_FAILURE_CAUSE_PATTERN, RETRYABLE_CODES, PLATFORM_OWNED_CODES, PLATFORM_OWNED_PREFIXES;
184285
184369
  var init_deployment_failure_contract = __esm({
184286
184370
  "../platform/src/deployment-failure-contract.ts"() {
184287
184371
  "use strict";
@@ -184292,6 +184376,8 @@ var init_deployment_failure_contract = __esm({
184292
184376
  DEPLOYMENT_FAILURE_STAGE_SET = new Set(DEPLOYMENT_FAILURE_STAGES);
184293
184377
  DEPLOYMENT_FAILURE_STAGE_BY_ERROR = /* @__PURE__ */ new WeakMap();
184294
184378
  CANDIDATE_CLEANUP_FAILURES = /* @__PURE__ */ new WeakSet();
184379
+ DEPLOYMENT_FAILURE_CAUSE_BY_ERROR = /* @__PURE__ */ new WeakMap();
184380
+ DEPLOYMENT_FAILURE_CAUSE_PATTERN = /^[A-Z][A-Z0-9_]{2,99}$/u;
184295
184381
  RETRYABLE_CODES = /* @__PURE__ */ new Set([
184296
184382
  "APP_DEPENDENCY_INSTALL_FAILED",
184297
184383
  "ACTIVATION_EPOCH_CAS_FAILED",
@@ -184756,6 +184842,9 @@ function getDeploymentAttemptFailureCode(error51, stage, crashLogs) {
184756
184842
  if (guardrailCode) return guardrailCode;
184757
184843
  if (isMigrationDeployError(error51)) return String(error51.code);
184758
184844
  if (isDeployDependencyVersionError(error51) || isCronManifestDeployError(error51)) return error51.code;
184845
+ if (getDeploymentFailureCause(error51)?.startsWith("DEPLOY_ARTIFACT_")) {
184846
+ return "DEPLOY_ARTIFACT_MATERIALIZE_FAILED";
184847
+ }
184759
184848
  const stableCode = getStableDeploymentFailureCode(error51);
184760
184849
  if (stableCode) return stableCode;
184761
184850
  if (stage === "admission") return "DEPLOY_CONTRACT_INVALID";
@@ -185369,7 +185458,8 @@ function fleetSelection() {
185369
185458
  ...bindingSelection(),
185370
185459
  authorityMode: appRuntimeDesiredState.authorityMode,
185371
185460
  desiredRuntimeState: appRuntimeDesiredState.desiredRuntimeState,
185372
- hasBackend: apps.hasBackend
185461
+ hasBackend: apps.hasBackend,
185462
+ appStatus: apps.status
185373
185463
  };
185374
185464
  }
185375
185465
  function queryBindingRows(db) {
@@ -185488,6 +185578,10 @@ async function loadCanonicalTenantRouteFleetSnapshot(input) {
185488
185578
  const desired = appRows[0];
185489
185579
  if (desired.hasBackend && desired.desiredRuntimeState === "serving" && desired.desiredNodeId === input.nodeId) {
185490
185580
  const joinedRows = appRows.filter((row) => row.instanceId !== null);
185581
+ if (joinedRows.length === 0 && desired.appStatus === "stopped") {
185582
+ removalTargets.push({ appId: desired.appId, appName: desired.appName });
185583
+ continue;
185584
+ }
185491
185585
  try {
185492
185586
  bindings.push(bindingFromRows(joinedRows));
185493
185587
  } catch (error51) {
@@ -186001,6 +186095,16 @@ function appDeleteOperationResult(operation, options = {}) {
186001
186095
  recoveryActivityEpoch: options.recovery.activityEpoch
186002
186096
  } : {};
186003
186097
  const blockedWithoutRecovery = operation.state === "blocked_active_work" && !options.recovery;
186098
+ const terminalRecoveryRequired = operation.state === "failed_delete_recovery_required";
186099
+ const recoveryDeadlineAnchor = operation.createdAt instanceof Date ? operation.createdAt : /* @__PURE__ */ new Date();
186100
+ const recoveryReconcileAnchor = operation.updatedAt instanceof Date ? operation.updatedAt : recoveryDeadlineAnchor;
186101
+ const recoveryEvidence = !isAppDeleteTerminalState(operation.state) ? {
186102
+ recoveryOwnerId: operation.ownerId,
186103
+ recoveryDeadlineAt: new Date(recoveryDeadlineAnchor.getTime() + RECOVERY_DEADLINE_MS).toISOString(),
186104
+ nextReconcileAt: new Date(
186105
+ recoveryReconcileAnchor.getTime() + RECOVERY_RECONCILE_INTERVAL_MS
186106
+ ).toISOString()
186107
+ } : {};
186004
186108
  return {
186005
186109
  success: false,
186006
186110
  deleted: operation.appName,
@@ -186013,6 +186117,13 @@ function appDeleteOperationResult(operation, options = {}) {
186013
186117
  ...operation.state === "completed" ? { success: true } : {},
186014
186118
  ...options.executorAvailable === void 0 ? {} : { executorAvailable: options.executorAvailable },
186015
186119
  ...operation.lastErrorCode ? { code: operation.lastErrorCode } : executorUnavailable ? { code: "PLATFORM_LIFECYCLE_EXECUTOR_UNAVAILABLE" } : {},
186120
+ ...terminalRecoveryRequired ? {
186121
+ code: "APP_DELETE_RECOVERY_REQUIRED",
186122
+ failureClass: "PLATFORM_ACTION_REQUIRED",
186123
+ action: "CONTACT_SUPPORT",
186124
+ recoveryCauseCode: operation.lastErrorCode
186125
+ } : {},
186126
+ ...recoveryEvidence,
186016
186127
  ...blockedRecovery,
186017
186128
  ...blockedWithoutRecovery ? {
186018
186129
  code: "PLATFORM_ACTION_REQUIRED",
@@ -186021,7 +186132,7 @@ function appDeleteOperationResult(operation, options = {}) {
186021
186132
  } : {}
186022
186133
  };
186023
186134
  }
186024
- var APP_DELETE_ACTIVE_STATES2, APP_DELETE_TERMINAL_FAILURE_STATES2, APP_DELETE_TERMINAL_STATES, APP_DELETE_ADMISSION_BLOCKING_STATES, RETENTION_MS;
186135
+ var APP_DELETE_ACTIVE_STATES2, APP_DELETE_TERMINAL_FAILURE_STATES2, APP_DELETE_TERMINAL_STATES, APP_DELETE_ADMISSION_BLOCKING_STATES, RETENTION_MS, RECOVERY_DEADLINE_MS, RECOVERY_RECONCILE_INTERVAL_MS;
186025
186136
  var init_app_delete_operation_store = __esm({
186026
186137
  "../platform/src/app-delete-operation-store.ts"() {
186027
186138
  "use strict";
@@ -186040,13 +186151,18 @@ var init_app_delete_operation_store = __esm({
186040
186151
  "failed_tenant_db_cleanup",
186041
186152
  "failed_catalog_cleanup"
186042
186153
  ];
186043
- APP_DELETE_TERMINAL_FAILURE_STATES2 = ["blocked_catalog_outcome_unknown"];
186154
+ APP_DELETE_TERMINAL_FAILURE_STATES2 = [
186155
+ "blocked_catalog_outcome_unknown",
186156
+ "failed_delete_recovery_required"
186157
+ ];
186044
186158
  APP_DELETE_TERMINAL_STATES = ["completed", ...APP_DELETE_TERMINAL_FAILURE_STATES2];
186045
186159
  APP_DELETE_ADMISSION_BLOCKING_STATES = [
186046
186160
  ...APP_DELETE_ACTIVE_STATES2,
186047
186161
  ...APP_DELETE_TERMINAL_FAILURE_STATES2
186048
186162
  ];
186049
186163
  RETENTION_MS = 7 * 24 * 60 * 6e4;
186164
+ RECOVERY_DEADLINE_MS = 15 * 6e4;
186165
+ RECOVERY_RECONCILE_INTERVAL_MS = 3e4;
186050
186166
  }
186051
186167
  });
186052
186168
 
@@ -401444,7 +401560,11 @@ async function waitForDirectRunnerHealth(port, timeoutMs, dependencies = {}) {
401444
401560
  while (now() - startedAt < timeoutMs) {
401445
401561
  if (dependencies.shouldContinue && !await dependencies.shouldContinue()) return false;
401446
401562
  const remainingMs = Math.max(1, timeoutMs - (now() - startedAt));
401447
- if (await probe(port, Math.min(2e3, remainingMs), dependencies.healthPath)) return true;
401563
+ const probeTimeoutMs = Math.min(2e3, remainingMs);
401564
+ if (await probe(port, probeTimeoutMs, dependencies.healthPath)) return true;
401565
+ if (dependencies.fallbackHealthPath && dependencies.fallbackHealthPath !== dependencies.healthPath && await probe(port, probeTimeoutMs, dependencies.fallbackHealthPath)) {
401566
+ return true;
401567
+ }
401448
401568
  const remainingAfterProbeMs = timeoutMs - (now() - startedAt);
401449
401569
  if (remainingAfterProbeMs <= 0) break;
401450
401570
  await sleep6(Math.min(DIRECT_RUNNER_HEALTH_POLL_INTERVAL_MS, remainingAfterProbeMs));
@@ -403162,7 +403282,8 @@ var init_direct_runner = __esm({
403162
403282
  const healthy = await spawnLifecycle.waitFor(
403163
403283
  this.waitForHealth(port, healthTimeoutMs, {
403164
403284
  ...options?.lifecycleRole === "candidate" ? { shouldContinue: () => this.isAlive(appName) } : {},
403165
- ...options?.lifecycleRole === "candidate" ? { healthPath: "/health/core-ready" } : {}
403285
+ ...options?.lifecycleRole === "candidate" ? { healthPath: "/health/core-ready" } : {},
403286
+ ...options?.lifecycleRole === "candidate" ? { fallbackHealthPath: "/health/live" } : {}
403166
403287
  })
403167
403288
  );
403168
403289
  if (!healthy) {
@@ -424339,10 +424460,21 @@ async function publishIdleRouteAndAwaitAck(input) {
424339
424460
  WHERE app_id = ${input.appId}
424340
424461
  `);
424341
424462
  const authority = rowsFromResult34(result2)[0];
424342
- if (!authority || authority.app_instance_id !== input.appInstanceId) {
424463
+ if (!authority) {
424343
424464
  fail31("RUNTIME_IDLE_ROUTE_AUTHORITY_MISSING");
424344
424465
  }
424345
424466
  const current = decodeAuthority(authority);
424467
+ if (current.mode === "tombstoned" && current.disposition === "tombstone") {
424468
+ const convergence = await assessAppServingRouteConvergence({
424469
+ db: input.db,
424470
+ eventId: authority.last_event_id
424471
+ });
424472
+ if (convergence.status !== "converged") fail31("RUNTIME_IDLE_ROUTE_ACK_PENDING");
424473
+ return;
424474
+ }
424475
+ if (authority.app_instance_id !== input.appInstanceId) {
424476
+ fail31("RUNTIME_IDLE_ROUTE_AUTHORITY_MISSING");
424477
+ }
424346
424478
  if (current.appId !== input.appId || current.appInstanceId !== input.appInstanceId || current.mode !== "backend_only" && current.mode !== "fullstack" || !current.backend || current.backend.activationId !== input.activationId || current.backend.activationEpoch !== input.activationEpoch) {
424347
424479
  fail31("RUNTIME_IDLE_ROUTE_IDENTITY_MISMATCH");
424348
424480
  }
@@ -425511,6 +425643,7 @@ async function armExplicitRuntimeStop(input) {
425511
425643
  ]);
425512
425644
  const drain = drainRows[0];
425513
425645
  const activity = activityRows[0];
425646
+ const appDeleteWithoutActivityObservation = drain?.reason === "app_delete" && !activity;
425514
425647
  if (!drain) throw new Error("RUNTIME_EXPLICIT_DRAIN_EXPIRED");
425515
425648
  if (drain.state === "dispatched" || drain.state === "completed") {
425516
425649
  const intents = await tx.select().from(runtimeStopIntents).where(eq60(runtimeStopIntents.drainRequestId, drain.id));
@@ -425523,7 +425656,7 @@ async function armExplicitRuntimeStop(input) {
425523
425656
  if (!intents[0]) throw new Error("RUNTIME_EXPLICIT_STOP_REPLAY_INVALID");
425524
425657
  return { intentId: intents[0].id, drainId: drain.id, replayed: true };
425525
425658
  }
425526
- if (drain.state !== "planned" || !activity || !activity.observationComplete || activity.activationId !== drain.activationId || activity.instanceId !== drain.instanceId || activity.nodeId !== drain.nodeId || activity.nodeEpoch !== drain.nodeEpoch || activity.httpActive !== 0 || activity.streamActive !== 0 || activity.websocketActive !== 0 || activity.workloadActive !== 0) {
425659
+ if (drain.state !== "planned" || !appDeleteWithoutActivityObservation && (!activity || !activity.observationComplete || activity.activationId !== drain.activationId || activity.instanceId !== drain.instanceId || activity.nodeId !== drain.nodeId || activity.nodeEpoch !== drain.nodeEpoch || activity.httpActive !== 0 || activity.streamActive !== 0 || activity.websocketActive !== 0 || activity.workloadActive !== 0)) {
425527
425660
  throw new Error("RUNTIME_EXPLICIT_DRAIN_NOT_QUIESCENT");
425528
425661
  }
425529
425662
  const intent = await createRuntimeStopIntentInTransaction({
@@ -425539,7 +425672,11 @@ async function armExplicitRuntimeStop(input) {
425539
425672
  now,
425540
425673
  drainRequestId: drain.id
425541
425674
  });
425542
- const armed = await tx.update(runtimeDrainRequests).set({ state: "armed", activityEpoch: activity.activityEpoch, updatedAt: now }).where(and56(eq60(runtimeDrainRequests.id, drain.id), eq60(runtimeDrainRequests.state, "planned"))).returning({ id: runtimeDrainRequests.id });
425675
+ const armed = await tx.update(runtimeDrainRequests).set({
425676
+ state: "armed",
425677
+ activityEpoch: activity?.activityEpoch ?? drain.activityEpoch,
425678
+ updatedAt: now
425679
+ }).where(and56(eq60(runtimeDrainRequests.id, drain.id), eq60(runtimeDrainRequests.state, "planned"))).returning({ id: runtimeDrainRequests.id });
425543
425680
  if (!armed[0]) throw new Error("RUNTIME_EXPLICIT_DRAIN_ARM_CAS_FAILED");
425544
425681
  await tx.update(runtimeLifecycleRequests).set({ state: "executing", updatedAt: now }).where(eq60(runtimeLifecycleRequests.id, drain.lifecycleRequestId));
425545
425682
  return { intentId: intent.id, drainId: drain.id, replayed: false };
@@ -428050,9 +428187,12 @@ function deriveRuntimeStopOperationState(input) {
428050
428187
  if (input.drainState === "blocked" && input.terminalResultCode === "RUNTIME_STOP_OWNERSHIP_AMBIGUOUS") {
428051
428188
  return "blocked_ambiguous_binding";
428052
428189
  }
428053
- if (input.drainState === "blocked" && ["RUNTIME_EXPLICIT_DRAIN_TIMEOUT", "RUNTIME_EXPLICIT_DRAIN_EXPIRED"].includes(
428054
- input.terminalResultCode ?? ""
428055
- )) {
428190
+ if (input.drainState === "blocked" && [
428191
+ "RUNTIME_EXPLICIT_DRAIN_TIMEOUT",
428192
+ "RUNTIME_EXPLICIT_DRAIN_EXPIRED",
428193
+ "RUNTIME_EXPLICIT_DRAIN_NOT_QUIESCENT",
428194
+ "RUNTIME_STOP_INTENT_ACTIVITY_CHANGED"
428195
+ ].includes(input.terminalResultCode ?? "")) {
428056
428196
  return "blocked_active_work";
428057
428197
  }
428058
428198
  if (input.requestState === "failed" || input.drainState === "cancelled") return "failed";
@@ -428074,10 +428214,7 @@ async function loadAppDeleteRuntimeRecoveryReceipt(input) {
428074
428214
  drainReason: runtimeDrainRequests.reason,
428075
428215
  intentReason: runtimeStopIntents.reason,
428076
428216
  intentCorrelationId: runtimeStopIntents.correlationId
428077
- }).from(runtimeLifecycleRequests).leftJoin(
428078
- runtimeDrainRequests,
428079
- eq70(runtimeDrainRequests.lifecycleRequestId, runtimeLifecycleRequests.id)
428080
- ).leftJoin(runtimeStopIntents, eq70(runtimeStopIntents.drainRequestId, runtimeDrainRequests.id)).where(
428217
+ }).from(runtimeLifecycleRequests).leftJoin(runtimeDrainRequests, eq70(runtimeDrainRequests.lifecycleRequestId, runtimeLifecycleRequests.id)).leftJoin(runtimeStopIntents, eq70(runtimeStopIntents.drainRequestId, runtimeDrainRequests.id)).where(
428081
428218
  and66(
428082
428219
  eq70(runtimeLifecycleRequests.appId, input.appId),
428083
428220
  eq70(runtimeLifecycleRequests.action, "app_delete"),
@@ -428092,7 +428229,8 @@ async function loadAppDeleteRuntimeRecoveryReceipt(input) {
428092
428229
  requestState: row.requestState,
428093
428230
  drainState: row.drainState,
428094
428231
  terminalResultCode: row.terminalResultCode
428095
- }) !== "blocked_active_work") return null;
428232
+ }) !== "blocked_active_work")
428233
+ return null;
428096
428234
  const ownerId = row.leaseOwner;
428097
428235
  if (!ownerId || !row.deadlineAt || !Number.isSafeInteger(Number(row.activityEpoch))) return null;
428098
428236
  return {
@@ -428184,10 +428322,12 @@ var init_app_delete_catalog_finalizer = __esm({
428184
428322
  });
428185
428323
 
428186
428324
  // ../platform/src/app-delete-operation-controller.ts
428325
+ var APP_DELETE_RECOVERY_DEADLINE_MS;
428187
428326
  var init_app_delete_operation_controller = __esm({
428188
428327
  "../platform/src/app-delete-operation-controller.ts"() {
428189
428328
  "use strict";
428190
428329
  init_app_delete_operation_store();
428330
+ APP_DELETE_RECOVERY_DEADLINE_MS = 15 * 6e4;
428191
428331
  }
428192
428332
  });
428193
428333
 
@@ -428338,7 +428478,7 @@ function publicAppDeleteErrorCode(error51) {
428338
428478
  return PUBLICLY_NORMALIZED_APP_DELETE_CODES.has(code) ? "APP_DELETE_OPERATION_PENDING" : code;
428339
428479
  }
428340
428480
  function appDeleteFailureWithReceipt(error51, receipt) {
428341
- const code = publicAppDeleteErrorCode(error51);
428481
+ const code = receipt.state === "failed_delete_recovery_required" ? "APP_DELETE_RECOVERY_REQUIRED" : publicAppDeleteErrorCode(error51);
428342
428482
  return Object.assign(new Error(code, { cause: error51 }), {
428343
428483
  code,
428344
428484
  operationId: receipt.id,
@@ -428348,7 +428488,7 @@ function appDeleteFailureWithReceipt(error51, receipt) {
428348
428488
  });
428349
428489
  }
428350
428490
  function appDeleteFailureHttpStatus(state2) {
428351
- return state2.startsWith("blocked_") ? 409 : 503;
428491
+ return state2.startsWith("blocked_") || state2 === "failed_delete_recovery_required" ? 409 : 503;
428352
428492
  }
428353
428493
  var PUBLICLY_NORMALIZED_APP_DELETE_CODES;
428354
428494
  var init_app_delete_diagnostic = __esm({
@@ -429573,6 +429713,7 @@ async function bootstrapPlatformRuntime(params) {
429573
429713
  subdomainRegex,
429574
429714
  getBunServer: params.getBunServer,
429575
429715
  domainLookupDb: params.db,
429716
+ resolveExistingOnlyRoute: routeProjectionRuntime.resolveExistingOnlyRoute,
429576
429717
  async findActiveDomainApp(host) {
429577
429718
  const rows4 = await params.db.select({
429578
429719
  name: appsTable.name,
@@ -429916,8 +430057,7 @@ async function bootstrapPlatformRuntime(params) {
429916
430057
  logger3.error("[ws-gateway] realtime usage metering bootstrap failed:", message);
429917
430058
  }
429918
430059
  startHeartbeat();
429919
- const limits = getGatewayLimits();
429920
- logger3.log(`[ws-gateway] WS Gateway active (max ${limits.maxConnectionsPerApp}/app, ${limits.maxTotalConnections} total)`);
430060
+ logger3.log(`[ws-gateway] WS Gateway active (max ${getGatewayLimits().maxConnectionsPerApp}/app, ${getGatewayLimits().maxTotalConnections} total)`);
429921
430061
  const startAfterListen = async () => {
429922
430062
  await routeProjectionRuntime.startAfterRecovery(autoRecoveryRuntime);
429923
430063
  explicitStopReconciler.start();
@@ -448229,7 +448369,10 @@ var APP_DELETE_ACTIVE_STATES = /* @__PURE__ */ new Set([
448229
448369
  "failed_tenant_db_cleanup",
448230
448370
  "failed_catalog_cleanup"
448231
448371
  ]);
448232
- var APP_DELETE_TERMINAL_FAILURE_STATES = /* @__PURE__ */ new Set(["blocked_catalog_outcome_unknown"]);
448372
+ var APP_DELETE_TERMINAL_FAILURE_STATES = /* @__PURE__ */ new Set([
448373
+ "blocked_catalog_outcome_unknown",
448374
+ "failed_delete_recovery_required"
448375
+ ]);
448233
448376
  var CAPABILITY_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/u;
448234
448377
  function createAppDeleteStatusLoader(getQueryDef2) {
448235
448378
  return async ({ ctx, args, result: result2 }) => {
@@ -448331,7 +448474,7 @@ import { randomUUID as randomUUID7 } from "node:crypto";
448331
448474
  var POSTGRES_CODE_PATTERN = /^[0-9A-Z]{5}$/u;
448332
448475
  var SAFE_CORRELATION_PATTERN = /^[A-Za-z0-9_-]{8,128}$/u;
448333
448476
  var SAFE_APP_DELETE_OPERATION_PATTERN = /^app_delete_(?:[a-f0-9]{32}|[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12})$/u;
448334
- var SAFE_APP_DELETE_STATE_PATTERN = /^(?:accepted|stopping_children|draining_runtime|stop_dispatched|runtime_absent|tenant_db_drop_pending|catalog_delete_pending|completed|blocked_ownership_ambiguous|blocked_active_work|blocked_runtime_outcome_unknown|failed_tenant_db_cleanup|failed_catalog_cleanup)$/u;
448477
+ var SAFE_APP_DELETE_STATE_PATTERN = /^(?:accepted|stopping_children|draining_runtime|stop_dispatched|runtime_absent|tenant_db_drop_pending|catalog_delete_pending|completed|blocked_ownership_ambiguous|blocked_active_work|blocked_runtime_outcome_unknown|blocked_catalog_outcome_unknown|failed_tenant_db_cleanup|failed_catalog_cleanup|failed_delete_recovery_required)$/u;
448335
448478
  var SAFE_PUBLIC_ERROR_CODE_PATTERN = /^[A-Z][A-Z0-9_]{2,127}$/u;
448336
448479
  var SAFE_RETRY_CLASSES = /* @__PURE__ */ new Set([
448337
448480
  "operator-action",