deepline 0.1.243 → 0.1.244

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 (71) hide show
  1. package/README.md +1 -1
  2. package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +5 -25
  3. package/dist/bundling-sources/sdk/src/release.ts +23 -21
  4. package/dist/bundling-sources/sdk/src/types.ts +1 -1
  5. package/dist/bundling-sources/shared_libs/play-runtime/backend.ts +2 -21
  6. package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +5 -6
  7. package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +6 -13
  8. package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +9 -26
  9. package/dist/bundling-sources/shared_libs/play-runtime/internal-step-ids.ts +1 -2
  10. package/dist/bundling-sources/shared_libs/play-runtime/map-row-identity.ts +1 -1
  11. package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +191 -29
  12. package/dist/bundling-sources/shared_libs/play-runtime/play-latency-trace.ts +1 -1
  13. package/dist/bundling-sources/shared_libs/play-runtime/providers.ts +1 -36
  14. package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +2 -3
  15. package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/index.ts +0 -7
  16. package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +1 -12
  17. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-pg.ts +2 -3
  18. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver.ts +5 -15
  19. package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +6 -21
  20. package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +3 -4
  21. package/dist/bundling-sources/shared_libs/plays/artifact-kind-guard.ts +16 -29
  22. package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +4 -8
  23. package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +21 -712
  24. package/dist/bundling-sources/shared_libs/plays/bundling/limits.ts +1 -18
  25. package/dist/cli/index.js +29 -71
  26. package/dist/cli/index.mjs +29 -71
  27. package/dist/{compiler-manifest-CYcwzSOJ.d.ts → compiler-manifest-DlE7dnRm.d.mts} +2 -8
  28. package/dist/{compiler-manifest-CYcwzSOJ.d.mts → compiler-manifest-DlE7dnRm.d.ts} +2 -8
  29. package/dist/index.d.mts +2 -2
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +24 -22
  32. package/dist/index.mjs +24 -22
  33. package/dist/plays/bundle-play-file.d.mts +7 -22
  34. package/dist/plays/bundle-play-file.d.ts +7 -22
  35. package/dist/plays/bundle-play-file.mjs +26 -614
  36. package/package.json +2 -2
  37. package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +0 -4504
  38. package/dist/bundling-sources/apps/play-runner-workers/src/dedup-do.ts +0 -1386
  39. package/dist/bundling-sources/apps/play-runner-workers/src/durable-object-deploy-handoff.ts +0 -30
  40. package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +0 -8385
  41. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/README.md +0 -21
  42. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +0 -251
  43. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/coordinator-progress.ts +0 -289
  44. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/csv-rows.ts +0 -85
  45. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/customer-console.ts +0 -23
  46. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/dataset-handles.ts +0 -528
  47. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/harness-receipt-store.ts +0 -229
  48. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/ledger-event-batches.ts +0 -81
  49. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/live-progress.ts +0 -22
  50. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +0 -920
  51. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-latency-profile.ts +0 -90
  52. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/output-datasets.ts +0 -475
  53. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/receipts.ts +0 -570
  54. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/result-dataset-persistence.ts +0 -50
  55. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/row-isolation.ts +0 -5
  56. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/run-work-dispatcher.ts +0 -519
  57. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-batch.ts +0 -107
  58. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +0 -2541
  59. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-http-errors.ts +0 -7
  60. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-receipts.ts +0 -227
  61. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/work-budget.ts +0 -130
  62. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/worker-platform-budget.ts +0 -39
  63. package/dist/bundling-sources/apps/play-runner-workers/src/runtime/workflow-preview.ts +0 -26
  64. package/dist/bundling-sources/apps/play-runner-workers/src/runtime-api-retry.ts +0 -23
  65. package/dist/bundling-sources/apps/play-runner-workers/src/workflow-instance-create.ts +0 -47
  66. package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry-state.ts +0 -167
  67. package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry.ts +0 -91
  68. package/dist/bundling-sources/sdk/src/plays/harness-stub.ts +0 -329
  69. package/dist/bundling-sources/sdk/src/worker-play-entry.ts +0 -240
  70. package/dist/bundling-sources/shared_libs/play-runtime/governor/coordinator-rate-state-backend.ts +0 -252
  71. package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +0 -217
package/README.md CHANGED
@@ -326,7 +326,7 @@ V2 prebuilt play sources are authored directly in `src/lib/plays/v2/`. After
326
326
  editing them, regenerate the committed Workers and share-page artifacts:
327
327
 
328
328
  ```bash
329
- bun scripts/regen.ts workers-prebuilt prebuilt-share-pages
329
+ bun scripts/regen.ts prebuilt-share-pages
330
330
  ```
331
331
 
332
332
  ## File structure
