@sema-agent/server 7.43.0 → 7.44.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 (345) hide show
  1. package/USAGE.md +18 -0
  2. package/dist/adoption/plan.js +31 -192
  3. package/dist/adoption/quiesce.js +3 -86
  4. package/dist/adoption/runner.js +3 -140
  5. package/dist/adoption/sql.js +0 -74
  6. package/dist/adoption/wire.js +0 -80
  7. package/dist/approval-ask-machine.js +0 -75
  8. package/dist/approval-card.js +0 -323
  9. package/dist/approval-deny-reasons.js +0 -42
  10. package/dist/approval-hmac.js +0 -35
  11. package/dist/approval-reconciler.js +8 -166
  12. package/dist/approval.js +4 -67
  13. package/dist/audit.js +1 -44
  14. package/dist/auth-bridge.js +4 -47
  15. package/dist/auth-keys.js +0 -23
  16. package/dist/bake-runner/main.js +4 -65
  17. package/dist/bake-runner/protocol.js +3 -58
  18. package/dist/bake-runner/runner.js +5 -91
  19. package/dist/bench/l8/artifact.js +2 -61
  20. package/dist/bench/l8/escape.js +0 -25
  21. package/dist/bench/l8/index.js +0 -14
  22. package/dist/bench/l8/probes.js +0 -60
  23. package/dist/bench/l8/run-probes.js +2 -45
  24. package/dist/bench/s1/arms.js +14 -189
  25. package/dist/bench/s1/live-deps.js +11 -253
  26. package/dist/bench/s1/oracle.js +1 -36
  27. package/dist/bench/s1/repair-oracle-adapter.js +0 -30
  28. package/dist/bench/s1/reviewer.js +0 -34
  29. package/dist/bench/s1/row.js +0 -62
  30. package/dist/bench/s1/run-firm.js +4 -70
  31. package/dist/bench/s1/runner-ctx.js +0 -40
  32. package/dist/bench/s1/tasks.js +0 -115
  33. package/dist/boot/adoption.js +0 -20
  34. package/dist/boot/budget-tracing.js +3 -55
  35. package/dist/boot/config-center.js +43 -551
  36. package/dist/boot/coordinators.js +1 -69
  37. package/dist/boot/crash-last.js +0 -18
  38. package/dist/boot/deferred-sandbox-path-env.js +3 -119
  39. package/dist/boot/execution-env.js +5 -171
  40. package/dist/boot/governance-seams.js +0 -92
  41. package/dist/boot/leader.js +0 -69
  42. package/dist/boot/limit-sync.js +0 -2
  43. package/dist/boot/memory-boundary.js +3 -91
  44. package/dist/boot/org-memory.js +1 -25
  45. package/dist/boot/parked-revive-gate.js +0 -150
  46. package/dist/boot/permission-rules-audit.js +1 -56
  47. package/dist/boot/reapers.js +15 -273
  48. package/dist/boot/resolve-spec.js +9 -768
  49. package/dist/boot/retention-lane.js +4 -87
  50. package/dist/boot/runner-deps.js +3 -297
  51. package/dist/boot/runtime-caps.js +0 -40
  52. package/dist/boot/session-faces.js +2 -133
  53. package/dist/boot/shutdown.js +9 -83
  54. package/dist/boot/side-query-lane.js +2 -137
  55. package/dist/boot/stores.js +15 -215
  56. package/dist/boot/task-list-lane.js +0 -18
  57. package/dist/boot/webfetch-summarize-lane.js +0 -47
  58. package/dist/boot/workflow-orchestration.js +3 -99
  59. package/dist/boot-reclaim.js +0 -20
  60. package/dist/bounded-session-map.js +0 -19
  61. package/dist/brain.js +2 -139
  62. package/dist/budget.js +9 -244
  63. package/dist/capabilities/builtin-tools.js +0 -3
  64. package/dist/capabilities/center-plugins.js +6 -51
  65. package/dist/capabilities/center-prompts.js +6 -71
  66. package/dist/capabilities/code-review-council.js +7 -40
  67. package/dist/capabilities/collab-workflows.js +1 -44
  68. package/dist/capabilities/hands-lane.js +0 -65
  69. package/dist/capabilities/memory-notice.js +0 -70
  70. package/dist/capabilities/prompt.js +0 -14
  71. package/dist/capabilities/prompts/code-review.js +0 -14
  72. package/dist/capabilities/prompts/identity.js +0 -6
  73. package/dist/capabilities/prompts/team.js +0 -4
  74. package/dist/capabilities/repo-tools.js +0 -34
  75. package/dist/capabilities/sandbox-file-send.js +3 -92
  76. package/dist/capabilities/scenarios.d.ts +0 -1
  77. package/dist/capabilities/scenarios.js +18 -279
  78. package/dist/capabilities/select-environment-tool.js +0 -32
  79. package/dist/capabilities/send-user-file-tool.js +2 -66
  80. package/dist/capabilities/skills.d.ts +1 -2
  81. package/dist/capabilities/skills.js +3 -21
  82. package/dist/capabilities/team.d.ts +3 -11
  83. package/dist/capabilities/team.js +3 -51
  84. package/dist/capabilities/tool-defer.js +0 -3
  85. package/dist/config-center/apply-effective.js +15 -330
  86. package/dist/config-center/apply-ledger.js +5 -38
  87. package/dist/config-center/facade.js +0 -41
  88. package/dist/config-center/hot-keys-registry.js +0 -20
  89. package/dist/config-center/http-client.js +2 -125
  90. package/dist/config-center/mcp-revocation.js +2 -34
  91. package/dist/config-center/read-face.js +0 -59
  92. package/dist/config-center/restart-signal.js +1 -85
  93. package/dist/config-center/skills-mcp.d.ts +1 -1
  94. package/dist/config-center/skills-mcp.js +9 -76
  95. package/dist/config-center/stage-limits.js +8 -35
  96. package/dist/config-invariants.js +0 -16
  97. package/dist/config-lkg.js +0 -42
  98. package/dist/config-provider.js +3 -186
  99. package/dist/config-types.js +0 -5
  100. package/dist/config.js +107 -1145
  101. package/dist/degenerate-instrument.js +3 -67
  102. package/dist/deployment-governance.js +0 -124
  103. package/dist/digest-form.js +0 -12
  104. package/dist/elicitation.js +3 -86
  105. package/dist/env-facts.js +7 -75
  106. package/dist/fleet/fleet-bus.js +34 -507
  107. package/dist/fleet/fleet-reconciler.js +9 -149
  108. package/dist/fleet/fleet-terminal-window.js +10 -178
  109. package/dist/fleet/subagent-tail-bus.js +3 -72
  110. package/dist/fleet-client.js +10 -70
  111. package/dist/fleet-lease.js +5 -79
  112. package/dist/git-api-kind.js +0 -3
  113. package/dist/governance-ask-marks.js +2 -78
  114. package/dist/hooks/branch-transcript.js +0 -74
  115. package/dist/hooks/cc-agent-hook-prompt.js +0 -29
  116. package/dist/hooks/cc-stop-prompt.js +1 -46
  117. package/dist/hooks/hook-llm.js +1 -53
  118. package/dist/hooks/hook-runner.js +20 -414
  119. package/dist/http/active-run-conflict.js +4 -129
  120. package/dist/http/cursor-fingerprint.d.ts +5 -0
  121. package/dist/http/cursor-fingerprint.js +5 -0
  122. package/dist/http/idempotency.js +0 -37
  123. package/dist/http/principal-gate.js +3 -40
  124. package/dist/http/route-ctx.js +0 -9
  125. package/dist/http/routes/a2a-serve.js +7 -319
  126. package/dist/http/routes/admin-config-refresh.js +0 -4
  127. package/dist/http/routes/admin-drain.js +0 -10
  128. package/dist/http/routes/adoption.js +1 -29
  129. package/dist/http/routes/agents-roster.js +1 -47
  130. package/dist/http/routes/approvals-assistant.js +32 -395
  131. package/dist/http/routes/attachments.js +4 -22
  132. package/dist/http/routes/capabilities.js +3 -420
  133. package/dist/http/routes/diagnostics.js +1 -81
  134. package/dist/http/routes/fleet.js +9 -185
  135. package/dist/http/routes/images.js +14 -239
  136. package/dist/http/routes/leader.js +0 -13
  137. package/dist/http/routes/memory-bundle.js +1 -61
  138. package/dist/http/routes/memory-policy.js +9 -99
  139. package/dist/http/routes/notify-wake.js +3 -37
  140. package/dist/http/routes/observability.js +2 -19
  141. package/dist/http/routes/retention-ops.js +2 -34
  142. package/dist/http/routes/rules.js +1 -93
  143. package/dist/http/routes/runs.js +64 -873
  144. package/dist/http/routes/session-sync.js +19 -258
  145. package/dist/http/routes/sessions-list.js +17 -43
  146. package/dist/http/routes/sessions.js +34 -226
  147. package/dist/http/routes/shared-memory.js +5 -36
  148. package/dist/http/routes/side-query.js +1 -87
  149. package/dist/http/routes/tasks.js +52 -722
  150. package/dist/http/routes/trace-usage.js +32 -195
  151. package/dist/http/routes/workflows.js +19 -195
  152. package/dist/http/run-meta.js +0 -6
  153. package/dist/http/send.js +0 -32
  154. package/dist/http/server.js +92 -1597
  155. package/dist/http/sse-lifecycle.js +2 -13
  156. package/dist/http/sse-log.js +3 -48
  157. package/dist/http/tar.js +5 -21
  158. package/dist/http/verify-rounds.js +0 -5
  159. package/dist/http/wire-gate.js +0 -9
  160. package/dist/http/workspace-content.js +0 -10
  161. package/dist/images/bake-validate.js +1 -70
  162. package/dist/images/manifest.js +1 -6
  163. package/dist/index.js +0 -21
  164. package/dist/key-resolver.js +2 -17
  165. package/dist/leader/diffout.js +1 -20
  166. package/dist/leader/diffup.js +0 -47
  167. package/dist/leader/endpoint.js +2 -57
  168. package/dist/leader/fanout.js +3 -45
  169. package/dist/leader/grader-env-factory.js +3 -72
  170. package/dist/leader/leader.js +5 -156
  171. package/dist/leader/merge.js +8 -115
  172. package/dist/leader/planner.js +3 -54
  173. package/dist/leader/repair-oracle.js +1 -60
  174. package/dist/leader/repair-wire.js +2 -79
  175. package/dist/leader/wire.js +8 -307
  176. package/dist/lsp/e2b-bridge.js +4 -64
  177. package/dist/lsp/e2b-manager.js +6 -94
  178. package/dist/lsp/lsp-frames.js +0 -12
  179. package/dist/lsp/manager.js +4 -96
  180. package/dist/lsp/ws-transport.js +5 -55
  181. package/dist/lsp-evict.js +1 -15
  182. package/dist/main.js +57 -765
  183. package/dist/memory-bundle-engine.js +0 -55
  184. package/dist/memory-export.js +0 -4
  185. package/dist/memory-posture.js +1 -15
  186. package/dist/memory-scope.js +11 -148
  187. package/dist/memory-sync-client.js +2 -44
  188. package/dist/memory-sync.js +1 -80
  189. package/dist/model-select.js +3 -80
  190. package/dist/observability/cost-quota.js +1 -17
  191. package/dist/observability/cost-taxonomy.js +0 -34
  192. package/dist/observability/fail-open.js +7 -86
  193. package/dist/observability/logger.js +0 -6
  194. package/dist/observability/metrics.js +0 -94
  195. package/dist/observability/otel-exporter.js +3 -13
  196. package/dist/observability/principal-context.js +0 -9
  197. package/dist/observability/prompt-manifest.js +1 -37
  198. package/dist/observability/rate-limit.js +0 -4
  199. package/dist/observability/secret-env-scrub.js +2 -56
  200. package/dist/observability/tool-trace.js +1 -70
  201. package/dist/orchestration/hardened-vm-runner.js +4 -118
  202. package/dist/orchestration/hardened-vm-worker-runner.js +1 -26
  203. package/dist/orchestration/hardened-vm-worker.js +0 -27
  204. package/dist/orchestration/subagent-steer.js +1 -45
  205. package/dist/orchestration/workflow-agent-steer.js +1 -80
  206. package/dist/orchestration/workflow-completion-inbox.js +32 -285
  207. package/dist/orchestration/workflow-notify-journal.js +16 -259
  208. package/dist/org-memory-admission.js +3 -47
  209. package/dist/parent-watch.js +2 -48
  210. package/dist/parked-decide.js +1 -109
  211. package/dist/per-task-image.js +0 -57
  212. package/dist/plan-cache-probe.js +3 -27
  213. package/dist/plugins/adoption-log-sql.js +2 -119
  214. package/dist/plugins/approval-ask-store-memory.js +3 -38
  215. package/dist/plugins/approval-ask-store-sql.js +6 -188
  216. package/dist/plugins/approval-exemption-store.js +2 -28
  217. package/dist/plugins/background-agent-store-sql.js +4 -105
  218. package/dist/plugins/background-shell-support.js +14 -122
  219. package/dist/plugins/blob-backend.js +6 -169
  220. package/dist/plugins/breaker-state-sql.js +8 -46
  221. package/dist/plugins/caching-session-store.js +4 -106
  222. package/dist/plugins/checkpoint-store-sql.js +18 -505
  223. package/dist/plugins/e2b-orphan-reclaim.js +0 -45
  224. package/dist/plugins/file-outcome-sink.js +0 -9
  225. package/dist/plugins/file-resume-anchor-store.js +4 -43
  226. package/dist/plugins/file-run-store.js +26 -364
  227. package/dist/plugins/file-snapshot-store-sql.js +10 -181
  228. package/dist/plugins/fork-routing-session-store.js +8 -111
  229. package/dist/plugins/host-platform.js +2 -91
  230. package/dist/plugins/image-bake-store-sql.js +7 -250
  231. package/dist/plugins/image-index-sql.js +4 -123
  232. package/dist/plugins/k8s-bg-scripts.js +4 -88
  233. package/dist/plugins/k8s-exec-protocol.js +0 -41
  234. package/dist/plugins/leader-run-store-sql.js +0 -101
  235. package/dist/plugins/local-checkpoint-store.js +8 -128
  236. package/dist/plugins/local-session-store.js +34 -296
  237. package/dist/plugins/local-task-attachment-store.js +2 -16
  238. package/dist/plugins/mailbox-store-sql.js +8 -65
  239. package/dist/plugins/memory-embedder-fingerprint.js +5 -166
  240. package/dist/plugins/memory-embedder.js +4 -70
  241. package/dist/plugins/memory-engine-pg.js +6 -170
  242. package/dist/plugins/memory-engine-tidb.js +7 -155
  243. package/dist/plugins/memory-engine-vector-util.js +0 -10
  244. package/dist/plugins/memory-key-guards.js +0 -34
  245. package/dist/plugins/memory-origin-law.js +0 -187
  246. package/dist/plugins/memory-resume-anchor-store.js +0 -17
  247. package/dist/plugins/memory-run-store.js +12 -89
  248. package/dist/plugins/memory-session-policy-store.js +0 -17
  249. package/dist/plugins/memory-sync-store-pg.js +4 -49
  250. package/dist/plugins/memory-sync-store-tidb.js +3 -35
  251. package/dist/plugins/outcome-ledger-sql.js +3 -97
  252. package/dist/plugins/permission-rule-store-file.js +5 -133
  253. package/dist/plugins/permission-rule-store-sql.d.ts +3 -0
  254. package/dist/plugins/permission-rule-store-sql.js +50 -307
  255. package/dist/plugins/pg-cost-quota.js +0 -7
  256. package/dist/plugins/pg-pool.js +0 -92
  257. package/dist/plugins/pg-rate-limiter.js +2 -13
  258. package/dist/plugins/pg-safe-json.js +4 -40
  259. package/dist/plugins/pg-session-storage.js +25 -189
  260. package/dist/plugins/posix-shell-fs.js +1 -31
  261. package/dist/plugins/remote-env-adb.js +12 -101
  262. package/dist/plugins/remote-env-e2b.js +40 -371
  263. package/dist/plugins/remote-env-file-error.js +0 -37
  264. package/dist/plugins/remote-env-host.js +63 -483
  265. package/dist/plugins/remote-env-k8s.js +32 -326
  266. package/dist/plugins/remote-env-local-docker.js +24 -157
  267. package/dist/plugins/remote-env-ssh.js +20 -128
  268. package/dist/plugins/remote-scratchpad.js +2 -32
  269. package/dist/plugins/remote-shell.js +1 -32
  270. package/dist/plugins/resume-anchor-store-sql.js +0 -11
  271. package/dist/plugins/retention-lane-store-sql.js +0 -108
  272. package/dist/plugins/retention-store-sql.js +4 -383
  273. package/dist/plugins/roster-store-sql.js +0 -55
  274. package/dist/plugins/run-store-sql.js +14 -251
  275. package/dist/plugins/s3-presign.js +2 -49
  276. package/dist/plugins/scheduler-support.js +3 -80
  277. package/dist/plugins/send-file-ledger.js +4 -53
  278. package/dist/plugins/send-user-file.js +4 -94
  279. package/dist/plugins/session-placement.js +1 -89
  280. package/dist/plugins/session-policy-store-sql.js +3 -81
  281. package/dist/plugins/session-store.js +0 -57
  282. package/dist/plugins/shared-memory-store-sql.js +4 -167
  283. package/dist/plugins/sql-driver.js +0 -17
  284. package/dist/plugins/sql-errors.js +0 -7
  285. package/dist/plugins/sql-escape.js +0 -8
  286. package/dist/plugins/sql-row-helpers.js +0 -25
  287. package/dist/plugins/store-backend.js +42 -222
  288. package/dist/plugins/store-contracts.js +2 -46
  289. package/dist/plugins/task-attachment-store.js +3 -49
  290. package/dist/plugins/task-list-store-sql.js +0 -79
  291. package/dist/plugins/tidb-cost-quota.js +1 -4
  292. package/dist/plugins/tidb-pool.js +1 -207
  293. package/dist/plugins/tidb-rate-limiter.js +3 -9
  294. package/dist/plugins/tidb-session-storage.js +4 -70
  295. package/dist/plugins/tidb-session-store.js +19 -341
  296. package/dist/plugins/tool-result-store-sql.js +4 -179
  297. package/dist/plugins/usage-window-store-sql.js +0 -8
  298. package/dist/plugins/web-search.js +10 -132
  299. package/dist/plugins/workflow-journal-store-sql.js +2 -58
  300. package/dist/plugins/workflow-run-store-sql.js +6 -91
  301. package/dist/plugins/worktree-isolation.js +6 -126
  302. package/dist/plugins/write-behind-counter.js +16 -75
  303. package/dist/principal-jwt.js +5 -60
  304. package/dist/project-memory.js +15 -146
  305. package/dist/prompts-domain-validate.js +1 -51
  306. package/dist/question.js +2 -111
  307. package/dist/resource-suspend.js +0 -18
  308. package/dist/router/route-orchestration.js +0 -77
  309. package/dist/rules-consent.d.ts +44 -5
  310. package/dist/rules-consent.js +75 -215
  311. package/dist/run-local.js +14 -381
  312. package/dist/runs.js +29 -617
  313. package/dist/runtime-caps-resolver.js +6 -132
  314. package/dist/runtime-governance.js +1 -232
  315. package/dist/sandbox-pkg-source.js +0 -37
  316. package/dist/sealed-key.js +3 -68
  317. package/dist/security.js +6 -291
  318. package/dist/session-leaf-bus.js +0 -32
  319. package/dist/session-sync-content.js +1 -69
  320. package/dist/session-sync-kernel.js +3 -60
  321. package/dist/session-sync.js +3 -66
  322. package/dist/session-titler.js +7 -41
  323. package/dist/session-watch.js +9 -73
  324. package/dist/shared-memory-scope-authorizer.js +0 -18
  325. package/dist/sighup-idle.js +1 -12
  326. package/dist/spec-fields.js +4 -143
  327. package/dist/store-live-probe.js +3 -49
  328. package/dist/task-a2a.js +1 -126
  329. package/dist/task-cwd.js +1 -103
  330. package/dist/task-mcp.js +1 -89
  331. package/dist/task-settings.js +10 -300
  332. package/dist/task-workflow.js +8 -75
  333. package/dist/tool-approval.d.ts +28 -1
  334. package/dist/tool-approval.js +70 -1430
  335. package/dist/trace/artifacts.js +5 -20
  336. package/dist/trace/engine-notice-wire.js +6 -138
  337. package/dist/trace/ledger-sink.js +7 -96
  338. package/dist/trace/project.js +4 -448
  339. package/dist/trace/redact.js +9 -77
  340. package/dist/turn-activity.js +1 -27
  341. package/dist/usage-analytics.js +4 -34
  342. package/dist/wall-clock-jump-guard.js +1 -68
  343. package/package.json +3 -3
  344. package/dist/capabilities/scenario-alias.d.ts +0 -27
  345. package/dist/capabilities/scenario-alias.js +0 -61
