@inflexa-ai/harness 0.42.2 → 0.43.0

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 (199) hide show
  1. package/README.md +2 -2
  2. package/dist/agents/sandbox/shared.d.ts +1 -6
  3. package/dist/agents/sandbox/shared.js +0 -15
  4. package/dist/app/chat-turn.js +13 -1
  5. package/dist/config/environment-stores.d.ts +4 -2
  6. package/dist/contracts/chat-events.d.ts +9 -1
  7. package/dist/contracts/chat-frame.d.ts +3 -3
  8. package/dist/contracts/chat-frame.js +8 -3
  9. package/dist/contracts/chat-parts.d.ts +4 -1
  10. package/dist/contracts/data-profile.d.ts +4 -6
  11. package/dist/contracts/index.d.ts +1 -1
  12. package/dist/contracts/report-blocks.d.ts +1364 -75
  13. package/dist/contracts/report-blocks.js +221 -29
  14. package/dist/contracts/report-reference.js +1 -1
  15. package/dist/contracts/schemas/chat-events.d.ts +13 -0
  16. package/dist/contracts/schemas/chat-events.js +5 -0
  17. package/dist/contracts/schemas/chat-parts.d.ts +2 -2
  18. package/dist/contracts/schemas/index.d.ts +1 -1
  19. package/dist/contracts/schemas/index.js +1 -1
  20. package/dist/execution/input-signature.d.ts +7 -13
  21. package/dist/execution/input-signature.js +0 -0
  22. package/dist/execution/run-canceler.d.ts +3 -2
  23. package/dist/execution/run-canceler.js +3 -2
  24. package/dist/execution/run-event-stream.d.ts +16 -2
  25. package/dist/execution/run-event-stream.js +54 -3
  26. package/dist/index.d.ts +1 -8
  27. package/dist/index.js +5 -16
  28. package/dist/input-scan/enrich.d.ts +0 -2
  29. package/dist/input-scan/enrich.js +0 -1
  30. package/dist/lib/metrics.js +6 -7
  31. package/dist/lib/otel-spans.d.ts +4 -9
  32. package/dist/lib/otel-spans.js +3 -8
  33. package/dist/loop/run-agent.d.ts +4 -2
  34. package/dist/loop/run-agent.js +38 -23
  35. package/dist/memory/thread-history.d.ts +1 -1
  36. package/dist/prompts/report-session.d.ts +1 -1
  37. package/dist/prompts/report-session.js +17 -0
  38. package/dist/provenance/exec-frame.d.ts +1 -1
  39. package/dist/report-model/authoring-grammar.d.ts +416 -17
  40. package/dist/report-model/authoring-grammar.js +25 -4
  41. package/dist/report-model/block-walk.d.ts +20 -4
  42. package/dist/report-model/block-walk.js +64 -7
  43. package/dist/report-model/draft-finish.d.ts +6 -2
  44. package/dist/report-model/draft-finish.js +6 -1
  45. package/dist/report-model/production-resolver.d.ts +8 -0
  46. package/dist/report-model/production-resolver.js +1 -1
  47. package/dist/report-model/validate.d.ts +20 -10
  48. package/dist/report-model/validate.js +29 -13
  49. package/dist/report-render/chart-export.d.ts +52 -0
  50. package/dist/report-render/chart-export.js +192 -0
  51. package/dist/report-render/chart-presets.d.ts +46 -47
  52. package/dist/report-render/chart-presets.js +31 -101
  53. package/dist/report-render/chart-renderers.d.ts +163 -0
  54. package/dist/report-render/chart-renderers.js +1055 -0
  55. package/dist/report-render/chart-toolbox.d.ts +124 -0
  56. package/dist/report-render/chart-toolbox.js +595 -0
  57. package/dist/report-render/chart.d.ts +60 -27
  58. package/dist/report-render/chart.js +2323 -524
  59. package/dist/report-render/design.d.ts +476 -16
  60. package/dist/report-render/design.js +390 -56
  61. package/dist/report-render/figures/common.d.ts +321 -0
  62. package/dist/report-render/figures/common.js +759 -0
  63. package/dist/report-render/figures/dendrogram.d.ts +36 -0
  64. package/dist/report-render/figures/dendrogram.js +130 -0
  65. package/dist/report-render/figures/dense.d.ts +111 -0
  66. package/dist/report-render/figures/dense.js +204 -0
  67. package/dist/report-render/figures/dotplot.d.ts +28 -0
  68. package/dist/report-render/figures/dotplot.js +234 -0
  69. package/dist/report-render/figures/embedding.d.ts +43 -0
  70. package/dist/report-render/figures/embedding.js +360 -0
  71. package/dist/report-render/figures/equal-units.d.ts +101 -0
  72. package/dist/report-render/figures/equal-units.js +215 -0
  73. package/dist/report-render/figures/forest.d.ts +20 -0
  74. package/dist/report-render/figures/forest.js +398 -0
  75. package/dist/report-render/figures/gsea.d.ts +30 -0
  76. package/dist/report-render/figures/gsea.js +391 -0
  77. package/dist/report-render/figures/heatmap.d.ts +40 -0
  78. package/dist/report-render/figures/heatmap.js +395 -0
  79. package/dist/report-render/figures/index.d.ts +135 -0
  80. package/dist/report-render/figures/index.js +100 -0
  81. package/dist/report-render/figures/km.d.ts +16 -0
  82. package/dist/report-render/figures/km.js +406 -0
  83. package/dist/report-render/figures/label-room.d.ts +130 -0
  84. package/dist/report-render/figures/label-room.js +341 -0
  85. package/dist/report-render/figures/locuszoom.d.ts +50 -0
  86. package/dist/report-render/figures/locuszoom.js +675 -0
  87. package/dist/report-render/figures/lollipop.d.ts +16 -0
  88. package/dist/report-render/figures/lollipop.js +247 -0
  89. package/dist/report-render/figures/ma.d.ts +20 -0
  90. package/dist/report-render/figures/ma.js +114 -0
  91. package/dist/report-render/figures/manhattan.d.ts +60 -0
  92. package/dist/report-render/figures/manhattan.js +343 -0
  93. package/dist/report-render/figures/oncoprint.d.ts +41 -0
  94. package/dist/report-render/figures/oncoprint.js +420 -0
  95. package/dist/report-render/figures/pca.d.ts +37 -0
  96. package/dist/report-render/figures/pca.js +241 -0
  97. package/dist/report-render/figures/qq.d.ts +30 -0
  98. package/dist/report-render/figures/qq.js +182 -0
  99. package/dist/report-render/figures/roc.d.ts +17 -0
  100. package/dist/report-render/figures/roc.js +116 -0
  101. package/dist/report-render/figures/sankey.d.ts +48 -0
  102. package/dist/report-render/figures/sankey.js +353 -0
  103. package/dist/report-render/figures/upset.d.ts +60 -0
  104. package/dist/report-render/figures/upset.js +316 -0
  105. package/dist/report-render/figures/volcano.d.ts +25 -0
  106. package/dist/report-render/figures/volcano.js +166 -0
  107. package/dist/report-render/hybrid-svg.d.ts +75 -0
  108. package/dist/report-render/hybrid-svg.js +504 -0
  109. package/dist/report-render/number-format.d.ts +19 -0
  110. package/dist/report-render/number-format.js +25 -1
  111. package/dist/report-render/page.d.ts +41 -4
  112. package/dist/report-render/page.js +247 -12
  113. package/dist/report-render/render.d.ts +13 -4
  114. package/dist/report-render/render.js +37 -6
  115. package/dist/report-render/types.d.ts +23 -2
  116. package/dist/report-render/value-bridge.d.ts +38 -3
  117. package/dist/report-render/value-bridge.js +137 -6
  118. package/dist/report-render/views/chart-view.d.ts +42 -6
  119. package/dist/report-render/views/chart-view.js +70 -9
  120. package/dist/report-render/views/page-view.js +9 -10
  121. package/dist/runtime/assemble.js +2 -2
  122. package/dist/sandbox/client.d.ts +23 -32
  123. package/dist/sandbox/client.js +3 -11
  124. package/dist/sandbox/create-sandbox.d.ts +9 -24
  125. package/dist/sandbox/create-sandbox.js +15 -30
  126. package/dist/sandbox/docker-client.d.ts +12 -22
  127. package/dist/sandbox/docker-client.js +29 -43
  128. package/dist/sandbox/exec.d.ts +58 -0
  129. package/dist/sandbox/exec.js +197 -0
  130. package/dist/sandbox/identity.d.ts +5 -5
  131. package/dist/sandbox/identity.js +7 -10
  132. package/dist/sandbox/k8s-client.d.ts +4 -10
  133. package/dist/sandbox/k8s-client.js +5 -12
  134. package/dist/sandbox/liveness.d.ts +5 -12
  135. package/dist/sandbox/liveness.js +5 -12
  136. package/dist/sandbox/notification-sweep.d.ts +4 -7
  137. package/dist/sandbox/notification-sweep.js +4 -7
  138. package/dist/sandbox/reaper.d.ts +3 -3
  139. package/dist/sandbox/reaper.js +3 -3
  140. package/dist/sandbox/sandbox-error.d.ts +10 -11
  141. package/dist/sandbox/sandbox-error.js +10 -11
  142. package/dist/sandbox/sandbox-step-translate.d.ts +1 -1
  143. package/dist/sandbox/sandbox-step-translate.js +1 -1
  144. package/dist/sandbox/types.d.ts +31 -99
  145. package/dist/sandbox/types.js +17 -84
  146. package/dist/state/active-sandboxes.d.ts +7 -32
  147. package/dist/state/active-sandboxes.js +11 -46
  148. package/dist/state/index.d.ts +1 -2
  149. package/dist/state/index.js +1 -1
  150. package/dist/state/migrations/20261005120000_drop_the_active_exec_tracking.d.ts +7 -0
  151. package/dist/state/migrations/20261005120000_drop_the_active_exec_tracking.js +12 -0
  152. package/dist/state/migrations/index.js +2 -0
  153. package/dist/state/schema.d.ts +1 -5
  154. package/dist/state/schema.js +1 -6
  155. package/dist/state/step-executions.js +1 -2
  156. package/dist/tasks/data-profile.js +7 -20
  157. package/dist/tasks/derive-table-exec.d.ts +4 -14
  158. package/dist/tasks/derive-table-exec.js +9 -24
  159. package/dist/tasks/extract-values.d.ts +2 -2
  160. package/dist/tasks/extract-values.js +4 -7
  161. package/dist/tools/define-tool.d.ts +56 -13
  162. package/dist/tools/define-tool.js +28 -1
  163. package/dist/tools/execute-analysis.js +3 -3
  164. package/dist/tools/report-session/derive-table.d.ts +8 -9
  165. package/dist/tools/report-session/derive-table.js +3 -4
  166. package/dist/tools/report-session/preview-report.js +4 -49
  167. package/dist/tools/sandbox/list-available-packages.d.ts +1 -1
  168. package/dist/tools/sandbox/list-available-packages.js +5 -4
  169. package/dist/tools/workspace/edit-file.d.ts +5 -4
  170. package/dist/tools/workspace/edit-file.js +10 -13
  171. package/dist/tools/workspace/execute-command.d.ts +27 -42
  172. package/dist/tools/workspace/execute-command.js +42 -38
  173. package/dist/tools/workspace/index.d.ts +5 -6
  174. package/dist/tools/workspace/index.js +5 -6
  175. package/dist/tools/workspace/mutator.d.ts +43 -8
  176. package/dist/tools/workspace/mutator.js +45 -34
  177. package/dist/tools/workspace/run-exec.d.ts +3 -12
  178. package/dist/tools/workspace/run-exec.js +7 -24
  179. package/dist/tools/workspace/scan-inputs.d.ts +0 -3
  180. package/dist/tools/workspace/scan-inputs.js +0 -1
  181. package/dist/tools/workspace/write-file.d.ts +12 -3
  182. package/dist/tools/workspace/write-file.js +17 -13
  183. package/dist/workflows/sandbox-step.d.ts +7 -11
  184. package/dist/workflows/sandbox-step.js +24 -27
  185. package/package.json +3 -1
  186. package/dist/sandbox/await-exec.d.ts +0 -143
  187. package/dist/sandbox/await-exec.js +0 -417
  188. package/dist/sandbox/deliver-exec-event.d.ts +0 -25
  189. package/dist/sandbox/deliver-exec-event.js +0 -29
  190. package/dist/sandbox/digest.d.ts +0 -14
  191. package/dist/sandbox/digest.js +0 -17
  192. package/dist/sandbox/exec-id.d.ts +0 -12
  193. package/dist/sandbox/exec-id.js +0 -20
  194. package/dist/sandbox/hmac.d.ts +0 -62
  195. package/dist/sandbox/hmac.js +0 -72
  196. package/dist/sandbox/submit-exec.d.ts +0 -38
  197. package/dist/sandbox/submit-exec.js +0 -80
  198. package/dist/sandbox/watchdog.d.ts +0 -71
  199. package/dist/sandbox/watchdog.js +0 -161
