deepline 0.3.89 → 0.3.90

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 (211) hide show
  1. package/contracts/install-commands.json +29 -0
  2. package/dist/bundling-sources/sdk/src/client.ts +120 -37
  3. package/dist/bundling-sources/sdk/src/index.ts +4 -0
  4. package/dist/bundling-sources/sdk/src/pagination.ts +25 -0
  5. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +1 -1
  6. package/dist/bundling-sources/sdk/src/release.ts +16 -9
  7. package/dist/bundling-sources/sdk/src/types.ts +23 -0
  8. package/dist/bundling-sources/shared_libs/monitors/analytics-public.ts +10 -0
  9. package/dist/bundling-sources/shared_libs/monitors/http-error-response.ts +3 -0
  10. package/dist/bundling-sources/shared_libs/monitors/inbound-queue.ts +4 -4
  11. package/dist/bundling-sources/shared_libs/monitors/inventory-reconciliation.ts +59 -0
  12. package/dist/bundling-sources/shared_libs/monitors/lifecycle-notifications.ts +7 -9
  13. package/dist/bundling-sources/shared_libs/monitors/package.json +7 -0
  14. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-batch-operation.ts +44 -2
  15. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-consumer-health.ts +2 -2
  16. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-identity-claims.ts +2 -2
  17. package/dist/bundling-sources/shared_libs/monitors/provider-monitor-public-aliases.ts +1 -1
  18. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-dead-letter.ts +245 -0
  19. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-message.ts +38 -0
  20. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-queue-ack-probe.ts +94 -0
  21. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-queue-delivery.ts +60 -0
  22. package/dist/bundling-sources/shared_libs/monitors/signal-radars/inbound-queue.ts +60 -0
  23. package/dist/bundling-sources/shared_libs/monitors/snitcher-install-validation.ts +1 -1
  24. package/dist/bundling-sources/shared_libs/monitors/snitcher-ip2company.ts +2 -2
  25. package/dist/bundling-sources/shared_libs/monitors/snitcher-radar.ts +1 -1
  26. package/dist/bundling-sources/shared_libs/monitors/tracking-provider-integrations.ts +1 -1
  27. package/dist/bundling-sources/shared_libs/observability/build-context.ts +13 -0
  28. package/dist/bundling-sources/shared_libs/observability/log-metadata.ts +160 -0
  29. package/dist/bundling-sources/shared_libs/observability/request-context.ts +68 -0
  30. package/dist/bundling-sources/shared_libs/observability/scheduled-jobs.json +654 -0
  31. package/dist/bundling-sources/shared_libs/observability/scheduled-work-manual.ts +35 -0
  32. package/dist/bundling-sources/shared_libs/observability/scheduled-work.ts +5 -0
  33. package/dist/bundling-sources/shared_libs/play-data-plane/neon-constants.ts +9 -0
  34. package/dist/bundling-sources/shared_libs/play-data-plane/r2.ts +272 -0
  35. package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +45 -0
  36. package/dist/bundling-sources/shared_libs/play-runtime/async-operation.ts +66 -1
  37. package/dist/bundling-sources/shared_libs/play-runtime/async-play-invocation.ts +0 -1
  38. package/dist/bundling-sources/shared_libs/play-runtime/bounceban-batching.ts +137 -0
  39. package/dist/bundling-sources/shared_libs/play-runtime/context.ts +779 -140
  40. package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +46 -0
  41. package/dist/bundling-sources/shared_libs/play-runtime/daytona-payload-contract.ts +68 -0
  42. package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-janitor.ts +103 -0
  43. package/dist/bundling-sources/shared_libs/play-runtime/daytona-sandbox-reaper.ts +725 -0
  44. package/dist/bundling-sources/shared_libs/play-runtime/durable-call-cache.ts +29 -0
  45. package/dist/bundling-sources/shared_libs/play-runtime/execution-capabilities.ts +23 -0
  46. package/dist/bundling-sources/shared_libs/play-runtime/execution-gateway-invocation-fence.ts +442 -0
  47. package/dist/bundling-sources/shared_libs/play-runtime/execution-protocol.ts +3 -3
  48. package/dist/bundling-sources/shared_libs/play-runtime/fixture-behavior.ts +18 -0
  49. package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +9 -0
  50. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +1 -1
  51. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +1 -1
  52. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/contracts.ts +66 -0
  53. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/job.ts +145 -0
  54. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/ports.ts +21 -0
  55. package/dist/bundling-sources/shared_libs/play-runtime/integration-operation-reader-fence/postgres-store.ts +170 -0
  56. package/dist/bundling-sources/shared_libs/play-runtime/internal-bootstrap-token.ts +1322 -0
  57. package/dist/bundling-sources/shared_libs/play-runtime/internal-step-ids.ts +2 -2
  58. package/dist/bundling-sources/shared_libs/play-runtime/lane-retirement-gate.ts +1 -1
  59. package/dist/bundling-sources/shared_libs/play-runtime/launch-source-policy.ts +112 -0
  60. package/dist/bundling-sources/shared_libs/play-runtime/map-execution-frame.ts +8 -0
  61. package/dist/bundling-sources/shared_libs/play-runtime/perf-trace.ts +127 -0
  62. package/dist/bundling-sources/shared_libs/play-runtime/play-artifact-runtime-contract.ts +5 -0
  63. package/dist/bundling-sources/shared_libs/play-runtime/play-run-recovery-policy.ts +24 -1
  64. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/contracts.ts +56 -0
  65. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/index.ts +13 -0
  66. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/job.ts +41 -0
  67. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/ports.ts +17 -0
  68. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/admission/postgres-adapter.ts +54 -0
  69. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/contracts.ts +114 -0
  70. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/engine-suspension.ts +108 -0
  71. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/index.ts +36 -0
  72. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/job.ts +97 -0
  73. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/ports.ts +104 -0
  74. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/postgres-fence-adapter.ts +263 -0
  75. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/attempts/worker-terminal-projection.ts +64 -0
  76. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/contracts.ts +29 -0
  77. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/gateway-adapter.ts +56 -0
  78. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/index.ts +15 -0
  79. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/job.ts +65 -0
  80. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/projection/ports.ts +17 -0
  81. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/contracts.ts +42 -0
  82. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/index.ts +17 -0
  83. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/job.ts +142 -0
  84. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/ports.ts +42 -0
  85. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/sandbox-cleanup/postgres-adapter.ts +102 -0
  86. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/contracts.ts +60 -0
  87. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/index.ts +16 -0
  88. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/job.ts +78 -0
  89. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/ports.ts +54 -0
  90. package/dist/bundling-sources/shared_libs/play-runtime/play-runs/terminal/postgres-adapter.ts +71 -0
  91. package/dist/bundling-sources/shared_libs/play-runtime/play-runtime-batching-registry.ts +4 -0
  92. package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +2 -0
  93. package/dist/bundling-sources/shared_libs/play-runtime/receipt-status.ts +5 -8
  94. package/dist/bundling-sources/shared_libs/play-runtime/run-failure.ts +3 -5
  95. package/dist/bundling-sources/shared_libs/play-runtime/run-identity.ts +168 -0
  96. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-lifecycle.ts +72 -9
  97. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona-payload-transport.ts +6 -12
  98. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/backends/daytona.ts +19 -0
  99. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/bundle.ts +0 -1
  100. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/runtime-sandbox-reconciliation.ts +14 -44
  101. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +57 -205
  102. package/dist/bundling-sources/shared_libs/play-runtime/runtime-authority.ts +201 -0
  103. package/dist/bundling-sources/shared_libs/play-runtime/runtime-env.ts +6 -0
  104. package/dist/bundling-sources/shared_libs/play-runtime/runtime-operation-contract.ts +67 -0
  105. package/dist/bundling-sources/shared_libs/play-runtime/runtime-release-environment.ts +2 -0
  106. package/dist/bundling-sources/shared_libs/play-runtime/runtime-sandbox-contract.ts +68 -0
  107. package/dist/bundling-sources/shared_libs/play-runtime/runtime-scheduler-topology.ts +14 -2
  108. package/dist/bundling-sources/shared_libs/play-runtime/runtime-telemetry.ts +108 -0
  109. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/contract.ts +4 -0
  110. package/dist/bundling-sources/shared_libs/play-runtime/sandbox-runs/runner-backend-adapter.ts +3 -0
  111. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +7 -0
  112. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-deadline-reconciliation.ts +88 -0
  113. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-deploy-task.ts +124 -0
  114. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-play-run-task.ts +68 -0
  115. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-pool.ts +193 -0
  116. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-queue-lifecycle.ts +269 -0
  117. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-queue-suffix.ts +73 -0
  118. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-runtime-worker.ts +6642 -0
  119. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-shared.ts +897 -0
  120. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-metrics.ts +120 -0
  121. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd-worker-required-env.ts +76 -0
  122. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/absurd.ts +476 -0
  123. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-heavy-request-admission.ts +47 -0
  124. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/gateway-progress-registry.ts +147 -0
  125. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/index.ts +27 -0
  126. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/lazy.ts +50 -0
  127. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/play-run-recovery.ts +98 -0
  128. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-budget-state.ts +260 -0
  129. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +1416 -0
  130. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-progress.ts +1255 -0
  131. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-rate-state.ts +942 -0
  132. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +14636 -0
  133. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/receipt-gateway.ts +888 -0
  134. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-ledger-outbox-recovery.ts +355 -0
  135. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/run-terminal-transition.ts +46 -0
  136. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runner-push.ts +60 -0
  137. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-api-origin.ts +33 -0
  138. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-receipt-gateway-health.ts +64 -0
  139. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-capacity.ts +835 -0
  140. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-ledger-reconciliation.ts +1218 -0
  141. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-sandbox-operation.ts +207 -0
  142. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/runtime-scheduler-schema.ts +10 -0
  143. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/scheduler-capacity.ts +123 -0
  144. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/scheduler-launch-read-observability.ts +78 -0
  145. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/submit-admission.ts +169 -0
  146. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/terminal-contract.ts +20 -0
  147. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-queue-metrics.ts +34 -0
  148. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/worker-resource-metrics.ts +249 -0
  149. package/dist/bundling-sources/shared_libs/play-runtime/sheet-attempt-sql.ts +7 -0
  150. package/dist/bundling-sources/shared_libs/play-runtime/step-progress.ts +296 -0
  151. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/native-batch.ts +3 -3
  152. package/dist/bundling-sources/shared_libs/play-runtime/tool-call/runtime-step-receipts-adapter.ts +20 -1
  153. package/dist/bundling-sources/shared_libs/play-runtime/tool-execute-retry-policy.ts +60 -15
  154. package/dist/bundling-sources/shared_libs/play-runtime/tool-execution-outcome.ts +20 -0
  155. package/dist/bundling-sources/shared_libs/play-runtime/transient-service-error.ts +12 -0
  156. package/dist/bundling-sources/shared_libs/play-runtime/vercel-protection.ts +14 -1
  157. package/dist/bundling-sources/shared_libs/play-runtime/work-receipt-storage-contract.ts +165 -0
  158. package/dist/bundling-sources/shared_libs/play-runtime/work-receipts.ts +15 -23
  159. package/dist/bundling-sources/shared_libs/play-runtime/workflow-executor-auth.ts +169 -0
  160. package/dist/bundling-sources/shared_libs/play-runtime/zerobounce-batching.ts +122 -0
  161. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +2 -0
  162. package/dist/bundling-sources/shared_libs/plays/contracts.ts +2 -0
  163. package/dist/bundling-sources/shared_libs/plays/deployment-status.ts +1 -1
  164. package/dist/bundling-sources/shared_libs/plays/docflow.ts +1 -1
  165. package/dist/bundling-sources/shared_libs/plays/play-grep-search.ts +39 -0
  166. package/dist/bundling-sources/shared_libs/plays/share/copy.ts +271 -0
  167. package/dist/bundling-sources/shared_libs/plays/share/metrics.ts +140 -0
  168. package/dist/bundling-sources/shared_libs/plays/share/public-read-model.ts +86 -0
  169. package/dist/bundling-sources/shared_libs/plays/share/seo-quality.ts +181 -0
  170. package/dist/bundling-sources/shared_libs/plays/share/static-pipeline-summary.ts +658 -0
  171. package/dist/bundling-sources/shared_libs/plays/share/types.ts +197 -0
  172. package/dist/bundling-sources/shared_libs/plays/slack-hitl-timeout-error.ts +37 -0
  173. package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +6 -1
  174. package/dist/bundling-sources/shared_libs/plays/tool-result-types.ts +1 -1
  175. package/dist/bundling-sources/shared_libs/product-notifications/configuration.ts +7 -1
  176. package/dist/bundling-sources/shared_libs/product-notifications/default-policy.ts +3 -2
  177. package/dist/bundling-sources/shared_libs/product-notifications/overflow.ts +18 -0
  178. package/dist/bundling-sources/shared_libs/product-notifications/rolling-limit.ts +24 -0
  179. package/dist/bundling-sources/shared_libs/product-notifications/slack-delivery.ts +624 -0
  180. package/dist/bundling-sources/shared_libs/product-notifications/slack-payload.ts +140 -0
  181. package/dist/bundling-sources/shared_libs/product-notifications/slack-transport.ts +75 -0
  182. package/dist/bundling-sources/shared_libs/runtime-env.ts +6 -0
  183. package/dist/bundling-sources/shared_libs/security/email-blacklist.ts +42 -0
  184. package/dist/bundling-sources/shared_libs/security/header-safe-env.ts +10 -3
  185. package/dist/bundling-sources/shared_libs/security/slack-sanitize.ts +133 -0
  186. package/dist/cli/getting-started.d.mts +52 -0
  187. package/dist/cli/getting-started.d.ts +52 -0
  188. package/dist/cli/getting-started.js +65 -0
  189. package/dist/cli/getting-started.mjs +36 -0
  190. package/dist/cli/index.d.mts +9 -0
  191. package/dist/cli/index.d.ts +9 -0
  192. package/dist/cli/index.js +545 -264
  193. package/dist/cli/index.mjs +543 -271
  194. package/dist/{compiler-manifest-DsLbQaew.d.mts → compiler-manifest-BaJfE-5H.d.mts} +5 -3
  195. package/dist/{compiler-manifest-DsLbQaew.d.ts → compiler-manifest-BaJfE-5H.d.ts} +5 -3
  196. package/dist/index.d.mts +81 -148
  197. package/dist/index.d.ts +81 -148
  198. package/dist/index.js +83 -26
  199. package/dist/index.mjs +83 -26
  200. package/dist/install-integrity.json +130 -2
  201. package/dist/monitor-fleet-contract.d.mts +138 -0
  202. package/dist/monitor-fleet-contract.d.ts +138 -0
  203. package/dist/monitor-fleet-contract.js +404 -0
  204. package/dist/monitor-fleet-contract.mjs +367 -0
  205. package/dist/plays/bundle-play-file.d.mts +2 -2
  206. package/dist/plays/bundle-play-file.d.ts +2 -2
  207. package/dist/release.d.mts +255 -0
  208. package/dist/release.d.ts +255 -0
  209. package/dist/release.js +215 -0
  210. package/dist/release.mjs +188 -0
  211. package/package.json +21 -4