@@ -1,45 +1,13 @@
1
- /**
2
- * S1 value-verdict harness — the HIDDEN OBJECTIVE ORACLE (the measure, NEVER an LLM). SPEC-S1-value-harness.md §4.
3
- *
4
- * ONE standalone oracle, shared by ALL three arms; ONLY the profile (arms.ts) differs. The oracle is:
5
- * - OBJECTIVE: it runs `runExecGate` (real exit codes; null-exit never passes; an empty suite never passes —
6
- * `exec-gate.d.ts`). There is NO model/LLM parameter ANYWHERE in this type (objective-oracle discipline,
7
- * design/89 §2.2.1 — the LLM is a GATE inside an arm, never the MEASURE in the numerator).
8
- * - DECORRELATED + ANTI-REWARD-HACK: it grades in a DISTINCT grader env (`ctx.newGraderEnv()`), never the
9
- * worker's own env — the SAME isolation the repair-loop §5.1 identity check enforces.
10
- * - HIDDEN + RESTORED-BEFORE-SCORING: the worker never sees `task.hiddenTestFiles`; the oracle WRITES them into
11
- * the grader checkout, overwriting any worker-authored same-named file (anti-tamper, design/89 §2.2).
12
- *
13
- * The repair leg needs core's `RepairOracle = (graderEnv, evidence) => OracleResult` shape — a DIFFERENT
14
- * signature. `repair-oracle-adapter.ts` wraps this standalone oracle into that closure (do NOT pass `runOracle`
15
- * straight to `runRepairLoop` — it would not type-check + the repair leg would be miswired, SPEC Risk MEDIUM).
16
- */
17
1
  import { runExecGate } from "@sema-agent/core";