@@ -1,45 +1,13 @@
1
1
  /**
2
2
  * Sandbox-client types — the wire/persistence shapes that cross the
3
- * submit/recv protocol (see the harness-sandbox-exec spec) and the active-sandbox registry.
3
+ * submit/poll protocol (see the harness-sandbox-exec spec) and the active-sandbox registry.
4
4
  *
5
- * `SandboxRef` is the in-memory handle the harness uses to talk to a live
6
- * sandbox; it carries the per-sandbox `callbackSecret` (see the harness-sandbox-exec spec). The
7
- * persistable subset is `PersistedSandboxRef` (from `harness/state/schema.ts`)
8
- * — that one OMITS the secret, which lives only in the cached
9
- * `createSandbox` DBOS step output.
5
+ * `SandboxRef` is the handle the harness uses to talk to a live sandbox. The
6
+ * active-sandbox registry persists the same shape (`PersistedSandboxRef`, from
7
+ * `harness/state/schema.ts`).
10
8
  */
11
9
  import { z } from "zod";
12
- import { PersistedSandboxRefSchema } from "../state/schema.js";
13
10
  export const SandboxBackend = z.enum(["docker", "k8s"]);
14
- /**
15
- * How a command's progress events and terminal result reach the host. Chosen by
16
- * the embedder at its composition root and carried into the container as
17
- * `SANDBOX_TRANSPORT`; backend-independent. The OSS default is `poll`.
18
- *
19
- * - `poll`: the host polls `GET /exec/{execId}?since={cursor}`; the sandbox
20
- * never dials out and needs no egress.
21
- * - `callback`: the sandbox POSTs signed event/completion callbacks; the
22
- * embedder runs an ingress. `GET /exec/{execId}` stays the recovery backstop.
23
- */
24
- export const SandboxTransportSchema = z.enum(["poll", "callback"]);
25
- export const SandboxRefSchema = PersistedSandboxRefSchema.extend({
26
- /**
27
- * 32-byte high-entropy bytes, base64-encoded. Minted once at
28
- * `createSandbox` and handed to the sandbox container via
29
- * `SANDBOX_CALLBACK_SECRET`. Never persisted outside the DBOS
30
- * step-output cache.
31
- */
32
- callbackSecret: z.string(),
33
- });
34
- /** Strip the secret before persisting to the active-sandbox registry. */
35
- export function toPersistedRef(ref) {
36
- return {
37
- sandboxId: ref.sandboxId,
38
- host: ref.host,
39
- port: ref.port,
40
- backend: ref.backend,
41
- };
42
- }
43
11
  /**
44
12
  * One tracked file operation in the sandbox-server provenance frame.
45
13
  * Mirrors Go's `ProvenanceEntry` (`images/sandbox-base/server/provenance.go`):
@@ -50,8 +18,8 @@ export const ProvenanceFrameEntrySchema = z.object({
50
18
  layers: z.array(z.string()).default([]),
51
19
  });
52
20
  /**
53
- * Runtime file-I/O frame sandbox-server attaches to the `/complete`
54
- * callback. Mirrors Go's `provenancePayload` — every field is
21
+ * Runtime file-I/O frame sandbox-server attaches to the terminal result.
22
+ * Mirrors Go's `provenancePayload` — every field is
55
23
  * `omitempty` on the wire, so each arm defaults so a completion that
56
24
  * omits the frame (or any arm) still parses.
57
25
  */