@@ -34,6 +34,35 @@ export function durableCacheStaleBucket(input: {
34
34
 
35
35
  export const durableCallStaleBucket = durableCacheStaleBucket;
36
36
 
37
+ /**
38
+ * An exact completed tool receipt owned by a source run. The opaque key keeps
39
+ * request data out of storage keys while still giving a replay one stable,
40
+ * deterministic lookup per logical tool call.
41
+ */
42
+ export function buildSourceRunToolReceiptManifestKey(input: {
43
+ orgId?: string | null;
44
+ sourceRunId: string;
45
+ logicalCallId: string;
46
+ }): string {
47
+ const orgId = input.orgId?.trim() || 'org';
48
+ const sourceRunId = input.sourceRunId.trim();
49
+ const logicalCallId = input.logicalCallId.trim();
50
+ if (!sourceRunId || !logicalCallId) {
51
+ throw new Error(
52
+ 'Source-run tool receipt manifest key requires sourceRunId and logicalCallId.',
53
+ );
54
+ }
55
+ const digest = sha256Hex(
56
+ stableStringify({
57
+ kind: 'source-run-tool-receipt-manifest-v1',
58
+ orgId,
59
+ sourceRunId,
60
+ logicalCallId,
61
+ }),
62
+ );
63
+ return `ctx:${orgId}:source-run-tool-receipt:${digest}`;
64
+ }
65
+
37
66
  export function buildDurableToolCallCacheKey(input: {
38
67
  orgId?: string | null;
39
68
  toolId: string;
@@ -63,6 +63,12 @@ export type RuntimeAuthorityDescriptor = {
63
63
  * the pre-feature behavior, which is the whole point of the switch.
64
64
  */
65
65
  docflowEnabled?: boolean | null;
66
+ /**
67
+ * Expand-before-enable fence for async-child attempt proof. Missing is the
68
+ * historic compatibility behavior; writers may enable it only after every
69
+ * worker can refresh an attempt token carrying a lease claim.
70
+ */
71
+ asyncChildAdmissionAttemptRequired?: boolean | null;
66
72
  capabilities: RuntimeExecutionCapability[];
67
73
  };
68
74
 
@@ -89,6 +95,21 @@ export function normalizeRuntimeExecutionCapabilities(
89
95
  return [...new Set(values.filter(isRuntimeExecutionCapability))].sort();
90
96
  }
91
97
 
98
+ /**
99
+ * A backend may impose a smaller execution surface, but it can never turn a
100
+ * durable run authority into a broader one. Keep this policy primitive beside
101
+ * the descriptor rather than letting token issuers reconstruct it ad hoc.
102
+ */
103
+ export function intersectRuntimeExecutionCapabilities(
104
+ persisted: readonly unknown[] | null | undefined,
105
+ backendAllowed: readonly RuntimeExecutionCapability[],
106
+ ): RuntimeExecutionCapability[] {
107
+ const allowed = new Set(backendAllowed);
108
+ return normalizeRuntimeExecutionCapabilities(persisted).filter((capability) =>
109
+ allowed.has(capability),
110
+ );
111
+ }
112
+
92
113
  export function hasRuntimeExecutionCapability(
93
114
  values: readonly string[] | null | undefined,
94
115
  capability: RuntimeExecutionCapability,
@@ -152,6 +173,8 @@ export function requireRuntimeAuthorityDescriptor(
152
173
  // read back through, so anything that is not an explicit yes — missing,
153
174
  // null, a string that survived a JSON round trip — denies.
154
175
  docflowEnabled: descriptor.docflowEnabled === true,
176
+ asyncChildAdmissionAttemptRequired:
177
+ descriptor.asyncChildAdmissionAttemptRequired === true,
155
178
  capabilities,
156
179
  };
157
180
  }
@@ -0,0 +1,442 @@
1
+ export type DurableInvocationResponse = {
2
+ status: number;
3
+ headers: Array<[string, string]>;
4
+ bodyBase64: string;
5
+ };
6
+
7
+ export type DurableInvocationRecord = {
8
+ invocationKey: string;
9
+ requestFingerprint: string;
10
+ ownerId: string;
11
+ parentRunId: string;
12
+ state: 'running' | 'completed' | 'compacted' | 'indeterminate';
13
+ response: DurableInvocationResponse | null;
14
+ updatedAt: string;
15
+ };
16
+
17
+ export type DurableInvocationStore = {
18
+ get(input: {
19
+ invocationKey: string;
20
+ }): Promise<DurableInvocationRecord | null>;
21
+ begin(input: {
22
+ invocationKey: string;
23
+ requestFingerprint: string;
24
+ acceptedRequestFingerprints?: readonly string[];
25
+ ownerId: string;
26
+ parentRunId: string;
27
+ }): Promise<DurableInvocationRecord>;
28
+ complete(input: {
29
+ invocationKey: string;
30
+ requestFingerprint: string;
31
+ ownerId: string;
32
+ response: DurableInvocationResponse;
33
+ }): Promise<DurableInvocationRecord | null>;
34
+ markIndeterminate(input: {
35
+ invocationKey: string;
36
+ requestFingerprint: string;
37
+ ownerId: string;
38
+ }): Promise<DurableInvocationRecord | null>;
39
+ abandon(input: {
40
+ invocationKey: string;
41
+ requestFingerprint: string;
42
+ ownerId: string;
43
+ }): Promise<boolean>;
44
+ };
45
+
46
+ export type DurableInvocationDiagnosticPhase =
47
+ | 'existing_indeterminate'
48
+ | 'existing_compacted'
49
+ | 'stale_running_indeterminate'
50
+ | 'foreign_owner_running'
51
+ | 'dispatch_failed'
52
+ | 'completion_failed'
53
+ | 'completion_missing'
54
+ | 'completion_recovered'
55
+ | 'fixture_abandon_succeeded'
56
+ | 'fixture_abandon_rejected'
57
+ | 'fixture_abandon_failed'
58
+ | 'wait_exhausted';
59
+
60
+ export type DurableInvocationDiagnostic = {
61
+ phase: DurableInvocationDiagnosticPhase;
62
+ error?: unknown;
63
+ };
64
+
65
+ export class DurableInvocationConflictError extends Error {
66
+ readonly code = 'DURABLE_INVOCATION_REQUEST_CONFLICT';
67
+
68
+ constructor() {
69
+ super('The durable invocation key was reused for a different request.');
70
+ this.name = 'DurableInvocationConflictError';
71
+ }
72
+ }
73
+
74
+ export class DurableInvocationOutcomeUnknownError extends Error {
75
+ readonly code = 'DURABLE_INVOCATION_OUTCOME_UNKNOWN';
76
+
77
+ constructor() {
78
+ super(
79
+ 'The durable invocation started but no response was committed. Deepline will not dispatch it again because its outcome may already have taken effect.',
80
+ );
81
+ this.name = 'DurableInvocationOutcomeUnknownError';
82
+ }
83
+ }
84
+
85
+ export class DurableInvocationInProgressError extends Error {
86
+ readonly code = 'GATEWAY_INVOCATION_IN_PROGRESS';
87
+
88
+ constructor() {
89
+ super(
90
+ 'The same durable invocation is still executing. Retry this transport delivery with the same invocation attempt.',
91
+ );
92
+ this.name = 'DurableInvocationInProgressError';
93
+ }
94
+ }
95
+
96
+ export class DurableInvocationCommitError extends Error {
97
+ readonly code = 'DURABLE_INVOCATION_COMMIT_FAILED';
98
+
99
+ constructor() {
100
+ super(
101
+ 'The integration response could not be committed before delivery. Its outcome is unknown and Deepline will not dispatch it again automatically.',
102
+ );
103
+ this.name = 'DurableInvocationCommitError';
104
+ }
105
+ }
106
+
107
+ function assertMatchingRequest(
108
+ record: DurableInvocationRecord,
109
+ requestFingerprint: string,
110
+ acceptedRequestFingerprints: readonly string[] = [],
111
+ ): void {
112
+ if (
113
+ record.requestFingerprint !== requestFingerprint &&
114
+ !acceptedRequestFingerprints.includes(record.requestFingerprint)
115
+ ) {
116
+ throw new DurableInvocationConflictError();
117
+ }
118
+ }
119
+
120
+ function completedResponse(
121
+ record: DurableInvocationRecord,
122
+ ): DurableInvocationResponse | null {
123
+ if (record.state !== 'completed') return null;
124
+ if (!record.response) throw new DurableInvocationCommitError();
125
+ return record.response;
126
+ }
127
+
128
+ function decodedBodyBytes(response: DurableInvocationResponse): number {
129
+ const padding = response.bodyBase64.endsWith('==')
130
+ ? 2
131
+ : response.bodyBase64.endsWith('=')
132
+ ? 1
133
+ : 0;
134
+ return Math.max(
135
+ 0,
136
+ Math.floor((response.bodyBase64.length * 3) / 4) - padding,
137
+ );
138
+ }
139
+
140
+ /**
141
+ * Deep transport-redelivery Module for integration execution.
142
+ *
143
+ * A live owner is never stolen. An indeterminate outcome stays blocked inside
144
+ * its owning run, but a later explicit Play Run may replace it. That rerun is
145
+ * fresh user intent and may repeat a side effect whose first outcome was
146
+ * unknown; automatic transport and same-run retries remain fenced.
147
+ */
148
+ export async function executeWithDurableInvocationFence(input: {
149
+ invocationKey: string;
150
+ requestFingerprint: string;
151
+ /** Exact historical fingerprint aliases accepted during a rolling upgrade. */
152
+ acceptedRequestFingerprints?: readonly string[];
153
+ ownerId: string;
154
+ parentRunId: string;
155
+ store: DurableInvocationStore;
156
+ execute: () => Promise<DurableInvocationResponse>;
157
+ /**
158
+ * Fixture execution has no provider-side effect. It may discard an
159
+ * ambiguous transport owner and redeliver the exact request. Live provider
160
+ * execution must leave this false and retain the fail-closed tombstone.
161
+ */
162
+ replaySafeAfterDispatch?: boolean;
163
+ onDispatchStart?: () => void;
164
+ beforeReplay?: () => Promise<void>;
165
+ wait?: (attempt: number) => Promise<void>;
166
+ maxWaitAttempts?: number;
167
+ runningStaleAfterMs?: number;
168
+ now?: () => number;
169
+ onOutcome?: (
170
+ outcome: 'live' | 'replay' | 'in_progress' | 'unknown',
171
+ responseBytes?: number,
172
+ ) => void;
173
+ /**
174
+ * Exceptional transition telemetry. This is intentionally silent on the
175
+ * normal dispatch/commit path so large maps do not produce per-row logs.
176
+ */
177
+ onDiagnostic?: (diagnostic: DurableInvocationDiagnostic) => void;
178
+ }): Promise<DurableInvocationResponse> {
179
+ const diagnose = (
180
+ phase: DurableInvocationDiagnosticPhase,
181
+ error?: unknown,
182
+ ): void => {
183
+ try {
184
+ input.onDiagnostic?.({
185
+ phase,
186
+ ...(error === undefined ? {} : { error }),
187
+ });
188
+ } catch {
189
+ // Observability must never change invocation fencing semantics.
190
+ }
191
+ };
192
+ const retryReplaySafeInvocation = async (
193
+ record: Pick<
194
+ DurableInvocationRecord,
195
+ 'invocationKey' | 'requestFingerprint' | 'ownerId'
196
+ >,
197
+ ): Promise<never> => {
198
+ try {
199
+ const abandoned = await input.store.abandon(record);
200
+ diagnose(
201
+ abandoned ? 'fixture_abandon_succeeded' : 'fixture_abandon_rejected',
202
+ );
203
+ } catch (error) {
204
+ diagnose('fixture_abandon_failed', error);
205
+ // The store may be the failed boundary. The next delivery retries this
206
+ // conditional cleanup after storage recovers; fixture execution remains
207
+ // safe to redeliver either way.
208
+ }
209
+ input.onOutcome?.('in_progress');
210
+ throw new DurableInvocationInProgressError();
211
+ };
212
+
213
+ const markStaleRunningUnknown = async (
214
+ record: DurableInvocationRecord,
215
+ ): Promise<DurableInvocationRecord> => {
216
+ if (record.state !== 'running') return record;
217
+ const updatedAt = Date.parse(record.updatedAt);
218
+ const staleAfterMs = input.runningStaleAfterMs ?? 30 * 60_000;
219
+ if (
220
+ Number.isFinite(updatedAt) &&
221
+ (input.now ?? Date.now)() - updatedAt >= staleAfterMs
222
+ ) {
223
+ const marked = await input.store.markIndeterminate({
224
+ invocationKey: record.invocationKey,
225
+ requestFingerprint: record.requestFingerprint,
226
+ ownerId: record.ownerId,
227
+ });
228
+ if (marked?.state === 'indeterminate') {
229
+ diagnose('stale_running_indeterminate');
230
+ if (marked.parentRunId !== input.parentRunId) {
231
+ return await input.store.begin({
232
+ invocationKey: input.invocationKey,
233
+ requestFingerprint: input.requestFingerprint,
234
+ acceptedRequestFingerprints: input.acceptedRequestFingerprints,
235
+ ownerId: input.ownerId,
236
+ parentRunId: input.parentRunId,
237
+ });
238
+ }
239
+ if (input.replaySafeAfterDispatch) {
240
+ return await retryReplaySafeInvocation(marked);
241
+ }
242
+ throw new DurableInvocationOutcomeUnknownError();
243
+ }
244
+ // The owner may have committed between this follower's stale read and
245
+ // the conditional transition. Read the winner before declaring the
246
+ // provider outcome unknown.
247
+ const winner =
248
+ marked ??
249
+ (await input.store.get({ invocationKey: record.invocationKey }));
250
+ if (!winner) {
251
+ diagnose('stale_running_indeterminate');
252
+ throw new DurableInvocationOutcomeUnknownError();
253
+ }
254
+ assertMatchingRequest(
255
+ winner,
256
+ input.requestFingerprint,
257
+ input.acceptedRequestFingerprints,
258
+ );
259
+ if (winner.state === 'indeterminate' || winner.state === 'compacted') {
260
+ diagnose(
261
+ winner.state === 'indeterminate'
262
+ ? 'stale_running_indeterminate'
263
+ : 'existing_compacted',
264
+ );
265
+ if (input.replaySafeAfterDispatch) {
266
+ return await retryReplaySafeInvocation(winner);
267
+ }
268
+ throw new DurableInvocationOutcomeUnknownError();
269
+ }
270
+ return winner;
271
+ }
272
+ return record;
273
+ };
274
+ let begun = await input.store.begin({
275
+ invocationKey: input.invocationKey,
276
+ requestFingerprint: input.requestFingerprint,
277
+ acceptedRequestFingerprints: input.acceptedRequestFingerprints,
278
+ ownerId: input.ownerId,
279
+ parentRunId: input.parentRunId,
280
+ });
281
+ assertMatchingRequest(
282
+ begun,
283
+ input.requestFingerprint,
284
+ input.acceptedRequestFingerprints,
285
+ );
286
+ if (begun.state === 'indeterminate' || begun.state === 'compacted') {
287
+ diagnose(
288
+ begun.state === 'indeterminate'
289
+ ? 'existing_indeterminate'
290
+ : 'existing_compacted',
291
+ );
292
+ if (input.replaySafeAfterDispatch) {
293
+ return await retryReplaySafeInvocation(begun);
294
+ }
295
+ input.onOutcome?.('unknown');
296
+ throw new DurableInvocationOutcomeUnknownError();
297
+ }
298
+ begun = await markStaleRunningUnknown(begun);
299
+ const replay = completedResponse(begun);
300
+ if (replay) {
301
+ await input.beforeReplay?.();
302
+ input.onOutcome?.('replay', decodedBodyBytes(replay));
303
+ return replay;
304
+ }
305
+
306
+ if (begun.ownerId === input.ownerId) {
307
+ let response: DurableInvocationResponse;
308
+ try {
309
+ // Store/control-plane failures before this boundary are safely
310
+ // retryable: no integration request has started. Unclassified failures
311
+ // after it must fail closed because the provider outcome may be unknown.
312
+ input.onDispatchStart?.();
313
+ response = await input.execute();
314
+ } catch (error) {
315
+ diagnose('dispatch_failed', error);
316
+ if (input.replaySafeAfterDispatch) {
317
+ return await retryReplaySafeInvocation(begun);
318
+ }
319
+ await input.store.markIndeterminate({
320
+ invocationKey: input.invocationKey,
321
+ requestFingerprint: input.requestFingerprint,
322
+ ownerId: input.ownerId,
323
+ });
324
+ throw error;
325
+ }
326
+ let completed: DurableInvocationRecord | null;
327
+ try {
328
+ completed = await input.store.complete({
329
+ invocationKey: input.invocationKey,
330
+ requestFingerprint: input.requestFingerprint,
331
+ ownerId: input.ownerId,
332
+ response,
333
+ });
334
+ } catch (error) {
335
+ diagnose('completion_failed', error);
336
+ if (!input.replaySafeAfterDispatch) throw error;
337
+ try {
338
+ const winner = await input.store.get({
339
+ invocationKey: input.invocationKey,
340
+ });
341
+ if (winner) {
342
+ assertMatchingRequest(
343
+ winner,
344
+ input.requestFingerprint,
345
+ input.acceptedRequestFingerprints,
346
+ );
347
+ const committed = completedResponse(winner);
348
+ if (committed) {
349
+ diagnose('completion_recovered');
350
+ input.onOutcome?.('replay', decodedBodyBytes(committed));
351
+ return committed;
352
+ }
353
+ }
354
+ } catch {
355
+ // Fall through to the fixture-safe conditional cleanup below.
356
+ }
357
+ return await retryReplaySafeInvocation(begun);
358
+ }
359
+ if (!completed) {
360
+ diagnose('completion_missing');
361
+ const winner = await input.store.get({
362
+ invocationKey: input.invocationKey,
363
+ });
364
+ if (winner) {
365
+ assertMatchingRequest(
366
+ winner,
367
+ input.requestFingerprint,
368
+ input.acceptedRequestFingerprints,
369
+ );
370
+ const committed = completedResponse(winner);
371
+ if (committed) {
372
+ diagnose('completion_recovered');
373
+ input.onOutcome?.('replay', decodedBodyBytes(committed));
374
+ return committed;
375
+ }
376
+ }
377
+ if (input.replaySafeAfterDispatch) {
378
+ return await retryReplaySafeInvocation(begun);
379
+ }
380
+ await input.store.markIndeterminate({
381
+ invocationKey: input.invocationKey,
382
+ requestFingerprint: input.requestFingerprint,
383
+ ownerId: input.ownerId,
384
+ });
385
+ input.onOutcome?.('unknown');
386
+ throw new DurableInvocationCommitError();
387
+ }
388
+ assertMatchingRequest(
389
+ completed,
390
+ input.requestFingerprint,
391
+ input.acceptedRequestFingerprints,
392
+ );
393
+ const committed = completedResponse(completed) ?? response;
394
+ input.onOutcome?.('live', decodedBodyBytes(committed));
395
+ return committed;
396
+ }
397
+
398
+ if (input.replaySafeAfterDispatch) {
399
+ diagnose('foreign_owner_running');
400
+ return await retryReplaySafeInvocation(begun);
401
+ }
402
+
403
+ const maxWaitAttempts = input.maxWaitAttempts ?? 20;
404
+ for (let attempt = 1; attempt <= maxWaitAttempts; attempt += 1) {
405
+ await (input.wait?.(attempt) ??
406
+ new Promise<void>((resolve) => setTimeout(resolve, 250)));
407
+ let latest = await input.store.get({
408
+ invocationKey: input.invocationKey,
409
+ });
410
+ if (!latest) continue;
411
+ assertMatchingRequest(
412
+ latest,
413
+ input.requestFingerprint,
414
+ input.acceptedRequestFingerprints,
415
+ );
416
+ if (
417
+ latest.state === 'indeterminate' &&
418
+ latest.parentRunId !== input.parentRunId
419
+ ) {
420
+ return await executeWithDurableInvocationFence(input);
421
+ }
422
+ if (latest.state === 'indeterminate' || latest.state === 'compacted') {
423
+ diagnose(
424
+ latest.state === 'indeterminate'
425
+ ? 'existing_indeterminate'
426
+ : 'existing_compacted',
427
+ );
428
+ input.onOutcome?.('unknown');
429
+ throw new DurableInvocationOutcomeUnknownError();
430
+ }
431
+ latest = await markStaleRunningUnknown(latest);
432
+ const response = completedResponse(latest);
433
+ if (response) {
434
+ await input.beforeReplay?.();
435
+ input.onOutcome?.('replay', decodedBodyBytes(response));
436
+ return response;
437
+ }
438
+ }
439
+ diagnose('wait_exhausted');
440
+ input.onOutcome?.('in_progress');
441
+ throw new DurableInvocationInProgressError();
442
+ }
@@ -14,9 +14,9 @@ export const PLAY_RUNTIME_PROTOCOL = {
14
14
  /**
15
15
  * Current scheduler/runner protocol. This number STAYS AT 1: the additive
16
16
  * compatibility rule (`docs/runtime-compatibility-contract.md`) covers new
17
- * fields and new named actions without a bump. A bump is a fence release —
18
- * two PRs, expand worker support first, then enable — and needs a written
19
- * reason the additive rule cannot serve.
17
+ * fields and new named actions without a bump. The required compatibility
18
+ * audit freezes these historical tags; ship a new action's reader before
19
+ * its writer instead of changing a global number.
20
20
  */
21
21
  current: 1,
22
22
  } as const;
@@ -51,6 +51,10 @@ const FIXTURE_MODE_BYPASS_PROVIDERS = new Set([
51
51
  'test',
52
52
  'test_high',
53
53
  'test_low',
54
+ // Dedicated stateful failure fixtures must reach their local custom handlers
55
+ // even when the surrounding Play runs in fixture mode.
56
+ 'test_receipt',
57
+ 'test_retry',
54
58
  'test_unhinted',
55
59
  ]);
56
60
 
@@ -443,6 +447,20 @@ export function shouldRouteFixtureToolId(toolId: string): boolean {
443
447
  );
444
448
  }
445
449
 
450
+ /** Only canned fixture responses are safe to redispatch after response loss. */
451
+ export function isReplaySafeFixtureToolId(toolId: string): boolean {
452
+ const normalized = toolId.trim().toLowerCase();
453
+ // Managed inference can use the fake Gateway while exercising real wallet
454
+ // authorization and settlement. Its invocation fence must survive retries.
455
+ // Keep all inference variants fenced, including aliases and local emulators.
456
+ return (
457
+ shouldRouteFixtureToolId(normalized) &&
458
+ normalized !== 'ai_inference' &&
459
+ normalized !== 'deeplineagent' &&
460
+ !normalized.startsWith('deeplineagent_')
461
+ );
462
+ }
463
+
446
464
  function stableFixtureRequestHash(value: string): number {
447
465
  let hash = 0x811c9dc5;
448
466
  for (let index = 0; index < value.length; index += 1) {
@@ -483,6 +483,15 @@ export class AppRuntimeRateStateBackend implements RateStateBackend {
483
483
  );
484
484
  return;
485
485
  }
486
+ // Zero grants without a finite positive wait cannot make progress.
487
+ // Older gateways return this for an empty/invalid normalized rule set;
488
+ // fail exhausted instead of spinning once per millisecond forever.
489
+ if (!Number.isFinite(response.waitMs) || response.waitMs <= 0) {
490
+ throw this.providerExhaustedFromResponse(bucketId, {
491
+ ...response,
492
+ waitMs: 0,
493
+ });
494
+ }
486
495
  // Live path: the server told us to wait past the threshold. Fail fast
487
496
  // with a typed PROVIDER_EXHAUSTED instead of sleeping toward it. The
488
497
  // rejection propagates to every waiter parked on this single-flight
@@ -16,7 +16,7 @@
16
16
  * is no `null`, no "off", no implicit infinity. Unaccounted resource use
17
17
  * must be impossible.
18
18
  *
19
- * The docs catalog (`src/lib/plays/limits-catalog.ts`) and its generated public
19
+ * The docs catalog (`apps/deepline-api/src/lib/plays/limits-catalog.ts`) and its generated public
20
20
  * + internal pages source their numbers from this table.
21
21
  */
22
22
 
@@ -24,7 +24,7 @@ export interface PacingRule {
24
24
 
25
25
  /**
26
26
  * Per-tool queue-hint metadata produced by the runtime tool catalog
27
- * (`src/lib/plays/runtime-tool-metadata.ts`) and surfaced to the runtime via
27
+ * (`packages/integrations/runtime-tool-metadata.ts`) and surfaced to the runtime via
28
28
  * `ContextOptions.getToolQueueHints`. It is the raw provider rate-limit metadata
29
29
  * that the runtime maps into one {@link PacingRule} per hint before handing it
30
30
  * to the Governor's pacing resolver. The `provider` field identifies the pacing
@@ -0,0 +1,66 @@
1
+ /**
2
+ * The storage format a gateway may write for one Runtime Postgres schema.
3
+ *
4
+ * `canonical_v1` is deliberately a reader capability, not a deploy toggle:
5
+ * every gateway which can encounter the schema must be able to materialize
6
+ * canonical operation outcomes before this mode is recorded.
7
+ */
8
+ export type IntegrationOperationStorageMode =
9
+ | 'legacy_byte_reader'
10
+ | 'canonical_v1';
11
+
12
+ export const INTEGRATION_OPERATION_CANONICAL_READER_CAPABILITY =
13
+ 'integration-operation-canonical-v1' as const;
14
+
15
+ export type RuntimeGatewayRole = 'receipt' | 'execution';
16
+
17
+ /**
18
+ * Operator-verified evidence that both durable gateway reader fleets can
19
+ * understand canonical Integration Operation rows. The control-plane verifier
20
+ * collects this evidence; this module records and validates its shape.
21
+ */
22
+ export type CanonicalReaderProof = {
23
+ capability: typeof INTEGRATION_OPERATION_CANONICAL_READER_CAPABILITY;
24
+ sourceSha: string;
25
+ machineIds: Readonly<Record<RuntimeGatewayRole, readonly string[]>>;
26
+ };
27
+
28
+ /**
29
+ * The local Runtime Postgres mirror of the control-plane reader fence.
30
+ * `schema` is the scheduler schema/namespace, never an application or lane.
31
+ */
32
+ export type RuntimeGatewayReaderFence = {
33
+ schema: string;
34
+ /** Strictly positive, monotonically increasing within a schema. */
35
+ epoch: number;
36
+ mode: IntegrationOperationStorageMode;
37
+ canonicalReaderProof: CanonicalReaderProof | null;
38
+ };
39
+
40
+ export type RuntimeGatewayReaderFenceCandidate = RuntimeGatewayReaderFence;
41
+
42
+ export type ReaderFenceWriterMode = {
43
+ mode: IntegrationOperationStorageMode;
44
+ /** `absent` and unavailable storage are intentionally legacy-only. */
45
+ source: 'fence' | 'absent' | 'fail_closed';
46
+ epoch: number | null;
47
+ failure?: 'store_unavailable' | 'invalid_record';
48
+ };
49
+
50
+ export type ReaderFenceApplyOutcome =
51
+ | { kind: 'advanced'; fence: RuntimeGatewayReaderFence }
52
+ | { kind: 'already_applied'; fence: RuntimeGatewayReaderFence }
53
+ | {
54
+ kind: 'rejected';
55
+ reason: 'stale_epoch' | 'epoch_conflict' | 'unsafe_mode_downgrade';
56
+ current: RuntimeGatewayReaderFence;
57
+ };
58
+
59
+ export type RuntimeGatewayReaderFenceJob = {
60
+ /** Resolve the only format this gateway may write. Never returns canonical on uncertainty. */
61
+ writerMode(input: { schema: string }): Promise<ReaderFenceWriterMode>;
62
+ /** Advance the mirror only with a strictly newer epoch, or retry the exact same fence. */
63
+ apply(
64
+ candidate: RuntimeGatewayReaderFenceCandidate,
65
+ ): Promise<ReaderFenceApplyOutcome>;
66
+ };