@@ -44,7 +44,7 @@ const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
44
44
  const SDK_PACKAGE_ROOT = resolve(MODULE_DIR, '..', '..');
45
45
  const SOURCE_REPO_ROOT = resolve(SDK_PACKAGE_ROOT, '..');
46
46
  const HAS_SOURCE_BUNDLING_SOURCES = existsSync(
47
- resolve(SOURCE_REPO_ROOT, 'apps', 'play-runner-workers', 'src', 'entry.ts'),
47
+ resolve(SOURCE_REPO_ROOT, 'shared_libs', 'plays', 'bundling', 'index.ts'),
48
48
  );
49
49
  const PACKAGED_BUNDLING_SOURCE_ROOT = resolve(
50
50
  SDK_PACKAGE_ROOT,
@@ -54,10 +54,10 @@ const PACKAGED_BUNDLING_SOURCE_ROOT = resolve(
54
54
  const HAS_PACKAGED_BUNDLING_SOURCES = existsSync(
55
55
  resolve(
56
56
  PACKAGED_BUNDLING_SOURCE_ROOT,
57
- 'apps',
58
- 'play-runner-workers',
59
- 'src',
60
- 'entry.ts',
57
+ 'shared_libs',
58
+ 'plays',
59
+ 'bundling',
60
+ 'index.ts',
61
61
  ),
62
62
  );
63
63
  const PROJECT_ROOT = HAS_SOURCE_BUNDLING_SOURCES
@@ -75,20 +75,6 @@ const SDK_ENTRY_FILE = resolve(SDK_SOURCE_ROOT, 'index.ts');
75
75
  const SDK_TYPES_ENTRY_FILE = HAS_SOURCE_BUNDLING_SOURCES
76
76
  ? SDK_ENTRY_FILE
77
77
  : resolve(SDK_PACKAGE_ROOT, 'dist', 'index.d.ts');
78
- const SDK_WORKERS_ENTRY_FILE = resolve(SDK_SOURCE_ROOT, 'worker-play-entry.ts');
79
- const WORKERS_HARNESS_ENTRY_FILE = resolve(
80
- PROJECT_ROOT,
81
- 'apps',
82
- 'play-runner-workers',
83
- 'src',
84
- 'entry.ts',
85
- );
86
- const WORKERS_HARNESS_FILES_DIR = resolve(
87
- PROJECT_ROOT,
88
- 'apps',
89
- 'play-runner-workers',
90
- 'src',
91
- );
92
78
  let hasWarnedAboutNonDevelopmentBundling = false;
93
79
 
94
80
  /**
@@ -150,12 +136,6 @@ export function createSdkPlayBundlingAdapter(): PlayBundlingAdapter {
150
136
  HAS_SOURCE_BUNDLING_SOURCES || !existsSync(SDK_TYPES_ENTRY_FILE)
151
137
  ? SDK_ENTRY_FILE
152
138
  : SDK_TYPES_ENTRY_FILE,
153
- sdkWorkersEntryFile: SDK_WORKERS_ENTRY_FILE,
154
- workersHarnessEntryFile: WORKERS_HARNESS_ENTRY_FILE,
155
- workersHarnessFilesDir: WORKERS_HARNESS_FILES_DIR,
156
- workersRuntimeFingerprintDirs: [
157
- resolve(PROJECT_ROOT, 'shared_libs', 'play-runtime'),
158
- ],
159
139
  discoverPackagedLocalFiles,
160
140
  warnAboutNonDevelopmentBundling,
161
141
  };
@@ -113,10 +113,12 @@ export const SDK_RELEASE = {
113
113
  // 0.1.241 hard-cuts published and launched plays to immutable cjs_node20
114
114
  // artifacts. Older clients can submit esm_workers artifacts that the Absurd
115
115
  // runtime intentionally no longer compiles at publish or launch time.
116
- version: '0.1.243',
117
- apiContract: '2026-07-immutable-cjs-play-artifacts-hard-cutover',
116
+ // 0.1.242 removes the retired Workers/ESM compiler, generated bundles, and
117
+ // deploy-time artifact migration. Play authoring now has one CJS contract.
118
+ version: '0.1.244',
119
+ apiContract: '2026-07-cjs-absurd-only-play-runtime-hard-cutover',
118
120
  supportPolicy: {
119
- latest: '0.1.243',
121
+ latest: '0.1.244',
120
122
  minimumSupported: '0.1.53',
121
123
  deprecatedBelow: '0.1.219',
122
124
  commandMinimumSupported: [
@@ -128,61 +130,61 @@ export const SDK_RELEASE = {
128
130
  },
129
131
  {
130
132
  command: 'plays',
131
- minimumSupported: '0.1.111',
133
+ minimumSupported: '0.1.241',
132
134
  reason:
133
- 'Play file commands now use dataset-native list getters and result row datasets.',
135
+ 'Older SDK CLI versions predate dataset-native Play results and can emit the retired esm_workers artifact contract. Update before checking, publishing, or running plays.',
134
136
  },
135
137
  {
136
138
  command: 'plays run',
137
- minimumSupported: '0.1.111',
139
+ minimumSupported: '0.1.241',
138
140
  reason:
139
- 'Play run results now promote row-shaped outputs into dataset handles for safe export.',
141
+ 'Older SDK CLI versions predate dataset-native Play results and can emit the retired esm_workers artifact contract.',
140
142
  },
141
143
  {
142
144
  command: 'run',
143
145
  displayCommand: 'plays run',
144
- minimumSupported: '0.1.111',
146
+ minimumSupported: '0.1.241',
145
147
  reason:
146
- 'Play run results now promote row-shaped outputs into dataset handles for safe export.',
148
+ 'Older SDK CLI versions predate dataset-native Play results and can emit the retired esm_workers artifact contract.',
147
149
  },
148
150
  {
149
151
  command: 'plays check',
150
- minimumSupported: '0.1.111',
152
+ minimumSupported: '0.1.241',
151
153
  reason:
152
- 'Play file checks now validate dataset-native list getter authoring.',
154
+ 'Older SDK CLI versions predate dataset-native Play authoring and validate against the retired esm_workers artifact contract.',
153
155
  },
154
156
  {
155
157
  command: 'check',
156
158
  displayCommand: 'plays check',
157
- minimumSupported: '0.1.111',
159
+ minimumSupported: '0.1.241',
158
160
  reason:
159
- 'Play file checks now validate dataset-native list getter authoring.',
161
+ 'Older SDK CLI versions predate dataset-native Play authoring and validate against the retired esm_workers artifact contract.',
160
162
  },
161
163
  {
162
164
  command: 'plays publish',
163
- minimumSupported: '0.1.111',
165
+ minimumSupported: '0.1.241',
164
166
  reason:
165
- 'Published play artifacts now target dataset-native list getters and result row datasets.',
167
+ 'Older SDK CLI versions predate dataset-native Play artifacts and can publish the retired esm_workers artifact contract.',
166
168
  },
167
169
  {
168
170
  command: 'publish',
169
171
  displayCommand: 'plays publish',
170
- minimumSupported: '0.1.111',
172
+ minimumSupported: '0.1.241',
171
173
  reason:
172
- 'Published play artifacts now target dataset-native list getters and result row datasets.',
174
+ 'Older SDK CLI versions predate dataset-native Play artifacts and can publish the retired esm_workers artifact contract.',
173
175
  },
174
176
  {
175
177
  command: 'plays set-live',
176
- minimumSupported: '0.1.111',
178
+ minimumSupported: '0.1.241',
177
179
  reason:
178
- 'Published play artifacts now target dataset-native list getters and result row datasets.',
180
+ 'Older SDK CLI versions predate dataset-native Play artifacts and can publish the retired esm_workers artifact contract.',
179
181
  },
180
182
  {
181
183
  command: 'set-live',
182
184
  displayCommand: 'plays set-live',
183
- minimumSupported: '0.1.111',
185
+ minimumSupported: '0.1.241',
184
186
  reason:
185
- 'Published play artifacts now target dataset-native list getters and result row datasets.',
187
+ 'Older SDK CLI versions predate dataset-native Play artifacts and can publish the retired esm_workers artifact contract.',
186
188
  },
187
189
  {
188
190
  command: 'runs',
@@ -1221,7 +1221,7 @@ export interface StartPlayRunRequest {
1221
1221
  waitForCompletionMs?: number;
1222
1222
  /**
1223
1223
  * Per-run execution profile override. The server defaults to absurd. The
1224
- * workers_edge profile is disabled; most callers should leave this unset.
1224
+ * Only `absurd` is accepted; most callers should leave this unset.
1225
1225
  */
1226
1226
  profile?: string;
1227
1227
  /** Optional per-run provider execution mode for eval/smoke runs. */
@@ -1,27 +1,17 @@
1
1
  export const PLAY_RUNTIME_BACKENDS = {
2
2
  localProcess: 'local_process',
3
3
  daytona: 'daytona',
4
- // Artifact/runtime contract for Cloudflare Dynamic Workers. This is no
5
- // longer a standalone runner backend; use profile=workers_edge so the
6
- // cf-workflows scheduler owns loading and execution.
7
- cloudflareWorkers: 'cloudflare_workers',
8
4
  } as const;
9
5
 
10
6
  export type PlayRuntimeBackendId =
11
7
  (typeof PLAY_RUNTIME_BACKENDS)[keyof typeof PLAY_RUNTIME_BACKENDS];
12
8
 
13
9
  /**
14
- * The runtime shape of a built play artifact. Different runner backends need
15
- * different bundle outputs:
16
- * - cjs_node20: Daytona + local-process (full Node.js sandbox).
17
- * - esm_workers: Cloudflare Workers (V8 isolate, no `fs`/`child_process`).
18
- *
19
- * The CLI selects which kind to build based on the target backend; the worker
20
- * validates the kind matches the backend it's about to dispatch to.
10
+ * The one executable Play artifact contract. Daytona and local-process both
11
+ * load CommonJS under Node 20.
21
12
  */
22
13
  export const PLAY_ARTIFACT_KINDS = {
23
14
  cjsNode20: 'cjs_node20',
24
- esmWorkers: 'esm_workers',
25
15
  } as const;
26
16
 
27
17
  export type PlayArtifactKind =
@@ -49,11 +39,6 @@ export const PLAY_BACKEND_DESCRIPTORS: Record<
49
39
  artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
50
40
  label: 'Daytona sandbox',
51
41
  },
52
- [PLAY_RUNTIME_BACKENDS.cloudflareWorkers]: {
53
- id: PLAY_RUNTIME_BACKENDS.cloudflareWorkers,
54
- artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
55
- label: 'Cloudflare Dynamic Workers',
56
- },
57
42
  };