@@ -86,9 +54,9 @@ export const ExecUsageSchema = z
86
54
  .optional()
87
55
  .catch(undefined);
88
56
  /**
89
- * Final outcome of a single exec, returned by `awaitExec`. Mirrors the
90
- * sandbox-server completion payload plus a discriminant for synthetic
91
- * (watchdog-emitted) failures.
57
+ * Final outcome of a single exec, returned by `SandboxClient.exec`. Mirrors
58
+ * the sandbox-server completion payload plus a discriminant for a synthetic
59
+ * failure: the machine died under the exec.
92
60
  */
93
61
  export const ExecResultSchema = z.object({
94
62
  execId: z.string(),
@@ -104,74 +72,45 @@ export const ExecResultSchema = z.object({
104
72
  * a capped stream and an empty one are indistinguishable downstream.
105
73
  *
106
74
  * Optional because a sandbox image that pre-dates the cap omits both, and
107
- * because the watchdog's synthetic failures carry neither.
75
+ * because a synthetic failure carries neither.
108
76
  */
109
77
  stdoutTruncated: z.boolean().optional(),
110
78
  stderrTruncated: z.boolean().optional(),
111
79
  stdoutTotalBytes: z.number().int().nonnegative().optional(),
112
80
  stderrTotalBytes: z.number().int().nonnegative().optional(),
113
- /** Set when the watchdog synthesises a completion for a dead sandbox. */
81
+ /** Set when the liveness probe found the machine dead under the exec. */
114
82
  syntheticFailure: z
115
83
  .object({
116
84
  reason: z.string(),
117
85
  })
118
86
  .optional(),
119
- /**
120
- * Runtime file-I/O frame from sandbox-server. Optional so synthetic
121
- * watchdog failures and pre-change cached recv messages parse; rides
122
- * the recv payload into the durable DBOS step output.
123
- */
87
+ /** Runtime file-I/O frame from sandbox-server. Absent from a synthetic failure. */
124
88
  provenance: ProvenanceFrameSchema.optional(),
125
89
  /**
126
90
  * Kernel accounting of the exec, for the sandbox-sizing histograms. Absent
127
- * from a synthetic watchdog failure, from a sandbox image that predates the
91
+ * from a synthetic failure, from a sandbox image that predates the
128
92
  * frame, and from any exec whose command never spawned.
129
93
  */
130
94
  usage: ExecUsageSchema,
131
95
  });
132
- /**
133
- * Per-message envelope on the per-exec DBOS topic. Real callbacks carry
134
- * a non-null `signature` and `timestamp`; the in-process watchdog uses a
135
- * `null` signature + a `synthetic-failure` payload (see `await-exec.ts`).
136
- *
137
- * `payloadDigest` is the hex SHA-256 of the exact bytes sandbox-server POSTed.
138
- * The HMAC signs that digest rather than the body itself, so the digest is all
139
- * verification needs — and carrying it instead of the bytes keeps the message
140
- * from holding a second copy of a payload that can be arbitrarily large.
141
- * Re-serializing the parsed payload would not do: Go's `encoding/json`
142
- * HTML-escapes `<`, `>`, `&` by default, so a JS re-serialization diverges for
143
- * any output containing those characters (common in bioinformatics: FASTA
144
- * headers, shell stderr, command pipelines).
145
- *
146
- * `payloadRaw` is the superseded form, kept optional so messages already in
147
- * flight or persisted still verify.
148
- */
149
- export const ExecEventMessageSchema = z.object({
150
- payload: z.unknown(),
151
- payloadDigest: z.string().optional(),
152
- payloadRaw: z.string().optional(),
153
- signature: z.string().nullable(),
154
- timestamp: z.number().int().nullable(),
155
- });
156
96
  /**
157
97
  * One buffered progress event in a poll response: the sandbox's monotonic
158
98
  * per-exec sequence number (the poll cursor) plus the event payload the host
159
- * forwards via `emit` — the same payload a callback-mode event POST carries.
99
+ * forwards via `emit`.
160
100
  */
161
101
  export const PollEventSchema = z.object({
162
102
  seq: z.number().int(),
163
103
  payload: z.unknown(),
164
104
  });
165
105
  /**
166
- * Body of `GET /exec/{execId}?since={cursor}` in poll mode. Mirrors Go's
106
+ * Body of `GET /exec/{execId}?since={cursor}`. Mirrors Go's
167
107
  * `pollResponseBody`: the events newer than the caller's cursor, the new
168
108
  * high-water `cursor`, a `truncated` marker set once the ring shed an event,
169
109
  * and — once the exec is terminal — the completion `result` (with its
170
- * provenance frame). The whole body is HMAC-signed, verified exactly as a
171
- * pushed completion is.
110
+ * provenance frame).
172
111
  */
173
112
  export const PollResponseSchema = z.object({
174
- status: z.string(),
113
+ status: z.enum(["running", "completed", "failed"]),
175
114
  events: z.array(PollEventSchema).default([]),
176
115
  cursor: z.number().int(),
177
116
  /**
@@ -182,9 +121,3 @@ export const PollResponseSchema = z.object({
182
121
  truncated: z.boolean().default(false),
183
122
  result: ExecResultSchema.optional(),
184
123
  });
185
- export function isDoneMarker(value) {
186
- return (typeof value === "object" && value !== null && value.done === true && typeof value.result === "object");
187
- }
188
- export function isSyntheticFailure(value) {
189
- return isDoneMarker(value) && value.kind === "synthetic-failure";
190
- }
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * Active-sandbox registry (CONTEXT.md) — the projection over
3
3
  * `cortex_step_executions` rows with a non-null `sandbox_ref` and a running
4
- * status. Owns the `sandbox_ref` + `exec_id` columns: written by
5
- * `sandbox/create-sandbox.ts` on mint, cleared on teardown, enumerated by
6
- * `sandbox/watchdog.ts` for liveness sweeps.
4
+ * status. Owns the `sandbox_ref` column: written by
5
+ * `sandbox/create-sandbox.ts` on mint, cleared on teardown, reconciled by
6
+ * `sandbox/reaper.ts` after it deletes a machine.
7
7
  */
8
8
  import type { ResultAsync } from "neverthrow";
9
9
  import { type DbError } from "../lib/db-result.js";
@@ -12,47 +12,22 @@ import type { PersistedSandboxRef } from "./schema.js";
12
12
  /**
13
13
  * Record the live sandbox handle on a step row. Called inside the
14
14
  * `createSandbox` DBOS step after the backend has confirmed the sandbox
15
- * is up. The `callbackSecret` is deliberately not part of the persisted
16
- * shape (see the harness-sandbox-exec spec) — it lives only in the cached step output.
15
+ * is up.
17
16
  */
18
- export declare function setSandboxRef(pool: Querier, runId: string, stepId: string, sandboxRef: PersistedSandboxRef, execId: string | null): ResultAsync<void, DbError>;
19
- /**
20
- * Tag the active-sandbox row with the exec currently in flight. Called from
21
- * `run-exec.ts` right before `awaitExec` so the liveness watchdog can target
22
- * the hung exec when the sandbox dies mid-command. Targets the same
23
- * `(run_id, step_id)` row `setSandboxRef` writes and `queryActiveSandboxes`
24
- * enumerates. Overwritten by the next exec; cleared on teardown.
25
- */
26
- export declare function setActiveExecId(pool: Querier, runId: string, stepId: string, execId: string): ResultAsync<void, DbError>;
17
+ export declare function setSandboxRef(pool: Querier, runId: string, stepId: string, sandboxRef: PersistedSandboxRef): ResultAsync<void, DbError>;
27
18
  /**
28
19
  * Clear the sandbox handle. Called inside the `teardown` DBOS step. Safe
29
20
  * to call when no sandbox was ever recorded — the UPDATE simply targets
30
21
  * zero rows.
31
22
  */
32
23
  export declare function clearSandboxRef(pool: Querier, runId: string, stepId: string): ResultAsync<void, DbError>;
33
- /**
34
- * Enumerate the active-sandbox registry — every running step with a live
35
- * sandbox attached. The liveness watchdog consumes this, shards the
36
- * result, and fans out per-shard check workflows.
37
- *
38
- * Returns the raw row tuple (no Zod parse) so the watchdog can shard
39
- * without paying for parse work it doesn't need.
40
- */
41
- export interface ActiveSandboxRow {
42
- runId: string;
43
- stepId: string;
44
- analysisId: string;
45
- sandboxRef: PersistedSandboxRef;
46
- execId: string | null;
47
- }
48
24
  /**
49
25
  * Reconcile a step row after the reaper deletes its sandbox machine (ADR
50
- * 0016). Always clears `sandbox_ref`/`exec_id` (drops the row from the
51
- * active-sandbox registry, ending the watchdog churn); a row still stuck at
26
+ * 0016). Always clears `sandbox_ref` (drops the row from the
27
+ * active-sandbox registry); a row still stuck at
52
28
  * `status='running'` — a cancellation that never ran its `mark-*` step — is
53
29
  * also flipped to the owning workflow's terminal status so a terminal workflow
54
30
  * never leaves a perpetually-"running" step behind. Returns true if a row
55
31
  * matched. Safe when no row exists (Class A pure orphan): matches zero rows.
56
32
  */
57
33
  export declare function reconcileReapedSandbox(pool: Querier, sandboxId: string, terminalStatus: "canceled" | "failed" | "completed"): ResultAsync<boolean, DbError>;
58
- export declare function queryActiveSandboxes(pool: Querier): ResultAsync<ActiveSandboxRow[], DbError>;
@@ -1,41 +1,23 @@
1
1
  /**
2
2
  * Active-sandbox registry (CONTEXT.md) — the projection over
3
3
  * `cortex_step_executions` rows with a non-null `sandbox_ref` and a running
4
- * status. Owns the `sandbox_ref` + `exec_id` columns: written by
5
- * `sandbox/create-sandbox.ts` on mint, cleared on teardown, enumerated by
6
- * `sandbox/watchdog.ts` for liveness sweeps.
4
+ * status. Owns the `sandbox_ref` column: written by
5
+ * `sandbox/create-sandbox.ts` on mint, cleared on teardown, reconciled by
6
+ * `sandbox/reaper.ts` after it deletes a machine.
7
7
  */
8
- import { tryMutation, tryQuery } from "../lib/db-result.js";
8
+ import { tryMutation } from "../lib/db-result.js";
9
9
  /**
10
10
  * Record the live sandbox handle on a step row. Called inside the
11
11
  * `createSandbox` DBOS step after the backend has confirmed the sandbox
12
- * is up. The `callbackSecret` is deliberately not part of the persisted
13
- * shape (see the harness-sandbox-exec spec) — it lives only in the cached step output.
12
+ * is up.
14
13
  */
15
- export function setSandboxRef(pool, runId, stepId, sandboxRef, execId) {
14
+ export function setSandboxRef(pool, runId, stepId, sandboxRef) {
16
15
  return tryMutation("activeSandboxes.setSandboxRef", async () => {
17
16
  await pool.query({
18
17
  text: `UPDATE cortex_step_executions
19
- SET sandbox_ref = $1::jsonb, exec_id = $2
20
- WHERE run_id = $3 AND step_id = $4`,
21
- values: [JSON.stringify(sandboxRef), execId, runId, stepId],
22
- });
23
- });
24
- }
25
- /**
26
- * Tag the active-sandbox row with the exec currently in flight. Called from
27
- * `run-exec.ts` right before `awaitExec` so the liveness watchdog can target
28
- * the hung exec when the sandbox dies mid-command. Targets the same
29
- * `(run_id, step_id)` row `setSandboxRef` writes and `queryActiveSandboxes`
30
- * enumerates. Overwritten by the next exec; cleared on teardown.
31
- */
32
- export function setActiveExecId(pool, runId, stepId, execId) {
33
- return tryMutation("activeSandboxes.setActiveExecId", async () => {
34
- await pool.query({
35
- text: `UPDATE cortex_step_executions
36
- SET exec_id = $1
18
+ SET sandbox_ref = $1::jsonb
37
19
  WHERE run_id = $2 AND step_id = $3`,
38
- values: [execId, runId, stepId],
20
+ values: [JSON.stringify(sandboxRef), runId, stepId],
39
21
  });
40
22
  });
41
23
  }
@@ -48,7 +30,7 @@ export function clearSandboxRef(pool, runId, stepId) {
48
30
  return tryMutation("activeSandboxes.clearSandboxRef", async () => {
49
31
  await pool.query({
50
32
  text: `UPDATE cortex_step_executions
51
- SET sandbox_ref = NULL, exec_id = NULL
33
+ SET sandbox_ref = NULL
52
34
  WHERE run_id = $1 AND step_id = $2`,
53
35
  values: [runId, stepId],
54
36
  });
@@ -56,8 +38,8 @@ export function clearSandboxRef(pool, runId, stepId) {
56
38
  }
57
39
  /**
58
40
  * Reconcile a step row after the reaper deletes its sandbox machine (ADR
59
- * 0016). Always clears `sandbox_ref`/`exec_id` (drops the row from the
60
- * active-sandbox registry, ending the watchdog churn); a row still stuck at
41
+ * 0016). Always clears `sandbox_ref` (drops the row from the
42
+ * active-sandbox registry); a row still stuck at
61
43
  * `status='running'` — a cancellation that never ran its `mark-*` step — is
62
44
  * also flipped to the owning workflow's terminal status so a terminal workflow
63
45
  * never leaves a perpetually-"running" step behind. Returns true if a row
@@ -73,7 +55,6 @@ export function reconcileReapedSandbox(pool, sandboxId, terminalStatus) {
73
55
  const result = await pool.query({
74
56
  text: `UPDATE cortex_step_executions
75
57
  SET sandbox_ref = NULL,
76
- exec_id = NULL,
77
58
  status = CASE WHEN status = 'running' THEN $2 ELSE status END,
78
59
  completed_at = CASE WHEN status = 'running' THEN $3 ELSE completed_at END
79
60
  WHERE sandbox_ref->>'sandboxId' = $1`,
@@ -82,19 +63,3 @@ export function reconcileReapedSandbox(pool, sandboxId, terminalStatus) {
82
63
  return (result.rowCount ?? 0) > 0;
83
64
  });
84
65
  }
85
- export function queryActiveSandboxes(pool) {
86
- return tryQuery("activeSandboxes.queryActiveSandboxes", async () => {
87
- const result = await pool.query({
88
- text: `SELECT run_id, step_id, analysis_id, sandbox_ref, exec_id
89
- FROM cortex_step_executions
90
- WHERE status = 'running' AND sandbox_ref IS NOT NULL`,
91
- });
92
- return result.rows.map((r) => ({
93
- runId: r.run_id,
94
- stepId: r.step_id,
95
- analysisId: r.analysis_id,
96
- sandboxRef: r.sandbox_ref,
97
- execId: r.exec_id ?? null,
98
- }));
99
- });
100
- }
@@ -16,8 +16,7 @@ setRunSynthesisOutcome, queryRun, queryActiveRun, queryNonTerminalRunsByAnalysis
16
16
  export type { InsertRunInput, RunPage, RunReservation } from "./runs.js";
17
17
  export { insertStepExecution, seedStepExecutions, sweepPendingStepExecutions, updateStepExecution, queryStepsByRun } from "./step-executions.js";
18
18
  export type { InsertStepExecutionInput, SeedStepExecutionRow, UpdateStepExecutionInput } from "./step-executions.js";
19
- export { setSandboxRef, setActiveExecId, clearSandboxRef, queryActiveSandboxes, reconcileReapedSandbox } from "./active-sandboxes.js";
20
- export type { ActiveSandboxRow } from "./active-sandboxes.js";
19
+ export { setSandboxRef, clearSandboxRef, reconcileReapedSandbox } from "./active-sandboxes.js";
21
20
  export { insertPlan, upsertPlan, loadPlan } from "./plans.js";
22
21
  export type { InsertPlanInput, UpsertPlanInput } from "./plans.js";
23
22
  export { tryStartDataProfile, tryRetryDataProfile, tryRerunDataProfile, completeDataProfile, failDataProfile, expireStaleDataProfile, reconcileOrphanedDataProfile, clearDataProfile, completeEmptyDataProfile, loadDataProfileStatus, loadSeedInputFileIds, recordDataProfileWorkflowId, } from "./data-profile.js";
@@ -12,7 +12,7 @@ export { upsertArtifact, upsertArtifacts, queryInputArtifacts, queryStepArtifact
12
12
  export { insertRun, reserveRunById, RunDedupCollisionError, RunIdentityCollisionError, updateRunStatus, markRunCanceledIfActive, promoteFailedToPartial, setRunMandate, // oss-core-managed-ok: run-mandate ledger (nullable; OSS leaves null)
13
13
  setRunSynthesisOutcome, queryRun, queryActiveRun, queryNonTerminalRunsByAnalysis, queryRunsForInspection, queryRunsByAnalysis, queryRunsByThread, } from "./runs.js";
14
14
  export { insertStepExecution, seedStepExecutions, sweepPendingStepExecutions, updateStepExecution, queryStepsByRun } from "./step-executions.js";
15
- export { setSandboxRef, setActiveExecId, clearSandboxRef, queryActiveSandboxes, reconcileReapedSandbox } from "./active-sandboxes.js";
15
+ export { setSandboxRef, clearSandboxRef, reconcileReapedSandbox } from "./active-sandboxes.js";
16
16
  export { insertPlan, upsertPlan, loadPlan } from "./plans.js";
17
17
  export { tryStartDataProfile, tryRetryDataProfile, tryRerunDataProfile, completeDataProfile, failDataProfile, expireStaleDataProfile, reconcileOrphanedDataProfile, clearDataProfile, completeEmptyDataProfile, loadDataProfileStatus, loadSeedInputFileIds, recordDataProfileWorkflowId, } from "./data-profile.js";
18
18
  export { queryRunCountsByAnalyses, queryThreadCountsByAnalyses, queryDataProfileStatusByAnalyses } from "./analyses-metrics.js";
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Drop the in-flight exec id of a step row, and the partial index of the rows
3
+ * that hold a sandbox. The exec id is the function id of its DBOS step, thus
4
+ * nothing outside the step reads it, and no query reads the rows by status.
5
+ */
6
+ import type { Migration } from "kysely/migration";
7
+ export declare const dropActiveExecTracking: Migration;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Drop the in-flight exec id of a step row, and the partial index of the rows
3
+ * that hold a sandbox. The exec id is the function id of its DBOS step, thus
4
+ * nothing outside the step reads it, and no query reads the rows by status.
5
+ */
6
+ import { sql } from "kysely";
7
+ export const dropActiveExecTracking = {
8
+ async up(db) {
9
+ await sql `ALTER TABLE cortex_step_executions DROP COLUMN IF EXISTS exec_id`.execute(db);
10
+ await sql `DROP INDEX IF EXISTS idx_cortex_step_exec_active_sandbox`.execute(db);
11
+ },
12
+ };
@@ -7,9 +7,11 @@
7
7
  */
8
8
  import { baseline } from "./20260927120000_baseline.js";
9
9
  import { threadTitleSetByUser } from "./20260927180000_thread_title_set_by_user.js";
10
+ import { dropActiveExecTracking } from "./20261005120000_drop_the_active_exec_tracking.js";
10
11
  export function cortexMigrations(logger) {
11
12
  return {
12
13
  "20260927120000_baseline": baseline(logger),
13
14
  "20260927180000_thread_title_set_by_user": threadTitleSetByUser,
15
+ "20261005120000_drop_the_active_exec_tracking": dropActiveExecTracking,
14
16
  };
15
17
  }
@@ -102,10 +102,7 @@ export declare const CortexRunRowSchema: z.ZodObject<{
102
102
  export type CortexRunRow = z.infer<typeof CortexRunRowSchema>;
103
103
  /**
104
104
  * Persistable sandbox handle — what the active-sandbox registry stores on
105
- * `cortex_step_executions.sandbox_ref`. Excludes the per-sandbox
106
- * `callbackSecret`, which lives only in the DBOS step-output cache (ADR
107
- * 0007). The harness reconstructs the full in-memory `SandboxRef` by
108
- * reading the secret from the cached `createSandbox` step output.
105
+ * `cortex_step_executions.sandbox_ref`.
109
106
  */
110
107
  export declare const PersistedSandboxRefSchema: z.ZodObject<{
111
108
  sandboxId: z.ZodString;
@@ -150,7 +147,6 @@ export declare const StepExecutionRowSchema: z.ZodObject<{
150
147
  k8s: "k8s";
151
148
  }>;
152
149
  }, z.core.$strip>>>;
153
- execId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
154
150
  childWorkflowId: z.ZodDefault<z.ZodNullable<z.ZodString>>;
155
151
  }, z.core.$strip>;
156
152
  export type StepExecutionRow = z.infer<typeof StepExecutionRowSchema>;
@@ -60,10 +60,7 @@ export const CortexRunRowSchema = z.object({
60
60
  });
61
61
  /**
62
62
  * Persistable sandbox handle — what the active-sandbox registry stores on
63
- * `cortex_step_executions.sandbox_ref`. Excludes the per-sandbox
64
- * `callbackSecret`, which lives only in the DBOS step-output cache (ADR
65
- * 0007). The harness reconstructs the full in-memory `SandboxRef` by
66
- * reading the secret from the cached `createSandbox` step output.
63
+ * `cortex_step_executions.sandbox_ref`.
67
64
  */
68
65
  export const PersistedSandboxRefSchema = z.object({
69
66
  sandboxId: z.string(),
@@ -94,8 +91,6 @@ export const StepExecutionRowSchema = z.object({
94
91
  blockedReason: z.string().nullable().default(null),
95
92
  /** Active-sandbox registry handle; null when no sandbox is live for this step. */
96
93
  sandboxRef: PersistedSandboxRefSchema.nullable().default(null),
97
- /** In-flight `${workflowId}:${stepId}:${functionId}`; null when no exec is in flight. */
98
- execId: z.string().nullable().default(null),
99
94
  /** DBOS child workflow id (`"${parentWorkflowId}-${N}"`); null on pre-DBOS rows. */
100
95
  childWorkflowId: z.string().nullable().default(null),
101
96
  });
@@ -142,7 +142,7 @@ export function queryStepsByRun(pool, runId) {
142
142
  text: `SELECT run_id, step_id, analysis_id, wave, agent_id,
143
143
  status, started_at, completed_at, duration_ms, error,
144
144
  attempts, last_error_class, finish_reason, hit_max_steps,
145
- blocked_reason, sandbox_ref, exec_id, child_workflow_id
145
+ blocked_reason, sandbox_ref, child_workflow_id
146
146
  FROM cortex_step_executions
147
147
  WHERE run_id = $1
148
148
  ORDER BY wave, started_at NULLS LAST, step_id`,
@@ -169,7 +169,6 @@ function mapStepExecutionRow(row) {
169
169
  hitMaxSteps: row.hit_max_steps === 1 || row.hit_max_steps === true,
170
170
  blockedReason: row.blocked_reason ?? null,
171
171
  sandboxRef: row.sandbox_ref ?? null,
172
- execId: row.exec_id ?? null,
173
172
  childWorkflowId: row.child_workflow_id ?? null,
174
173
  };
175
174
  }
@@ -127,7 +127,7 @@ export function buildDataProfileResult(submission, resolution, stagedInputs, pro
127
127
  * rests on, so failing the profile over it would trade the whole capability for a nicety.
128
128
  */
129
129
  async function readSetHeaders(args) {
130
- const { session, deps, analysisId, detected, sandbox, execId, deadlineMs, logger } = args;
130
+ const { session, deps, analysisId, detected, sandbox, deadlineMs, logger } = args;
131
131
  try {
132
132
  return await readHeaders({
133
133
  targets: readoutTargets(detected),
@@ -136,7 +136,6 @@ async function readSetHeaders(args) {
136
136
  sandboxClient: deps.sandboxClient,
137
137
  sandbox,
138
138
  mountRoot: `/${analysisId}`,
139
- execId,
140
139
  deadlineMs,
141
140
  emit: async () => { },
142
141
  });
@@ -306,8 +305,8 @@ export async function runDataProfileBody(input, deps) {
306
305
  selfCancelled = true;
307
306
  await cancelSelf("self-cancel-suspended");
308
307
  };
309
- // The profile's activity channel. `DBOS.writeStream` is body-only, so the write is bound here
310
- // while every phase and phrase lives in the emitter — the phrases are the observable contract of
308
+ // The profile's activity channel. The write to the stream is bound here, while every phase and
309
+ // phrase lives in the emitter — the phrases are the observable contract of
311
310
  // this capability, and a body that composed its own strings is a body they can drift from.
312
311
  // The frame is the workflow's synthetic one: both values are constants shared by every analysis,
313
312
  // so they identify nothing and consumers are required not to key on them.
@@ -434,20 +433,16 @@ export async function runDataProfileBody(input, deps) {
434
433
  return await suspendProfile(suspensionOfSpawnRefusal(spawned.error));
435
434
  const sandbox = spawned.value;
436
435
  try {
437
- // Checkpointed clock, not `Date.now()`: `awaitExec` gates on this absolute
438
- // deadline and its recovery-pull is a durable step, so a wall-clock deadline
439
- // that grew on replay would shift which loop iteration crosses the deadline
440
- // and desynchronise the recorded function-ID sequence (see sandbox-step.ts,
441
- // which captures its step deadline the same way).
436
+ // Checkpointed clock, not `Date.now()`: one deadline bounds every exec of the
437
+ // profile, and a wall-clock deadline would grow on each recovery (see
438
+ // sandbox-step.ts, which captures its step deadline the same way).
442
439
  const deadlineAbs = (await DBOS.now()) + DEFAULT_DEADLINE_MS;
443
- const nextFunctionId = makeNextFunctionId();
444
440
  const headers = await readSetHeaders({
445
441
  session: childSession,
446
442
  deps,
447
443
  analysisId,
448
444
  detected,
449
445
  sandbox,
450
- execId: `${workflowId}:${DATA_PROFILE_STEP_LITERAL}:${nextFunctionId()}`,
451
446
  deadlineMs: deadlineAbs,
452
447
  logger,
453
448
  });
@@ -482,14 +477,10 @@ export async function runDataProfileBody(input, deps) {
482
477
  sandbox,
483
478
  workspaceRoot,
484
479
  analysisId,
485
- runId: DATA_PROFILE_RUN_LITERAL,
486
- stepId: DATA_PROFILE_STEP_LITERAL,
487
- workflowId,
488
480
  // The profiler writes Python scripts and intermediate artifacts under
489
481
  // the synthetic step path; the post-agent `rm -rf runs/data-profile/`
490
482
  // cleanup wipes them.
491
483
  allowedWritePrefix: profileWritePrefix,
492
- nextFunctionId,
493
484
  deadlineMs: () => deadlineAbs,
494
485
  });
495
486
  let accepted = null;
@@ -548,6 +539,7 @@ export async function runDataProfileBody(input, deps) {
548
539
  },
549
540
  runStep: durableStep,
550
541
  resolved: () => accepted !== null,
542
+ invocationId: workflowId,
551
543
  usageRecorder: deps.usageRecorder,
552
544
  toolOutputStore: deps.toolOutputStore,
553
545
  isFatalLoopError: (err) => err instanceof DBOSErrors.DBOSWorkflowCancelledError,
@@ -878,8 +870,3 @@ function profileFailureReason(err) {
878
870
  const firstLine = raw.split("\n", 1)[0].replace(/\s+/g, " ").trim();
879
871
  return firstLine.length > PROFILE_ERROR_MAX_LEN ? firstLine.slice(0, PROFILE_ERROR_MAX_LEN - 1) + "…" : firstLine || "Data profiling failed";
880
872
  }
881
- /** Per-call function-id minter — replay-deterministic. */
882
- function makeNextFunctionId() {
883
- let n = 0;
884
- return () => `fn-${(n++).toString(36)}`;
885
- }
@@ -1,22 +1,17 @@
1
1
  /**
2
2
  * The container of one report-session derivation, as a registered DBOS workflow.
3
3
  *
4
- * The `derive_table` tool runs inside one live chat turn, and a chat turn is not a workflow body. An await
5
- * of an exec under the callback transport calls `DBOS.recv`, which a workflow body alone can call. Thus the
4
+ * The `derive_table` tool runs inside one live chat turn, and a chat turn is not a workflow. An exec runs as
5
+ * a durable step of a workflow, and the reaper maps each container to the workflow that owns it. Thus the
6
6
  * container lives here, behind a registered workflow, and the tool starts it and awaits the handle.
7
7
  *
8
8
  * The shape is the shape of `tasks/extract-values.ts`: a body that a test drives directly, a registration
9
9
  * that closes over the construction-time deps, and a trigger that starts the workflow and gives the result
10
10
  * back. The tool holds the trigger as a plain function, thus no module under `tools/` imports DBOS.
11
11
  *
12
- * The body owns the whole machine lifetime. It creates the container, submits one exec, awaits the terminal
12
+ * The body owns the whole machine lifetime. It creates the container, runs one exec to its terminal
13
13
  * result, and tears the container down on both paths. A teardown fault reaches the log alone, because the
14
14
  * work is done by then.
15
- *
16
- * The exec id is `${workflowId}:${stepId}:${fnId}`, the one shape that `workflowIdFromExec` parses. A
17
- * callback host reads the owner workflow out of the exec id alone, thus a flat id makes the completion
18
- * callback unroutable and it lands as a `400`. The pull backstop still settles such an exec, but it pays
19
- * the quiet interval first.
20
15
  */
21
16
  import { type Result } from "neverthrow";
22
17
  import type { Logger } from "../lib/logger.js";
@@ -48,12 +43,7 @@ export declare function runDeriveTableExecBody(input: DeriveTableExecInput, deps
48
43
  * dispatches with `DBOS.startWorkflow`.
49
44
  */
50
45
  export declare function registerDeriveTableExecWorkflow(deps: DeriveTableExecDeps): (input: DeriveTableExecInput) => Promise<Result<ExecResult, Suspension>>;
51
- /**
52
- * The workflow id of one derivation.
53
- *
54
- * It carries exactly one colon, because `workflowIdFromExec` recovers the id by a strip of the last two
55
- * colon-delimited segments of the exec id. The execution id is unique already, thus no nonce joins it.
56
- */
46
+ /** The workflow id of one derivation. The execution id is unique already, thus no nonce joins it. */
57
47
  export declare function deriveTableExecWorkflowId(executionId: string): string;
58
48
  /**
59
49
  * The async edge. It starts the registered workflow and it awaits the terminal result.