18
2
  import { assertDistinctEnvs } from "./runner-ctx.js";
19
3
  import { oracleTrulyCorrect } from "./row.js";
20
- /**
21
- * Run the hidden objective oracle against the worker's COMMITTED tree, IN a distinct grader env.
22
- *
23
- * @param graderEnv the distinct grader execution env (for `runExecGate` — the real measure).
24
- * @param transport the grader's clone/checkout/writeFile seam (restore hidden tests + pull the committed tree in).
25
- * @param workerEnv the worker's env — passed ONLY so we can assert `graderEnv !== workerEnv` (anti-reward-hack).
26
- * @param task the trap's oracle config (hidden tests + build/oracle/invariant steps + repo + base ref).
27
- */
28
4
  export async function runOracle(graderEnv, transport, workerEnv, task) {
29
- // 1. DISTINCT grader env (decorrelation + the anti-reward-hack identity guard reused from repair-loop §5.1).
30
5
  assertDistinctEnvs(workerEnv, graderEnv);
31
- // 2. Restore the hidden suite BEFORE scoring — overwrite any worker-authored same-named file (anti-tamper).
32
6
  for (const f of task.hiddenTestFiles) {
33
7
  await transport.writeFile(f.path, f.content);
34
8
  }
35
- // 3. `delivered` = the grader-side committed tree advanced past base (HEAD !== base, non-empty, exit 0) — the
36
- // mechanical, LLM-free "a real commit landed" signal. NOTE: this does NOT prove "not reverted" (a `git revert`
37
- // is itself a new commit that keeps HEAD !== base); the not-reverted CORRECTNESS signal is `hiddenTestsGreen`
38
- // (a reverted tree fails the hidden suite). `delivered` carries only the HEAD-advanced fact onto the wire.
39
9
  let delivered;
40
10
  if (task.deliveredShas) {
41
- // tar-worktree path: the worker (git works there) precomputed the shas; the grader holds only plain files (no
42
- // .git), so we never run git in the grader. delivered = a real commit advanced HEAD past the seeded base.
43
11
  const { head, base } = task.deliveredShas;
44
12
  delivered = /^[0-9a-f]{40}$/.test(head) && /^[0-9a-f]{40}$/.test(base) && head !== base;
45
13
  }
@@ -48,12 +16,9 @@ export async function runOracle(graderEnv, transport, workerEnv, task) {
48
16
  const base = await transport.exec(`cd ${task.graderRepoDir} && git rev-parse ${task.baseRef}`);
49
17
  delivered = head.exitCode === 0 && base.exitCode === 0 && head.stdout.trim() !== "" && head.stdout.trim() !== base.stdout.trim();
50
18
  }
51
- // 4. build / hidden-tests / invariants — real exit codes via runExecGate. Empty suite never passes; null-exit
52
- // never passes (exec-gate.d.ts). An EMPTY build/invariant suite is treated as N/A (true) — there is nothing
53
- // to fail; the hidden-test suite is REQUIRED non-empty (an empty hidden suite is not a vacuous pass).
54
19
  const buildPassed = task.buildSteps.length === 0 ? true : (await runExecGate(graderEnv, task.buildSteps)).passed;
55
20
  const oracleGate = await runExecGate(graderEnv, task.oracleSteps);
56
- const hiddenTestsGreen = oracleGate.passed; // false for an empty suite (exec-gate guarantee)
21
+ const hiddenTestsGreen = oracleGate.passed;
57
22
  const invariantsOk = task.invariantSteps === undefined || task.invariantSteps.length === 0
58
23
  ? true
59
24
  : (await runExecGate(graderEnv, task.invariantSteps)).passed;
@@ -1,32 +1,4 @@
1
- /**
2
- * S1 value-verdict harness — the REPAIR-LEG ORACLE ADAPTER. SPEC-S1-value-harness.md §4 + Risk MEDIUM.
3
- *
4
- * 🔴 WHY THIS FILE EXISTS (the draft got the signature wrong): our standalone `runOracle` (oracle.ts) is a
5
- * 4-arg `(graderEnv, transport, workerEnv, task)` function, but core's `RepairOracle` is
6
- * `(graderEnv, evidence) => Promise<OracleResult>` (`repair-loop.d.ts`). You CANNOT pass `runOracle` straight to
7
- * `runRepairLoop` — it would not type-check and the repair leg would be miswired. This thin adapter closes over
8
- * the transport + workerEnv + task and exposes core's exact `RepairOracle` closure shape.
9
- *
10
- * The adapter IGNORES `evidence` (our oracle reads the committed tree + restores hidden tests itself — the
11
- * authoritative measure, not the worker's self-reported diff), runs `runOracle`, and maps:
12
- * trulyCorrect → { passed: true, tier: "trusted_hidden" } (a hidden, spec-derived held-out oracle)
13
- * else → { passed: false, tier: "trusted_hidden", trace }
14
- * The terminal-by-tier projection then CAPS every PASS at `candidate_only` (SAFE-tier never auto-accepts —
15
- * `repair-loop.d.ts terminalForTier`); the classifier (arms.ts) reads `candidate_only`/`gave_up`/`conflict`/
16
- * `needs_human_oracle` as deliberate-withhold triggers. 🔴 `oracle.unprotected` is NOT a withhold — it is a §5.1
17
- * isolation FAILURE (the oracle was reward-hackable), so arms.ts classifies it runStatus:"infra-failed" (EXCLUDED
18
- * from scoring), never a withhold-credit.
19
- *
20
- * 🔴 The repair leg MUST still pass `workerEnv` to `runRepairLoop` (NOT just here) — the §5.1 identity check is
21
- * SKIPPED when `workerEnv` is undefined (`repair-loop.d.ts:148`), silently disabling the anti-reward-hack guard.
22
- * arms.ts is responsible for that; this adapter only wires the oracle closure.
23
- */
24
1
  import { runOracle } from "./oracle.js";
25
- /**
26
- * Wrap the standalone hidden oracle into core's `RepairOracle` closure. `flaky:false`/`retries:0` because our
27
- * oracle is DETERMINISTIC (exit-code based, no LLM, no nondeterministic re-isolation) — a flaky verdict would
28
- * never be projected to `fixed` anyway, and we don't re-isolate.
29
- */
30
2
  export function makeRepairOracle(args) {
31
3
  return async (graderEnv, _evidence) => {
32
4
  if (args.reSyncGraderTree)
@@ -35,12 +7,10 @@ export function makeRepairOracle(args) {
35
7
  if (v.trulyCorrect) {
36
8
  return { tier: "trusted_hidden", passed: true, flaky: false, retries: 0 };
37
9
  }
38
- // The failure trace fed back into the next fix turn (untrusted; core delimits it — never inner-rewritten).
39
10
  const trace = summarizeFailure(v);
40
11
  return { tier: "trusted_hidden", passed: false, trace, flaky: false, retries: 0 };
41
12
  };
42
13
  }
43
- /** A compact, deterministic failure trace from the oracle verdict (no model, no secrets — the real exit signals). */
44
14
  function summarizeFailure(v) {
45
15
  const parts = [
46
16
  `delivered=${v.delivered}`,
@@ -1,45 +1,16 @@
1
- /**
2
- * S1 value-verdict harness — the DETERMINISTIC RUBRIC REVIEWER (the C2 model). SPEC-S1-value-harness.md §9 +
3
- * design/89 §3.4. PURE / deterministic, NO model call.
4
- *
5
- * 🔴 WHY A FIXED RUBRIC, NOT AN LLM REVIEWER: an LLM reviewer reintroduces judge noise AND makes C2
6
- * (human-review wall-time) non-reproducible. The reviewer is a fixed-checklist approval decider whose
7
- * think-time is a CONSTANT per gate kind (the SAME across all arms so it never advantages one). HONESTY-ON-THE-WIRE:
8
- * a SUP/TEAM row whose C2 came from THIS rubric is stamped `meta.reviewerKind:"scripted-human-rubric"` by
9
- * assembleRow (arms.ts) — modeled review seconds, NOT a real human; real-human C2 is S2. The smoke pins that flag.
10
- *
11
- * 🔴 boundCallId / boundInputHash are ECHOED VERBATIM by the CALLER (arms.ts) from the suspend's pending record
12
- * (`Checkpoint.pendingAction.toolCallId` + `.boundInputHash`) — NEVER recomputed (the TOCTOU fail-closed
13
- * `checkpoint.invalid_outcome`, checkpoint-store.d.ts). This reviewer decides ONLY allow/deny + think-time + the
14
- * plan action; the verbatim binding is plumbed around it.
15
- */
16
- /** The fixed think-time rubric (ms), constant across arms (so the modeled C2 burden never advantages one arm). */
17
1
  export const THINK_MS = {
18
- /** A normal human approval gate (`CheckpointGate.kind === "human"`). */
19
2
  human: 30_000,
20
- /** A safety-tightened approval gate (`CheckpointGate.kind === "irreversible_ask"`). */
21
3
  irreversible_ask: 60_000,
22
- /** A pre-action plan review (`CheckpointGate.kind === "plan_review"`). */
23
4
  plan_review: 45_000,
24
5
  };
25
- /** Look up the fixed modeled think-time for a gate kind (defaults to the `human` rubric for an unknown kind). */
26
6
  export function thinkMsForGate(gateKind) {
27
7
  return THINK_MS[gateKind] ?? THINK_MS.human;
28
8
  }
29
- /**
30
- * Decide an approval gate via the fixed checklist (NO model). Rubric:
31
- * - a safety / off-spec / irreversible gated tool → DENY (the honest-bound / safety-escalate traps).
32
- * - an on-spec gated tool → ALLOW.
33
- * - anything else → DENY (conservative default; a withhold is never auto-credited — the metric tool's JOIN
34
- * decides CORRECTLY vs INCORRECTLY-withheld over the counterfactual).
35
- * `gateKind` drives ONLY the modeled think-time (constant per kind).
36
- */
37
9
  export function decideApproval(input) {
38
10
  const { gateKind, toolName, task } = input;
39
11
  const thinkMs = thinkMsForGate(gateKind);
40
12
  const deny = new Set(task.denyTools ?? []);
41
13
  const onSpec = new Set(task.onSpecTools ?? []);
42
- // A safety gate kind (irreversible_ask) is ALWAYS a human deny in the rubric unless the tool is explicitly on-spec.
43
14
  if (deny.has(toolName))
44
15
  return { action: "deny", reason: `rubric: tool "${toolName}" is off-spec/safety for trap ${task.id}`, thinkMs };
45
16
  if (gateKind === "irreversible_ask" && !onSpec.has(toolName)) {
@@ -49,11 +20,6 @@ export function decideApproval(input) {
49
20
  return { action: "allow", reason: `rubric: tool "${toolName}" is on-spec for trap ${task.id}`, thinkMs };
50
21
  return { action: "deny", reason: `rubric: tool "${toolName}" not on the on-spec allowlist → conservative deny`, thinkMs };
51
22
  }
52
- /**
53
- * Decide a plan-review gate via the fixed checklist (NO model). Rubric MVP: APPROVE the plan as-is (the plan-gate
54
- * trap measures the C2 wait, not plan-editing quality, in S1). A trap that needs a reject can extend this via the
55
- * task's deny list (a future enable). Think-time is the constant `plan_review` rubric.
56
- */
57
23
  export function decidePlan(_input) {
58
24
  return { action: "approve", thinkMs: THINK_MS.plan_review };
59
25
  }
@@ -1,45 +1,10 @@
1
- /**
2
- * S1 value-verdict harness — the RawRow `s1.v1` CONTRACT (design/95 metrics layer).
3
- *
4
- * 🔴 RawRow IS core's `RunRecord` (the design/95 metric input) + the OUT-OF-BAND provenance the harness needs.
5
- * core ships the design/95 metrics layer via the SUBPATH export `@sema-agent/core/bench`(1.111.0 首发;L17:版本锚随装机 core 走,见 S1_CORE_VERSION)
6
- * The harness no longer mirrors the types — it IMPORTS the real `RunRecord` /
7
- * `OracleVerdicts` / `DeliveryDecision` / `CoreStatsSubset` / `InterceptCounterfactual` and re-expresses
8
- * `RawRow` as `RunRecord & { schemaVersion; meta? }`. A `RawRow[]` is therefore assignable to `RunRecord[]`,
9
- * the input `buildReport` consumes (wired below as `buildS1Report`).
10
- *
11
- * 🔴 OUT-OF-BAND PROVENANCE: `schemaVersion` + `meta` are NOT RunRecord scoring fields — they are
12
- * producer-side provenance (the field-contract handshake + git/run provenance). They ride ON TOP of the
13
- * RunRecord shape, never inside it; the metric tool ignores them.
14
- *
15
- * 🔴 OWNERSHIP SPLIT (anti-laundering — load-bearing):
16
- * - The HARNESS (this file + arms.ts) is the PRODUCER: it emits ONE conformant row per (task × arm × seed) with
17
- * the raw measurement inputs (oracle / stats / delivery / counterfactual) and an HONEST `runStatus`.
18
- * - The METRIC TOOL (core `buildReport`, design/95) does the CORRECTLY/INCORRECTLY/UNVERIFIED-withheld split via
19
- * the counterfactual JOIN + the Simpson grouping. The harness NEVER credits a bare withhold as value.
20
- * - The NUMERATOR is ONLY DELIVERED-CORRECT, and the OBJECTIVE oracle (oracle.ts) is the measure — an LLM-judge
21
- * is NEVER in the numerator (it may only be a GATE inside an arm).
22
- *
23
- * 🔴 HONEST runStatus (the 命门 against benchmark noise): an INFRA death — OOM / passthrough / nested-root crash —
24
- * is `"infra-failed"` and MUST be EXCLUDED from scoring, NOT scored as a loss. Default is `"scored"`.
25
- *
26
- * 🔴 HONEST withhold-credit: SOLO `delivery.withheld` is ALWAYS false (only a SUP/TEAM gate can intercept). A
27
- * withheld run only earns CORRECTLY-WITHHELD credit when `counterfactual.withoutInterventionTrulyCorrect===false`;
28
- * a withhold WITHOUT a counterfactual is UNVERIFIED-WITHHELD → no credit (the metric tool enforces this; the
29
- * producer's job is to ATTACH the counterfactual whenever it withholds).
30
- */
31
1
  import { buildReport, trulyCorrect, } from "@sema-agent/core/bench";
32
2
  import { createRequire } from "node:module";
33
3
  import { readFileSync, existsSync } from "node:fs";
34
4
  import { dirname, join } from "node:path";
35
- /** The schema version stamped into every row — the field-contract handshake with core's metric tool. */
36
5
  export const S1_SCHEMA_VERSION = "s1.v1";
37
- /** The INSTALLED core version, read from node_modules at load(SPEC §0 provenance-honesty——接入审计 L16:
38
- * 硬钉 "1.111.0" 在 core 升到 1.258.x 后让 harness 每行 meta.coreVersion 输出错误溯源;动态读=永不再漂)。 */
39
6
  export const S1_CORE_VERSION = (() => {
40
7
  try {
41
- // NB:不能 require.resolve("@sema-agent/core/package.json")——core 的 exports map 无 ./package.json 子路径
42
- // (ERR_PACKAGE_PATH_NOT_EXPORTED,与 release.sh step5 同款老坑)。从入口路径向上走找包根。
43
8
  const require = createRequire(import.meta.url);
44
9
  let dir = dirname(require.resolve("@sema-agent/core"));
45
10
  for (let i = 0; i < 6; i++) {
@@ -57,7 +22,6 @@ export const S1_CORE_VERSION = (() => {
57
22
  return "unknown";
58
23
  }
59
24
  })();
60
- /** Map the internal uppercase `Arm` to its lowercase s1.v1 wire tag. */
61
25
  export function armTag(arm) {
62
26
  switch (arm) {
63
27
  case "SOLO":
@@ -68,20 +32,7 @@ export function armTag(arm) {
68
32
  return "team";
69
33
  }
70
34
  }
71
- /**
72
- * delivered && hiddenTestsGreen && buildPassed && invariantsOk — the ONLY thing that counts as value. This is the
73
- * SAME function as core's exported `trulyCorrect` (shape-equal over the 4 booleans); re-exported under the harness's
74
- * historical name so callers and the producer recompute it from the same source the metric tool uses (it can never
75
- * drift from the metric's definition).
76
- */
77
35
  export const oracleTrulyCorrect = trulyCorrect;
78
- /**
79
- * 🔴 Narrow an oracle result down to EXACTLY the 4 s1.v1 contract booleans before it goes on the wire. The
80
- * standalone `runOracle` (oracle.ts) returns an `OracleVerdict` SUPERSET (`trulyCorrect`, `raw`) that is
81
- * structurally assignable to the `() => Promise<OracleVerdicts>` seam — without this defensive projection those
82
- * extra producer-internal fields would JSON.stringify straight into the emitted row's `oracle` block, drifting it
83
- * off s1.v1 and (worse) re-exporting the derived `trulyCorrect` the metric tool must RECOMPUTE and never trust.
84
- */
85
36
  export function pickOracleVerdicts(o) {
86
37
  return {
87
38
  delivered: o.delivered,
@@ -92,25 +43,12 @@ export function pickOracleVerdicts(o) {
92
43
  }
93
44
  const _rawRowIsRunRecord = true;
94
45
  void _rawRowIsRunRecord;
95
- /** Serialize a RawRow to one JSONL line (no trailing newline — the writer joins with "\n"). */
96
46
  export function rowToJsonl(row) {
97
47
  return JSON.stringify(row);
98
48
  }
99
- /** Serialize a batch of RawRows to a JSONL document (one row per line, trailing newline). */
100
49
  export function rowsToJsonl(rows) {
101
50
  return rows.map(rowToJsonl).join("\n") + (rows.length > 0 ? "\n" : "");
102
51
  }
103
- /**
104
- * 🔴 Wire the REAL design/95 metric tool. `buildReport` (core 1.111.0 `@sema-agent/core/bench`) is the
105
- * value-verdict JOIN: it SCORES only `scored` rows, GROUPS by `(suiteVersion, taskId, archetype, valueDimension,
106
- * arm)` (the Simpson guard), folds each cell, splits the withhold bucket by the counterfactual, and emits the
107
- * `ValueJudgmentReport` (groupedCells / comparisons / cells / pareto / excluded). A `RawRow[]` is assignable to its
108
- * `RunRecord[]` input (RawRow extends RunRecord), so the harness produces the verdict from its OWN rows with no
109
- * re-mapping — the metric definition lives in core, the producer only emits honest inputs.
110
- *
111
- * The live SOLO/SUP/TEAM run that GENERATES rows is clay-gated (expensive E2B+DeepSeek); this is purely the
112
- * CONSUME path (test-covered on synthetic conformant rows in test/s1-report.test.ts).
113
- */
114
52
  export function buildS1Report(rows, opts) {
115
53
  return buildReport(rows, opts);
116
54
  }
@@ -1,21 +1,3 @@
1
- /**
2
- * S1 value-verdict harness — the RESUMABLE FIRM-RUN DRIVER. SPEC-S1-value-harness.md §11 ("the human's post-step
3
- * that wires this scaffold into a runnable batch CLI"). Enumerates the firm cells {C1,C2,C4} × the arms each trap
4
- * declares × N seeds, runs each MISSING cell via `runArm` against a REAL `ProfileDeps` (live-deps.ts), records an
5
- * append-only JSONL LEDGER keyed by (taskId, arm, seed), and at the end builds the `ValueJudgmentReport` via
6
- * `buildS1Report`. The report IS the output — this driver never asserts which arm wins.
7
- *
8
- * 🔴 RESUMABLE (clay's hard requirement): on start the driver READS the ledger, builds the done-set, and runs ONLY
9
- * missing cells. A completed SCORED cell is NEVER re-run. A cell that throws / times out is recorded
10
- * `runStatus:"infra-failed"` (EXCLUDED from scoring, NOT a fake loss) AND left re-runnable on the next pass — so
11
- * a hang/crash mid-run resumes cleanly. Per-cell wall-clock timeout → kill the cell, mark infra-failed, move on.
12
- *
13
- * 🔴 --dry-run: a MOCK ProfileDeps (no E2B/DeepSeek) proves the driver loop + ledger + resume + buildReport work
14
- * DETERMINISTICALLY (this is what the test + CI exercise; the REAL run is the owner's gated step).
15
- *
16
- * 🔴 ENV GATING: the live path requires E2B_API_KEY + DEEPSEEK_API_KEY; absent → the driver refuses the live path
17
- * with a clear message (never a silent fake run). The deterministic --dry-run never needs keys.
18
- */
19
1
  import { promises as fs } from "node:fs";
20
2
  import path from "node:path";
21
3
  import { Runner, InMemoryCheckpointStore } from "@sema-agent/core";
@@ -25,14 +7,8 @@ import { makeBenchClock } from "./runner-ctx.js";
25
7
  import { buildS1Report, S1_SCHEMA_VERSION, S1_CORE_VERSION } from "./row.js";
26
8
  import { armTag } from "./row.js";
27
9
  import { buildLiveDeps, liveRuntimeConfigFromEnv } from "./live-deps.js";
28
- /** Enumerate the firm cells = FIRM_TRAPS × trap.arms × seeds. Optional `only` (trapId) / `arm` filters slice the
29
- * set for a controlled live run — a single-cell smoke (`--only C1 --arm solo --seeds 1`) before the full sweep, or
30
- * re-running one trap/arm. The ledger keys are unchanged, so a filtered run still resumes/merges into the same run. */
31
10
  export function enumerateCells(seeds, filter = {}) {
32
11
  const cells = [];
33
- // 🔴 default sweep = FIRM_TRAPS only (directional traps must NEVER enter a firm verdict). An explicit --only MAY
34
- // target a directional trap (e.g. C6 hazard) for a controlled make-real probe — its rows carry liveProof:directional
35
- // so buildReport still excludes them from the verdict; running it just produces the data to CONFIRM the hazard fires.
36
12
  const source = filter.only ? ALL_TRAPS : FIRM_TRAPS;
37
13
  for (const trap of source) {
38
14
  if (filter.only && trap.id !== filter.only)
@@ -47,12 +23,9 @@ export function enumerateCells(seeds, filter = {}) {
47
23
  }
48
24
  return cells;
49
25
  }
50
- /** A stable string key for a cell (the ledger dedupe key). */
51
26
  export function cellKeyStr(k) {
52
27
  return `${k.taskId}::${armTag(k.arm)}::${String(k.seed)}`;
53
28
  }
54
- /** Read the ledger, returning ALL records + the done-set of SCORED-or-otherwise-completed cell keys. A record with
55
- * `runStatus:"infra-failed"` is NOT in the done-set (it is re-runnable — the resume contract). */
56
29
  export async function readLedger(ledgerPath) {
57
30
  let raw;
58
31
  try {
@@ -72,14 +45,12 @@ export async function readLedger(ledgerPath) {
72
45
  rec = JSON.parse(t);
73
46
  }
74
47
  catch {
75
- continue; // a torn final line from a crash mid-write — skip it (the cell stays re-runnable)
48
+ continue;
76
49
  }
77
50
  records.push(rec);
78
- // A cell is "done" (never re-run) ONLY when it is a completed scored/excluded-but-final row. An infra-failed
79
- // row is re-runnable, so it does NOT enter the done-set. (The LAST record for a key wins on re-aggregation.)
80
51
  const key = cellKeyStr({ taskId: rec.taskId, arm: armUpper(rec.arm), seed: rec.seed ?? 0 });
81
52
  if (rec.runStatus === "infra-failed") {
82
- done.delete(key); // a later successful re-run supersedes; an infra-failed alone keeps it runnable
53
+ done.delete(key);
83
54
  }
84
55
  else {
85
56
  done.add(key);
@@ -87,7 +58,6 @@ export async function readLedger(ledgerPath) {
87
58
  }
88
59
  return { records, done };
89
60
  }
90
- /** Map the lowercase wire tag back to the internal uppercase Arm. */
91
61
  function armUpper(tag) {
92
62
  switch (tag) {
93
63
  case "solo":
@@ -97,18 +67,13 @@ function armUpper(tag) {
97
67
  case "team":
98
68
  return "TEAM";
99
69
  default:
100
- // 🔴 fail-loud (review council DESIGN#1): `tag` comes from a parsed JSONL ledger line, so a corrupt/unknown arm
101
- // would otherwise produce an `undefined` cellKeyStr → silent dedup poisoning. A bad ledger row must throw, not
102
- // collapse two cells onto one undefined key.
103
70
  throw new Error(`s1 run-firm: unknown arm tag ${JSON.stringify(tag)} in ledger row (expected solo|sup|team)`);
104
71
  }
105
72
  }
106
- /** Append one record to the ledger (atomic-ish: one write of one line + newline). */
107
73
  async function appendLedger(ledgerPath, rec) {
108
74
  await fs.mkdir(path.dirname(ledgerPath), { recursive: true });
109
75
  await fs.appendFile(ledgerPath, JSON.stringify(rec) + "\n", "utf8");
110
76
  }
111
- /** Run a promise with a wall-clock timeout. Rejects with a timeout error on expiry (the caller marks infra-failed). */
112
77
  function withTimeout(p, ms, label) {
113
78
  return new Promise((resolve, reject) => {
114
79
  const timer = setTimeout(() => reject(new Error(`cell timeout after ${ms}ms (${label})`)), ms);
@@ -122,7 +87,6 @@ function withTimeout(p, ms, label) {
122
87
  });
123
88
  });
124
89
  }
125
- /** Build an infra-failed RawRow for a cell that threw/timed out (EXCLUDED, NOT a fake loss; re-runnable). */
126
90
  function infraFailedRow(cell, ctx) {
127
91
  const now = ctx.clock.now();
128
92
  return {
@@ -141,13 +105,9 @@ function infraFailedRow(cell, ctx) {
141
105
  humanReview: { count: 0, totalWaitMs: 0, gates: [] },
142
106
  },
143
107
  wallTimeSec: 0,
144
- meta: { startedAt: now, finishedAt: now, coreVersion: S1_CORE_VERSION, gitSha: ctx.gitSha, runId: ctx.runId }, // L16:动态读装机 core 版本(硬钉曾漂到 1.111.0)
108
+ meta: { startedAt: now, finishedAt: now, coreVersion: S1_CORE_VERSION, gitSha: ctx.gitSha, runId: ctx.runId },
145
109
  };
146
110
  }
147
- /**
148
- * Run the firm batch. Returns the final `ValueJudgmentReport` (also written to `reportPath`). Resumable: re-running
149
- * continues where it stopped, never re-running a completed scored cell.
150
- */
151
111
  export async function runFirm(opts) {
152
112
  const seeds = opts.seeds ?? 5;
153
113
  if (!Number.isInteger(seeds) || seeds < 1)
@@ -186,23 +146,16 @@ export async function runFirm(opts) {
186
146
  }
187
147
  await appendLedger(opts.ledgerPath, row);
188
148
  ranThisPass++;
189
- // Only a non-infra-failed row enters the done-set (an infra-failed cell stays re-runnable on the next pass).
190
149
  if (row.runStatus !== "infra-failed")
191
150
  done.add(key);
192
151
  log("cell_done", { key, runStatus: row.runStatus });
193
152
  }
194
- // Final pass: load ALL ledger rows, de-dupe to the LAST record per key (a re-run supersedes an earlier
195
- // infra-failed), build the report.
196
153
  const { records } = await readLedger(opts.ledgerPath);
197
154
  const lastByKey = new Map();
198
155
  for (const rec of records) {
199
156
  lastByKey.set(cellKeyStr({ taskId: rec.taskId, arm: armUpper(rec.arm), seed: rec.seed ?? 0 }), rec);
200
157
  }
201
158
  const allRows = [...lastByKey.values()];
202
- // 🔴 (review HIGH finding) the firm report is FIRM_TRAPS rows ONLY. A directional probe (C6/C7) can share a ledger
203
- // via --only, and buildReport does NOT filter by liveProof — an unfiltered call would let directional rows
204
- // pollute the firm comparisons/pareto. Filter to firm taskIds here (directional rows stay in the ledger for
205
- // separate analysis); a directional probe should also use its own --run-id to keep ledgers cleanly separate.
206
159
  const firmIds = new Set(FIRM_TRAPS.map((t) => t.id));
207
160
  const rows = allRows.filter((r) => firmIds.has(r.taskId));
208
161
  const report = buildS1Report(rows);
@@ -212,21 +165,13 @@ export async function runFirm(opts) {
212
165
  const excluded = rows.length - scored;
213
166
  return { report, scored, excluded, ranThisPass };
214
167
  }
215
- /** Build a live cell or throw a clear message if the live runtime is missing (env gating). */
216
168
  function buildLiveCellOrThrow(opts, trap, seed, cellId) {
217
169
  if (!opts.liveRuntime) {
218
170
  throw new Error("S1 run-firm: live path requires E2B_API_KEY + DEEPSEEK_API_KEY (the brain gateway). None resolved — refusing a silent fake run. Use --dry-run for the deterministic loop, or set the keys for the owner's gated live run.");
219
171
  }
220
172
  return buildLiveDeps(opts.liveRuntime, trap, seed, cellId);
221
173
  }
222
- // ─────────────────────────────── CLI ───────────────────────────────
223
- /** The default shared budget (the §3.2 fairness root). Overridable via CLI flags. */
224
174
  function defaultBudget(modelId) {
225
- // 🔴 maxTokens is a GENEROUS safety net, NOT the binding gate (clay: budget unlimited). The 1-cell live smoke caught
226
- // that maxTokens:8000 capped EVERY run "failed" → infra-failed → nothing ever scored: the token counter includes
227
- // CACHED tokens (97% cache hit), so a single verify round over repo context blew 8000 while real cost was ~$0. The
228
- // real, FAIR economic gate is maxCostUsd + maxTurns (uniform across all arms); maxTokens just must not bind before
229
- // them. 200k comfortably fits ~12 turns of verify→fix with repo context; cost stays the measured economic axis.
230
175
  return { modelId, maxTokens: 200_000, maxCostUsd: 1.0, maxTurns: 12, maxRounds: 2, supAutoBudget: 1 };
231
176
  }
232
177
  function parseArgs(argv) {
@@ -235,9 +180,6 @@ function parseArgs(argv) {
235
180
  return i >= 0 && i + 1 < argv.length ? argv[i + 1] : undefined;
236
181
  };
237
182
  const runId = get("run-id") ?? `s1-firm-${Date.now()}`;
238
- // --seeds / --cell-timeout-ms: explicit positive-integer validation (NOT a `|| default` truthy coercion, which
239
- // silently turns `--seeds 0` into 5 and lets `--seeds -1` enumerate ZERO cells = a silent empty run). Absent flag
240
- // → default; present-but-invalid → a clear error + non-zero exit (never a silently-coerced batch).
241
183
  const seeds = positiveIntArg(get("seeds"), 5, "--seeds");
242
184
  const cellTimeoutMs = positiveIntArg(get("cell-timeout-ms"), 15 * 60_000, "--cell-timeout-ms");
243
185
  return {
@@ -251,8 +193,6 @@ function parseArgs(argv) {
251
193
  ...(get("arm") ? { arm: get("arm") } : {}),
252
194
  };
253
195
  }
254
- /** Parse a CLI flag as a positive integer; default when the flag is absent; exit(2) on a present-but-invalid value
255
- * (0, negative, NaN, fractional) rather than silently coercing it. */
256
196
  export function positiveIntArg(raw, def, flag) {
257
197
  if (raw === undefined)
258
198
  return def;
@@ -263,15 +203,13 @@ export function positiveIntArg(raw, def, flag) {
263
203
  }
264
204
  return n;
265
205
  }
266
- /** The mock deps factory for --dry-run: a deterministic LiveCell (no E2B/DeepSeek). Per-cell deterministic by seed. */
267
206
  function dryRunMockFactory() {
268
207
  return (trap, seed) => {
269
- // A deterministic stats fixture + a deterministic oracle keyed on the trap (C2 = impossible-spec → not green).
270
208
  const stats = {
271
209
  costBreakdown: { llmRootMicroUsd: 50_000, nestedSubagentMicroUsd: 0, memoryConsolidationMicroUsd: 0, compactionMicroUsd: 0 },
272
210
  humanReview: { count: 0, totalWaitMs: 0, gates: [] },
273
211
  };
274
- const green = trap.id !== "C2-honest-bound"; // C2's contradiction can never be objectively correct
212
+ const green = trap.id !== "C2-honest-bound";
275
213
  const oracle = { delivered: true, hiddenTestsGreen: green, buildPassed: true, invariantsOk: true };
276
214
  const vr = {
277
215
  taskId: trap.id,
@@ -294,7 +232,6 @@ function dryRunMockFactory() {
294
232
  return { deps, dispose: async () => { } };
295
233
  };
296
234
  }
297
- /** CLI entry. */
298
235
  export async function main(argv = process.argv.slice(2)) {
299
236
  const args = parseArgs(argv);
300
237
  const liveRuntime = liveRuntimeConfigFromEnv();
@@ -335,8 +272,6 @@ export async function main(argv = process.argv.slice(2)) {
335
272
  directionalOnly: result.report.directionalOnly,
336
273
  }, null, 2));
337
274
  }
338
- // Run as a CLI when invoked directly (not when imported by the test). `import.meta.url` guard keeps the module
339
- // import-safe for the deterministic test.
340
275
  const isMain = (() => {
341
276
  try {
342
277
  return typeof process !== "undefined" && Array.isArray(process.argv) && /run-firm(\.[jt]s)?$/.test(process.argv[1] ?? "");
@@ -351,7 +286,6 @@ if (isMain) {
351
286
  process.exit(1);
352
287
  });
353
288
  }
354
- // Re-export the live wiring for the owner's gated run + the test.
355
289
  export { buildLiveDeps, liveRuntimeConfigFromEnv } from "./live-deps.js";
356
290
  export { Runner };
357
291
  //# sourceMappingURL=run-firm.js.map
@@ -1,22 +1,3 @@
1
- /**
2
- * S1 value-verdict harness — the FAIRNESS ROOT (SPEC-S1-value-harness.md §2). ONE place constructs the shared
3
- * Runner ingredients (config / brain / pricing), the SAME budget for every arm, and the injected deterministic
4
- * clock that makes C2 (human-review wall-time) reproducible.
5
- *
6
- * 🔴 THE §3.2 RED LINE (design/89's #1 confound): every leaf TaskSpec across all 3 arms carries the SAME
7
- * `limits.{ maxTokens, maxCostUsd, maxTurns }` (core ≥5.8: budget keys live ONLY in `limits` — a top-level
8
- * `maxTokens`/`maxCostUsd` is a silently-unread dead key), and TEAM's per-worker budgets sum to ≤ the solo budget — so no
9
- * arm can win on a bigger pie. `assertBudgetMatch` (below) is the build-time guard the shape test runs.
10
- *
11
- * 🔴 BUDGET-MATCH for TEAM is NEW WIRING the live conflict test does NOT do: `leader-conflict-resolver-live.test.ts`
12
- * sets NO budget on `SubtaskSpec.spec` and NO `now` on any Runner. The harness STAMPS both (arms.ts) — copying the
13
- * live test verbatim would yield an unbounded TEAM (the confound) and an empty `humanReview` (C2 = undefined).
14
- *
15
- * The real-infra construction (E2B worker/grader envs + a live brain) is deferred to the live make-real proof
16
- * (`test/s1-value-live.test.ts`, gated on E2B+DEEPSEEK). This module only fixes the SHAPE + the budget invariant
17
- * + the clock; a deterministic shape test exercises it with a MOCK runner (no real agents, no keys).
18
- */
19
- /** Project the producer's shared budget (+ an optional TEAM worker-sum) into a `RowBudget` for the fairness guard. */
20
1
  export function budgetDescriptor(budget, arm, teamWorkerBudgetSumUsd) {
21
2
  return {
22
3
  modelId: budget.modelId,
@@ -28,7 +9,6 @@ export function budgetDescriptor(budget, arm, teamWorkerBudgetSumUsd) {
28
9
  ...(arm === "TEAM" && teamWorkerBudgetSumUsd !== undefined ? { teamWorkerBudgetSumUsd } : {}),
29
10
  };
30
11
  }
31
- /** Construct the deterministic clock used to model C2 review seconds (no real wall-time advance). */
32
12
  export function makeBenchClock(startEpochMs = Date.now()) {
33
13
  let t = startEpochMs;
34
14
  return {
@@ -40,15 +20,6 @@ export function makeBenchClock(startEpochMs = Date.now()) {
40
20
  },
41
21
  };
42
22
  }
43
- /**
44
- * Apply the shared budget to a leaf TaskSpec-like object (SOLO impl, SUP impl, each TEAM `SubtaskSpec.spec`).
45
- * Returns the budget fields to spread onto the spec — kept as a helper so EVERY leaf is stamped identically
46
- * (the live tests forget this for TEAM workers — the confound). `maxCostUsd` is overridable for the TEAM
47
- * per-worker split (Σ ≤ solo, enforced by `assertBudgetMatch`).
48
- *
49
- * 🔴 ALL THREE keys live under `limits` — core ≥5.8 reads `maxTokens`/`maxCostUsd` ONLY from `TaskSpec.limits`;
50
- * a top-level key is DEAD (silently unread — the cost/token gates never bind).
51
- */
52
23
  export function leafBudgetFields(budget, overrideMaxCostUsd) {
53
24
  return {
54
25
  limits: {
@@ -58,17 +29,8 @@ export function leafBudgetFields(budget, overrideMaxCostUsd) {
58
29
  },
59
30
  };
60
31
  }
61
- /**
62
- * BUDGET-MATCH build-time guard (the §3.2 red line — run by the shape test). FAILS if, within a task class:
63
- * (a) any arm's `{ modelId, maxTokens, maxCostUsd, maxTurns, maxRounds }` differs, OR
64
- * (b) a TEAM row's `teamWorkerBudgetSumUsd` exceeds `maxCostUsd` (the bigger-pie confound).
65
- *
66
- * Pure over the rows' `budget` blocks (so it works on emitted RawRows AND on a pre-flight check). Returns the
67
- * list of violations (empty = OK) so the caller can assert it.
68
- */
69
32
  export function assertBudgetMatch(rows) {
70
33
  const violations = [];
71
- // Group by task class (here: taskId — each trap is its own class for the budget invariant).
72
34
  const byTask = new Map();
73
35
  for (const r of rows) {
74
36
  const g = byTask.get(r.taskId) ?? [];
@@ -84,7 +46,6 @@ export function assertBudgetMatch(rows) {
84
46
  violations.push(`budget-match: task ${taskId} arm ${r.arm} ${k}=${String(b[k])} != ${r.arm === group[0].arm ? "" : `${group[0].arm} `}${String(ref[k])}`);
85
47
  }
86
48
  }
87
- // (b) TEAM bigger-pie guard: Σ per-worker budget must not exceed the shared per-arm maxCostUsd.
88
49
  if (b.teamWorkerBudgetSumUsd !== undefined && b.teamWorkerBudgetSumUsd > b.maxCostUsd + 1e-9) {
89
50
  violations.push(`budget-match: task ${taskId} arm ${r.arm} teamWorkerBudgetSumUsd=${b.teamWorkerBudgetSumUsd} > maxCostUsd=${b.maxCostUsd} (bigger-pie confound)`);
90
51
  }
@@ -92,7 +53,6 @@ export function assertBudgetMatch(rows) {
92
53
  }
93
54
  return violations;
94
55
  }
95
- /** Assert two execution envs are DISTINCT objects (the §5.1 anti-reward-hack precondition). Throws if same. */
96
56
  export function assertDistinctEnvs(workerEnv, graderEnv) {
97
57
  if (workerEnv === graderEnv) {
98
58
  throw new Error("S1 oracle: graderEnv === workerEnv — the anti-reward-hack identity check would fail closed (oracle.unprotected). The grader MUST be a distinct env (decorrelation + the repair-loop §5.1 boundary).");