58
43
 
59
44
  export function describePlayBackend(
@@ -84,10 +69,6 @@ export function normalizePlayRuntimeBackend(
84
69
  return PLAY_RUNTIME_BACKENDS.localProcess;
85
70
  }
86
71
 
87
- if (normalized === PLAY_RUNTIME_BACKENDS.cloudflareWorkers) {
88
- return PLAY_RUNTIME_BACKENDS.cloudflareWorkers;
89
- }
90
-
91
72
  throw new Error(
92
73
  `Unsupported play runtime backend "${normalized}". Expected one of: ${Object.values(
93
74
  PLAY_RUNTIME_BACKENDS,
@@ -1,11 +1,9 @@
1
1
  /**
2
2
  * Play Execution Governor — the deep module that owns execution policy.
3
3
  *
4
- * Both runner Adapters (`cjs_node20`, `esm_workers`) gate their work through one
5
- * Governor instance per run-attempt so the substrates cannot diverge on
6
- * concurrency, budgets, or pacing. Adapters keep only substrate mechanism (how
7
- * to resolve a row, batch a tool call, or submit a child); the Governor owns the
8
- * "may I, and how many at once" policy. See ADR 0007 + CONTEXT.md.
4
+ * The CJS runner gates work through one Governor instance per run-attempt. The
5
+ * runner owns execution mechanics; the Governor owns the "may I, and how many
6
+ * at once" policy. See ADR 0007 + CONTEXT.md.
9
7
  *
10
8
  * Surface (small, by design):
11
9
  * - acquireRowSlot / acquireToolSlot → blocking leases
@@ -283,7 +281,8 @@ export function createPlayExecutionGovernor(
283
281
  }
284
282
 
285
283
  const scopeFor = (toolId: string | undefined, provider: string) =>
286
- scopeByTool.get(toolId ?? '') ?? ([orgBucket(provider), ''] as [string, string]);
284
+ scopeByTool.get(toolId ?? '') ??
285
+ ([orgBucket(provider), ''] as [string, string]);
287
286
 
288
287
  async function resolveAdaptivePacing(toolId: string): Promise<{
289
288
  provider: string;
@@ -2,10 +2,8 @@
2
2
  * Play Execution Governor — the single policy table.
3
3
  *
4
4
  * This is the ONE source of truth for every concurrency, budget, and pacing
5
- * number in the play runtime. Both runner Adapters (`cjs_node20` in-process and
6
- * `esm_workers` cloud) resolve their limits from here, so the two substrates
7
- * cannot drift. See ADR 0007 and the "Play Execution Governor" entry in
8
- * CONTEXT.md.
5
+ * number in the CJS/Node play runtime. See ADR 0007 and the "Play Execution
6
+ * Governor" entry in CONTEXT.md.
9
7
  *
10
8
  * Tuning philosophy (product decision):
11
9
  * - Caps are explicit resource admission boundaries. A run should queue behind
@@ -51,13 +49,9 @@ export interface ExecutionBudgetPolicy {
51
49
  /**
52
50
  * Per-provider rate pacing — the real outbound throughput governor.
53
51
  *
54
- * SUBSTRATE NOTE: the per-provider request RATE (`requestsPerWindow`/`windowMs`
55
- * from a provider's `PacingRule`s) is enforced on BOTH substrates. A rule's
56
- * optional `maxConcurrency` (simultaneous-in-flight cap) is enforced only on
57
- * `cjs_node20`; on `esm_workers` it is intentionally excluded from the pacing
58
- * contract because a fanned-out run cannot guarantee the per-isolate release
59
- * signal an in-flight count needs, so only the org-wide tool-concurrency
60
- * backstop applies there. See PacingRule.maxConcurrency in rate-state-backend.ts.
52
+ * Per-provider request rate and optional in-flight concurrency are enforced by
53
+ * the same CJS/Node substrate. See PacingRule.maxConcurrency in
54
+ * rate-state-backend.ts.
61
55
  */
62
56
  export interface ExecutionPacingPolicy {
63
57
  /** RPS applied to a provider that declares no explicit rate limit. */
@@ -120,7 +114,7 @@ export const SHARED_EXECUTION_POLICY: ResolvedExecutionPolicy = {
120
114
  },
121
115
  };
122
116
 
123
- export type AdapterId = 'cjs_node20' | 'esm_workers';
117
+ export type AdapterId = 'cjs_node20';
124
118
 
125
119
  /**
126
120
  * One level deep on purpose: each policy section is a flat record of numbers, so
@@ -141,7 +135,6 @@ type PolicyOverride = {
141
135
  */
142
136
  export const ADAPTER_POLICY_OVERRIDES: Record<AdapterId, PolicyOverride> = {
143
137
  cjs_node20: {},
144
- esm_workers: {},
145
138
  };
146
139
 
147
140
  /** Merge the shared policy with any documented Adapter override. */
@@ -1,14 +1,9 @@
1
1
  /**
2
2
  * Rate State Backend — the one swappable seam of the Play Execution Governor.
3
3
  *
4
- * Per-`(org, provider)` rate windows are the only execution state that cannot be
5
- * process-local: on `esm_workers` a run fans child plays across isolates, so the
6
- * window must be shared. Everything else the Governor owns (budgets, concurrency
7
- * slots) stays Governor-local and threads down the lineage via the snapshot.
8
- *
9
- * Adapters: an in-memory backend for the single-process `cjs_node20` runner, and
10
- * a shared backend (Run Coordination Cache Durable Object, or server-side Redis)
11
- * for `esm_workers`. See ADR 0007 and CONTEXT.md (Rate State Backend).
4
+ * Per-`(org, provider)` rate windows are shared across CJS runner processes.
5
+ * Everything else the Governor owns stays local to one run attempt and threads
6
+ * down the lineage via the snapshot. See ADR 0007 and CONTEXT.md.
12
7
  */
13
8
 
14
9
  /** A single resolved rate rule for a bucket (from rate-limit-definitions). */
@@ -19,16 +14,8 @@ export interface PacingRule {
19
14
  /**
20
15
  * Optional simultaneous-in-flight cap for this rule.
21
16
  *
22
- * SUBSTRATE NOTE: `maxConcurrency` is enforced ONLY on `cjs_node20` (the
23
- * single-process {@link RateStateBackend} can hold a reliable in-flight count
24
- * and release it on permit.release). On `esm_workers` it is intentionally NOT
25
- * enforced: a run fans across V8 isolates and a dying isolate cannot guarantee
26
- * the release signal a leased in-flight count would require, so the
27
- * coordinator DO debits `requestsPerWindow` only. The Governor's global
28
- * tool-concurrency semaphore is the cross-isolate in-flight backstop there.
29
- * `requestsPerWindow`/`windowMs` (the request-RATE governor) ARE enforced on
30
- * both substrates. See coordinator-rate-state-backend.ts and dedup-do.ts
31
- * (computeRateAcquire) for the workers side.
17
+ * The CJS runtime holds a reliable in-flight count and releases it on
18
+ * permit.release. `requestsPerWindow`/`windowMs` enforce request rate.
32
19
  */
33
20
  readonly maxConcurrency: number | null;
34
21
  }
@@ -60,25 +47,21 @@ export interface PacingPermit {
60
47
  * Discriminates the backend so the Governor can adapt its policy to it. Only
61
48
  * `app_runtime_postgres` (the Absurd/Node substrate's DB-backed pacer) is
62
49
  * db-authoritative: it runs the whole token-bucket + AIMD in Postgres, so the
63
- * Governor's in-memory adaptive admission must become a passthrough and defer
64
- * pacing to the row. The in-memory and coordinator backends leave `kind`
65
- * undefined and keep the Governor's in-memory adaptive admission (byte-identical
66
- * to today).
50
+ * Governor's in-memory adaptive admission becomes a passthrough and defers
51
+ * pacing to the row. The in-memory backend leaves `kind` undefined.
67
52
  */
68
53
  export type RateStateBackendKind = 'app_runtime_postgres';
69
54
 
70
55
  export interface RateStateBackend {
71
56
  /**
72
57
  * When present, tells the Governor this backend owns pacing authoritatively.
73
- * Absent on the in-memory and coordinator backends — those keep the Governor's
74
- * in-memory adaptive admission.
58
+ * Absent on the in-memory backend.
75
59
  */
76
60
  readonly kind?: RateStateBackendKind;
77
61
 
78
62
  /**
79
63
  * Block until one outbound call is permitted for `bucketId` under all `rules`
80
- * (request windows always; per-rule `maxConcurrency` only on the in-memory
81
- * `cjs_node20` backend — see {@link PacingRule.maxConcurrency}), then debit and
64
+ * (request windows and per-rule `maxConcurrency`), then debit and
82
65
  * return a permit. `bucketId` is `${orgId}:${provider}` so the window is global
83
66
  * per (org, provider). Resolves immediately when `rules` is empty (provider has
84
67
  * no configured limit — pacing is a no-op, the global tool-concurrency backstop
@@ -6,8 +6,7 @@
6
6
  * machine-generated source line range (`lines_<startLine>_<endLine>`, built in
7
7
  * `src/lib/plays/static-analysis.ts` → `createCodeStageForStatements`). The
8
8
  * execution plan / runtime node ids namespace every substep by its type
9
- * (`getStaticSubstepNodeId` in `src/lib/plays/step-progress.ts` and
10
- * `apps/play-runner-workers/src/entry.ts`), so glue nodes are ALWAYS
9
+ * (`getStaticSubstepNodeId` in `src/lib/plays/step-progress.ts`), so glue nodes are ALWAYS
11
10
  * `run_javascript:<alias>` on the wire (ledger stepsById, snapshot
12
11
  * nodeStates, `play.step.*` stream events).
13
12
  *
@@ -3,7 +3,7 @@ import {
3
3
  derivePlayRowIdentityFromKey,
4
4
  // Relative (not '@shared_libs/...') because this file ships inside the
5
5
  // packed SDK's dist/bundling-sources graph (reachable from the
6
- // apps/play-runner-workers entry), where only relative imports resolve.
6
+ // packaged runner entry), where only relative imports resolve.
7
7
  } from '../plays/row-identity';
8
8
  import type { MapExecutionScope } from './ctx-types';
9
9
 
@@ -13,7 +13,16 @@ export const TERMINAL_RUN_RESULT_MAX_BYTES = 2_500_000;
13
13
  * of provider payload — which is durable in scheduler Postgres and never read
14
14
  * back from Convex, yet deterministically wedged the append.
15
15
  */
16
- export const LEDGER_TERMINAL_RESULT_MAX_BYTES = 768 * 1024;
16
+ // The terminal projection is persisted twice on `playRuns` (top-level result
17
+ // and runSnapshot.result), in addition to the event document. Keep one copy at
18
+ // 256 KiB so ordinary snapshots retain headroom under Convex's 1 MiB document
19
+ // ceiling. The runtime route has a reference-only fallback for an unusually
20
+ // large pre-existing snapshot that still exceeds the aggregate document cap.
21
+ export const LEDGER_TERMINAL_RESULT_MAX_BYTES = 256 * 1024;
22
+ export const LEDGER_TERMINAL_RESULT_MAX_DEPTH = 10;
23
+ export const CONVEX_LEDGER_ARRAY_MAX_ITEMS = 8_192;
24
+ export const CONVEX_LEDGER_OBJECT_MAX_FIELDS = 1_024;
25
+ export const CONVEX_LEDGER_FIELD_NAME_MAX_LENGTH = 1_024;
17
26
  export const CUSTOMER_OUTPUT_VALUE_MAX_BYTES = 1 * 1024 * 1024;
18
27
  export const CUSTOMER_OUTPUT_TOTAL_MAX_BYTES = 2 * 1024 * 1024;
19
28
  /** Inline Postgres receipt contract: one serialized output is at most 10 MiB. */
@@ -121,13 +130,183 @@ export type LedgerTerminalResultRef = {
121
130
  key: 'terminal_result_json';
122
131
  /** Serialized byte size of the result that was elided from the ledger. */
123
132
  bytes: number;
124
- reason: 'terminal_result_exceeds_ledger_limit';
133
+ reason: LedgerTerminalResultRefReason;
134
+ };
135
+
136
+ export type LedgerTerminalResultRefReason =
137
+ | 'terminal_result_exceeds_ledger_limit'
138
+ | 'terminal_result_exceeds_ledger_depth'
139
+ | 'terminal_result_has_invalid_field_name'
140
+ | 'terminal_result_array_too_long'
141
+ | 'terminal_result_object_too_wide'
142
+ | 'terminal_result_not_json_serializable'
143
+ | 'terminal_result_rejected_by_convex';
144
+
145
+ export type ConvexLedgerPayloadIssue = {
146
+ reason:
147
+ | 'size_limit'
148
+ | 'depth_limit'
149
+ | 'invalid_field_name'
150
+ | 'array_too_long'
151
+ | 'object_too_wide'
152
+ | 'not_json_serializable';
153
+ bytes?: number;
125
154
  };
126
155
 
127
156
  function isPlainObject(value: unknown): value is Record<string, unknown> {
128
157
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
129
158
  }
130
159
 
160
+ function isConvexFieldName(value: string): boolean {
161
+ if (
162
+ value.length > CONVEX_LEDGER_FIELD_NAME_MAX_LENGTH ||
163
+ value.startsWith('$')
164
+ ) {
165
+ return false;
166
+ }
167
+ for (let index = 0; index < value.length; index += 1) {
168
+ const code = value.charCodeAt(index);
169
+ if (code < 32 || code >= 127) return false;
170
+ }
171
+ return true;
172
+ }
173
+
174
+ /**
175
+ * Validate the part of Convex's value contract that can permanently poison a
176
+ * durable run-ledger append. The walk is iterative and stops at the depth
177
+ * boundary, so adversarial nesting cannot overflow the JS stack while being
178
+ * classified. It intentionally returns no path or customer field name.
179
+ */
180
+ export function inspectConvexLedgerPayload(
181
+ value: unknown,
182
+ ): ConvexLedgerPayloadIssue | null {
183
+ const stack: Array<{ value: unknown; depth: number }> = [
184
+ {
185
+ value,
186
+ depth: value !== null && typeof value === 'object' ? 1 : 0,
187
+ },
188
+ ];
189
+
190
+ while (stack.length > 0) {
191
+ const current = stack.pop()!;
192
+ if (current.depth > LEDGER_TERMINAL_RESULT_MAX_DEPTH) {
193
+ return { reason: 'depth_limit' };
194
+ }
195
+ if (Array.isArray(current.value)) {
196
+ if (current.value.length > CONVEX_LEDGER_ARRAY_MAX_ITEMS) {
197
+ return { reason: 'array_too_long' };
198
+ }
199
+ for (const item of current.value) {
200
+ stack.push({
201
+ value: item,
202
+ depth:
203
+ item !== null && typeof item === 'object'
204
+ ? current.depth + 1
205
+ : current.depth,
206
+ });
207
+ }
208
+ continue;
209
+ }
210
+ if (!current.value || typeof current.value !== 'object') continue;
211
+
212
+ const entries = Object.entries(current.value as Record<string, unknown>);
213
+ if (entries.length > CONVEX_LEDGER_OBJECT_MAX_FIELDS) {
214
+ return { reason: 'object_too_wide' };
215
+ }
216
+ for (const [key, entry] of entries) {
217
+ if (!isConvexFieldName(key)) {
218
+ return { reason: 'invalid_field_name' };
219
+ }
220
+ stack.push({
221
+ value: entry,
222
+ depth:
223
+ entry !== null && typeof entry === 'object'
224
+ ? current.depth + 1
225
+ : current.depth,
226
+ });
227
+ }
228
+ }
229
+
230
+ try {
231
+ const bytes = jsonByteLength(value);
232
+ return bytes > LEDGER_TERMINAL_RESULT_MAX_BYTES
233
+ ? { reason: 'size_limit', bytes }
234
+ : null;
235
+ } catch {
236
+ return { reason: 'not_json_serializable' };
237
+ }
238
+ }
239
+
240
+ export function isLedgerTerminalResultRef(
241
+ value: unknown,
242
+ ): value is LedgerTerminalResultRef {
243
+ return (
244
+ isPlainObject(value) &&
245
+ value.__kind === 'deepline.ledger_terminal_result_ref.v1' &&
246
+ value.store === 'scheduler_postgres' &&
247
+ value.key === 'terminal_result_json'
248
+ );
249
+ }
250
+
251
+ export function stripReplayOnlyTerminalResult(value: unknown): unknown {
252
+ if (!isPlainObject(value) || isLedgerTerminalResultRef(value)) return value;
253
+ const stripped: Record<string, unknown> = {};
254
+ for (const [key, entry] of Object.entries(value)) {
255
+ if (
256
+ (LEDGER_STRIPPED_TERMINAL_RESULT_KEYS as readonly string[]).includes(key)
257
+ ) {
258
+ continue;
259
+ }
260
+ stripped[key] = entry;
261
+ }
262
+ return stripped;
263
+ }
264
+
265
+ function refReasonForIssue(
266
+ issue: ConvexLedgerPayloadIssue['reason'],
267
+ ): LedgerTerminalResultRefReason {
268
+ switch (issue) {
269
+ case 'size_limit':
270
+ return 'terminal_result_exceeds_ledger_limit';
271
+ case 'depth_limit':
272
+ return 'terminal_result_exceeds_ledger_depth';
273
+ case 'invalid_field_name':
274
+ return 'terminal_result_has_invalid_field_name';
275
+ case 'array_too_long':
276
+ return 'terminal_result_array_too_long';
277
+ case 'object_too_wide':
278
+ return 'terminal_result_object_too_wide';
279
+ case 'not_json_serializable':
280
+ return 'terminal_result_not_json_serializable';
281
+ }
282
+ }
283
+
284
+ export function ledgerTerminalResultRefForValue(
285
+ value: unknown,
286
+ reason: LedgerTerminalResultRefReason,
287
+ ): LedgerTerminalResultRef {
288
+ let bytes = 0;
289
+ try {
290
+ bytes = jsonByteLength(value);
291
+ } catch {
292
+ // The bounded reason is the useful diagnostic. Never serialize the
293
+ // customer payload again merely to populate reference metadata.
294
+ }
295
+ return {
296
+ __kind: 'deepline.ledger_terminal_result_ref.v1',
297
+ store: 'scheduler_postgres',
298
+ key: 'terminal_result_json',
299
+ bytes,
300
+ reason,
301
+ };
302
+ }
303
+
304
+ /** Optional derived summaries must never block the terminal lifecycle event. */
305
+ export function ledgerSummaryForLedger(value: unknown): unknown {
306
+ if (value === undefined || value === null) return value;
307
+ return inspectConvexLedgerPayload(value) ? undefined : value;
308
+ }
309
+
131
310
  /**
132
311
  * Shape a terminal run result for the Convex run ledger. Control-plane only:
133
312
  *
@@ -138,40 +317,23 @@ function isPlainObject(value: unknown): value is Record<string, unknown> {
138
317
  * the durable scheduler copy, so the ledger event stays small and the
139
318
  * Convex append cannot wedge on an oversized/over-nested document.
140
319
  *
141
- * The full result (including its checkpoint) remains durable in scheduler
142
- * Postgres regardless; this only governs what the ledger embeds.
320
+ * Any result accepted by the existing terminal persistence contract remains
321
+ * durable in scheduler Postgres; this only governs what the ledger embeds.
143
322
  */
144
323
  export function terminalRunResultForLedger(value: unknown): unknown {
145
324
  if (value === undefined || value === null) {
146
325
  return value;
147
326
  }
148
- let candidate = value;
149
- if (isPlainObject(value)) {
150
- const stripped: Record<string, unknown> = {};
151
- for (const [key, entry] of Object.entries(value)) {
152
- if (
153
- (LEDGER_STRIPPED_TERMINAL_RESULT_KEYS as readonly string[]).includes(
154
- key,
155
- )
156
- ) {
157
- continue;
158
- }
159
- stripped[key] = entry;
160
- }
161
- candidate = stripped;
162
- }
163
- const bytes = jsonByteLength(candidate);
164
- if (bytes <= LEDGER_TERMINAL_RESULT_MAX_BYTES) {
327
+ if (isLedgerTerminalResultRef(value)) return value;
328
+ const candidate = stripReplayOnlyTerminalResult(value);
329
+ const issue = inspectConvexLedgerPayload(candidate);
330
+ if (!issue) {
165
331
  return candidate;
166
332
  }
167
- const ref: LedgerTerminalResultRef = {
168
- __kind: 'deepline.ledger_terminal_result_ref.v1',
169
- store: 'scheduler_postgres',
170
- key: 'terminal_result_json',
171
- bytes,
172
- reason: 'terminal_result_exceeds_ledger_limit',
173
- };
174
- return ref;
333
+ return ledgerTerminalResultRefForValue(
334
+ candidate,
335
+ refReasonForIssue(issue.reason),
336
+ );
175
337
  }
176
338
 
177
339
  export function assertCustomerOutputValueWithinLimit(input: {
@@ -107,7 +107,7 @@ export const PLAY_LATENCY_SUMMARY_COLUMNS: PlayLatencyPhaseDefinition[] = [
107
107
  header: 'route_child',
108
108
  phase: 'server.start_route_resolve_child_manifests',
109
109
  source: 'server',
110
- description: 'Start route child play manifest resolution for workers_edge.',
110
+ description: 'Start route child play manifest resolution.',
111
111
  },
112
112
  {
113
113
  header: 'route_active',