@tangle-network/agent-bench 0.1.0 → 0.3.5

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 (139) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/HARNESS.md +302 -0
  3. package/README.md +26 -1
  4. package/fixtures/aec-bench.json +18 -0
  5. package/fixtures/agentbench-dbbench.json +22 -0
  6. package/fixtures/bfcl.json +45 -0
  7. package/fixtures/commit0.json +72 -0
  8. package/fixtures/crag.json +10 -0
  9. package/fixtures/dabstep.json +22 -0
  10. package/fixtures/enterpriseops-gym.json +103 -0
  11. package/fixtures/finresearchbench.json +21 -0
  12. package/fixtures/finsearchcomp.json +66 -0
  13. package/fixtures/frames.json +26 -0
  14. package/fixtures/hotpotqa.json +182 -0
  15. package/fixtures/nomiracl.json +26 -0
  16. package/fixtures/open-rag-bench.json +16 -0
  17. package/fixtures/pier-agent/no-model-task/environment/Dockerfile +16 -0
  18. package/fixtures/pier-agent/no-model-task/environment/seed/src/status.txt +1 -0
  19. package/fixtures/pier-agent/no-model-task/instruction.md +6 -0
  20. package/fixtures/pier-agent/no-model-task/pre_artifacts.sh +6 -0
  21. package/fixtures/pier-agent/no-model-task/task.toml +35 -0
  22. package/fixtures/pier-agent/no-model-task/tests/Dockerfile +17 -0
  23. package/fixtures/pier-agent/no-model-task/tests/seed/src/status.txt +1 -0
  24. package/fixtures/pier-agent/no-model-task/tests/test.sh +19 -0
  25. package/fixtures/programbench.json +17 -0
  26. package/fixtures/ragbench.json +21 -0
  27. package/fixtures/simpleqa.json +121 -0
  28. package/fixtures/t2-ragbench.json +13 -0
  29. package/fixtures/tau2-bench.json +16 -0
  30. package/fixtures/tau3-banking.json +16 -0
  31. package/fixtures/toollm.json +28 -0
  32. package/fixtures/webarena-verified.json +20 -0
  33. package/package.json +39 -15
  34. package/pier_agents/__init__.py +18 -0
  35. package/pier_agents/candidate_contract.py +755 -0
  36. package/pier_agents/process_boundary.py +321 -0
  37. package/pier_agents/tangle_candidate.py +907 -0
  38. package/pier_agents/workspace_boundary.py +368 -0
  39. package/scripts/appworld_driver.py +359 -0
  40. package/scripts/cadbench_prepare.py +22 -0
  41. package/scripts/cadgenbench_hard_parts.py +48 -0
  42. package/scripts/clbench_codebase_judge.py +73 -0
  43. package/scripts/commit0_judge.py +170 -0
  44. package/scripts/dabstep_judge.py +42 -0
  45. package/scripts/enterpriseops_gym_judge.py +281 -0
  46. package/scripts/programbench_judge.py +120 -0
  47. package/scripts/render-gate-chart.mjs +176 -0
  48. package/scripts/run-package-tests.mjs +56 -0
  49. package/scripts/terminate-pier-trial.mts +66 -0
  50. package/scripts/trata-hedge/README.md +56 -0
  51. package/scripts/trata-hedge/run.sh +60 -0
  52. package/scripts/trata-hedge/solve.py +83 -0
  53. package/scripts/verify-packed-consumer.mjs +224 -0
  54. package/scripts/verify-pier-agent.mts +715 -0
  55. package/scripts/verify-pier-pair.mts +74 -0
  56. package/scripts/verify-pier-recovery.mts +139 -0
  57. package/src/adapters.ts +26 -0
  58. package/src/benchmarks/_harness.test.mts +178 -0
  59. package/src/benchmarks/_harness.ts +239 -16
  60. package/src/benchmarks/agentbench.ts +163 -0
  61. package/src/benchmarks/appworld.test.mts +15 -9
  62. package/src/benchmarks/bfcl.ts +346 -0
  63. package/src/benchmarks/crag.ts +137 -0
  64. package/src/benchmarks/dabstep.test.mts +70 -0
  65. package/src/benchmarks/dabstep.ts +212 -0
  66. package/src/benchmarks/external-adapters.test.mts +150 -0
  67. package/src/benchmarks/finresearchbench.ts +269 -0
  68. package/src/benchmarks/humaneval.ts +20 -8
  69. package/src/benchmarks/nomiracl.ts +180 -0
  70. package/src/benchmarks/open-rag-bench.ts +153 -0
  71. package/src/benchmarks/rag-benchmarks.test.mts +138 -0
  72. package/src/benchmarks/rag-shared.ts +327 -0
  73. package/src/benchmarks/ragbench.ts +171 -0
  74. package/src/benchmarks/swe-bench.test.mts +61 -0
  75. package/src/benchmarks/swe-bench.ts +201 -19
  76. package/src/benchmarks/t2-ragbench.ts +166 -0
  77. package/src/benchmarks/tau-bench-shared.ts +214 -0
  78. package/src/benchmarks/tau2-bench.ts +30 -0
  79. package/src/benchmarks/tau3-banking.ts +29 -0
  80. package/src/benchmarks/terminal-bench.test.mts +33 -0
  81. package/src/benchmarks/terminal-bench.ts +23 -8
  82. package/src/benchmarks/toollm.ts +254 -0
  83. package/src/benchmarks/types.ts +42 -0
  84. package/src/benchmarks/webarena-verified.ts +200 -0
  85. package/src/commit0-prereqs.sh +0 -0
  86. package/src/coordination-mcp-container-reach.mts +181 -0
  87. package/src/decoder-live.mts +1 -1
  88. package/src/examples/README.md +103 -39
  89. package/src/examples/benchmark-matrix.mts +101 -0
  90. package/src/examples/lean-proof-gate.README.md +77 -0
  91. package/src/examples/lean-proof-gate.mts +162 -0
  92. package/src/examples/lean-verify.ts +95 -0
  93. package/src/examples/lean.Dockerfile +12 -0
  94. package/src/examples/math-demo.mts +9 -7
  95. package/src/examples/strategy-demo.mts +10 -12
  96. package/src/gate.ts +3 -2
  97. package/src/hev-eval.mts +69 -0
  98. package/src/hev-improve.mts +169 -0
  99. package/src/hev-structural.mts +688 -0
  100. package/src/index.ts +73 -0
  101. package/src/mbpp-structural.mts +662 -0
  102. package/src/pier-agent.test-fixtures.mts +19 -0
  103. package/src/pier-agent.test.mts +363 -0
  104. package/src/pier-agent.ts +657 -0
  105. package/src/pier-result-grader.mjs +30 -0
  106. package/src/pier-result-grader.test.mts +62 -0
  107. package/src/pier-result-grader.ts +108 -0
  108. package/src/pier-task-outcome.test.mts +117 -0
  109. package/src/pier-task-outcome.ts +240 -0
  110. package/src/pier-trial-controller.test.mts +412 -0
  111. package/src/pier-trial-controller.ts +858 -0
  112. package/src/pier-trial-supervisor.mjs +352 -0
  113. package/src/resolve-client.ts +25 -2
  114. package/src/run-benchmarks-cli.mts +72 -0
  115. package/src/run-benchmarks-report.ts +66 -0
  116. package/src/run-benchmarks.test.mts +231 -0
  117. package/src/run-benchmarks.ts +589 -0
  118. package/src/smoke-structural-rollout.mts +393 -0
  119. package/src/swe-bench-env.test.ts +207 -0
  120. package/src/swe-bench-env.ts +554 -0
  121. package/src/swe-jail.ts +293 -0
  122. package/src/swe-self-improve.mts +84 -0
  123. package/src/swe-structural-judge-policy.test.ts +117 -0
  124. package/src/swe-structural-judge-policy.ts +133 -0
  125. package/src/swe-structural-policy.test.ts +124 -0
  126. package/src/swe-structural-policy.ts +132 -0
  127. package/src/swe-structural-provenance.test.ts +93 -0
  128. package/src/swe-structural-provenance.ts +138 -0
  129. package/src/swe-structural.mts +1260 -0
  130. package/src/swe-temp.ts +14 -0
  131. package/src/tb-container-executor.mts +234 -0
  132. package/src/tb-container-executor.test.mts +99 -0
  133. package/src/tb-supervisor-sidecar.mts +222 -0
  134. package/src/trata-gepa.mts +1 -1
  135. package/steerers/eops-itsm-population.json +1 -0
  136. package/tb_agents/opencode_refine_agent.py +117 -0
  137. package/tb_agents/opencode_router_agent.py +406 -0
  138. package/tb_agents/opencode_supervisor_agent.py +239 -0
  139. package/tb_agents/script_agent.py +66 -0
@@ -0,0 +1,1260 @@
1
+ /**
2
+ * Two-session SWE-bench experiment with generation and official scoring split into separate modes.
3
+ *
4
+ * MODE=generate requires EXPERIMENT_ARM=independent-2|persistent-refine-2 and writes only Phase A.
5
+ * The independent arm runs two fresh attempts. The persistent arm runs one attempt and one fresh
6
+ * continuation with attempt one's cumulative patch pre-applied. Both use the same run-capable tools,
7
+ * prompt, temperature, two worker sessions, and later-on-visible-tie selection rule. Per-row hashes
8
+ * bind source, config, reproduction, prompt, tools, task, parent patch, and final patch.
9
+ *
10
+ * MODE=judge-only requires INDEPENDENT_PHASE_A, PERSISTENT_PHASE_A, and a distinct OUT. It validates
11
+ * both complete Phase-A files and every paired fingerprint before the first serialized official score.
12
+ *
13
+ * Generate env: ZAI_API_KEY, REPRO_MANIFEST, IDS, OUT, MODEL, ZAI_BASE, MAX_TOKENS, TEMPERATURE,
14
+ * INNER_TURNS, CONC, REPRO_TIMEOUT, LLM_TIMEOUT_MS, SWE_RUN_TIMEOUT, SWE_RUN_OUTPUT_LIMIT,
15
+ * PRICE_IN, PRICE_OUT. Judge env: INDEPENDENT_PHASE_A, PERSISTENT_PHASE_A, OUT.
16
+ */
17
+ import { execFile } from 'node:child_process'
18
+ import { appendFileSync, existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
19
+ import { join, relative } from 'node:path'
20
+ import { fileURLToPath } from 'node:url'
21
+ import { promisify } from 'node:util'
22
+ import type { AgenticSurface, AgenticTask, ArtifactHandle, SurfaceScore } from '@tangle-network/agent-runtime/loops'
23
+ import { refine, runAgentic } from '@tangle-network/agent-runtime/loops'
24
+ import type { BenchTask } from './benchmarks/types'
25
+ import {
26
+ createSweBenchEnvironment,
27
+ resolveImageForMetadata,
28
+ resolveSweBenchScorerVersion,
29
+ SWE_RUN_TOOL_CONFIG,
30
+ SWE_SEED_PROMPT_WITH_RUN,
31
+ type SweImageIdentity,
32
+ } from './swe-bench-env'
33
+ import {
34
+ APPLY_SENTINEL,
35
+ assertNoHiddenLeak,
36
+ cachedInstanceIds,
37
+ IMPORT_NAME,
38
+ importCanaryScript,
39
+ runPyInJail,
40
+ tail,
41
+ zaiChatRaw,
42
+ } from './swe-jail'
43
+ import {
44
+ type ExperimentArm,
45
+ type ExperimentArmPreset,
46
+ assertExactCompletedWorkerSessions,
47
+ continuationDisposition,
48
+ continuationStateNotice,
49
+ preferLaterCandidate,
50
+ resolveExperimentArm,
51
+ resolveExperimentTemperature,
52
+ shouldAcceptContinuation,
53
+ shouldRunContinuation,
54
+ } from './swe-structural-policy'
55
+ import {
56
+ assertFingerprintsEqual,
57
+ createExecutionReceipt,
58
+ createFingerprints,
59
+ diffChanged,
60
+ diffFingerprint,
61
+ fingerprint,
62
+ runtimeImplementationFingerprint,
63
+ type ExecutionReceipt,
64
+ type Fingerprints,
65
+ type SharedExecutionReceipt,
66
+ } from './swe-structural-provenance'
67
+ import {
68
+ assertCompleteTaskSet,
69
+ assertDistinctArtifactPaths,
70
+ assertJudgeCompletionMatchesInput,
71
+ assertJudgeResumeFingerprints,
72
+ assertPairedExecutionFingerprint,
73
+ assertPairedFingerprints,
74
+ completeJudgeScore,
75
+ } from './swe-structural-judge-policy'
76
+
77
+ const exec = promisify(execFile)
78
+ const TEMPERATURE = resolveExperimentTemperature(process.env)
79
+
80
+ function sourceTreeReceipt(
81
+ rootUrl: URL,
82
+ label: string,
83
+ include: (path: string) => boolean,
84
+ ): Array<{ name: string; content: string }> {
85
+ const root = fileURLToPath(rootUrl)
86
+ const receipt: Array<{ name: string; content: string }> = []
87
+ const visit = (dir: string): void => {
88
+ for (const entry of readdirSync(dir, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name))) {
89
+ const path = join(dir, entry.name)
90
+ if (entry.isDirectory()) visit(path)
91
+ else if (entry.isFile() && include(path)) {
92
+ receipt.push({ name: `${label}/${relative(root, path)}`, content: readFileSync(path, 'utf8') })
93
+ }
94
+ }
95
+ }
96
+ visit(root)
97
+ return receipt
98
+ }
99
+
100
+ // ---------- config ----------
101
+
102
+ type Mode = 'generate' | 'judge-only'
103
+ const MODE_INPUT = process.env.MODE ?? 'generate'
104
+ if (MODE_INPUT !== 'generate' && MODE_INPUT !== 'judge-only') {
105
+ throw new Error(`MODE must be generate|judge-only, got "${MODE_INPUT}"`)
106
+ }
107
+ const MODE: Mode = MODE_INPUT
108
+ const OFFICIAL_SCORER_CACHE_LEVEL = 'instance' as const
109
+ if (
110
+ MODE === 'judge-only' &&
111
+ process.env.SWEBENCH_CACHE_LEVEL !== undefined &&
112
+ process.env.SWEBENCH_CACHE_LEVEL !== OFFICIAL_SCORER_CACHE_LEVEL
113
+ ) {
114
+ throw new Error('MODE=judge-only requires SWEBENCH_CACHE_LEVEL=instance')
115
+ }
116
+ if (MODE === 'judge-only') process.env.SWEBENCH_CACHE_LEVEL = OFFICIAL_SCORER_CACHE_LEVEL
117
+ for (const legacy of ['ARM', 'ARM_NAME', 'K', 'REPAIRS', 'FORCE_TWO_SESSIONS', 'SOLO_TEMP', 'SKIP_JUDGE']) {
118
+ if (process.env[legacy] !== undefined) {
119
+ throw new Error(`${legacy} is not supported; use typed EXPERIMENT_ARM plus MODE=generate|judge-only`)
120
+ }
121
+ }
122
+ const ARM_PRESET: ExperimentArmPreset | null = MODE === 'generate'
123
+ ? resolveExperimentArm(process.env.EXPERIMENT_ARM ?? '')
124
+ : null
125
+ const ZAI_BASE = process.env.ZAI_BASE ?? 'https://api.z.ai/api/coding/paas/v4'
126
+ const ZAI_KEY = process.env.ZAI_API_KEY ?? ''
127
+ if (MODE === 'generate' && !ZAI_KEY) throw new Error('ZAI_API_KEY required for MODE=generate')
128
+ const MODEL = process.env.MODEL ?? 'glm-5.2'
129
+ // glm-5.2 is a reasoning model: hidden reasoning consumes max_tokens, so <8000 starves content.
130
+ const MAX_TOKENS = Number(process.env.MAX_TOKENS ?? 12_000)
131
+ const INNER_TURNS = Number(process.env.INNER_TURNS ?? 40)
132
+ const CONC = Math.max(1, Math.min(4, Number(process.env.CONC ?? 2)))
133
+ const REPRO_TIMEOUT_S = Number(process.env.REPRO_TIMEOUT ?? 120)
134
+ const LLM_TIMEOUT_MS = Number(process.env.LLM_TIMEOUT_MS ?? 480_000)
135
+ // Cost-table rates, USD per Mtok. ASSUMED (zai coding-plan tokens have no per-call list price);
136
+ // override with PRICE_IN/PRICE_OUT. The summary labels them as assumed.
137
+ const PRICE_IN = Number(process.env.PRICE_IN ?? 0.6)
138
+ const PRICE_OUT = Number(process.env.PRICE_OUT ?? 2.2)
139
+
140
+ interface ReproManifestEntry {
141
+ script: string
142
+ source: string
143
+ stage0Class: string
144
+ }
145
+
146
+ const MANIFEST: Record<string, ReproManifestEntry> = (() => {
147
+ if (MODE !== 'generate') return {}
148
+ const p = process.env.REPRO_MANIFEST
149
+ if (!p) throw new Error('REPRO_MANIFEST required for MODE=generate')
150
+ return JSON.parse(readFileSync(p, 'utf8')) as Record<string, ReproManifestEntry>
151
+ })()
152
+
153
+ interface CommonConfigReceipt {
154
+ schema: 'swe-structural-v2'
155
+ model: string
156
+ zaiBase: string
157
+ maxTokens: number
158
+ temperature: number
159
+ innerTurns: number
160
+ concurrency: number
161
+ reproTimeoutS: number
162
+ llmTimeoutMs: number
163
+ sweRunTimeoutS: number
164
+ sweRunOutputLimit: number
165
+ runTool: true
166
+ seedPrompt: 'SWE_SEED_PROMPT_WITH_RUN'
167
+ taskIds: string[]
168
+ }
169
+
170
+ interface ExperimentConfigReceipt extends CommonConfigReceipt {
171
+ arm: ExperimentArm
172
+ k: 1 | 2
173
+ repairs: 0 | 1
174
+ alwaysRunContinuation: boolean
175
+ persistent: boolean
176
+ workerSessions: 2
177
+ }
178
+
179
+ const SOURCE_RECEIPT = [
180
+ ['swe-structural.mts', new URL('./swe-structural.mts', import.meta.url)],
181
+ ['swe-structural-policy.ts', new URL('./swe-structural-policy.ts', import.meta.url)],
182
+ ['swe-structural-provenance.ts', new URL('./swe-structural-provenance.ts', import.meta.url)],
183
+ ['swe-structural-judge-policy.ts', new URL('./swe-structural-judge-policy.ts', import.meta.url)],
184
+ ['swe-bench-env.ts', new URL('./swe-bench-env.ts', import.meta.url)],
185
+ ['swe-jail.ts', new URL('./swe-jail.ts', import.meta.url)],
186
+ ['swe-temp.ts', new URL('./swe-temp.ts', import.meta.url)],
187
+ ['benchmarks/swe-bench.ts', new URL('./benchmarks/swe-bench.ts', import.meta.url)],
188
+ ['benchmarks/_harness.ts', new URL('./benchmarks/_harness.ts', import.meta.url)],
189
+ ['runtime/strategy.ts', new URL('../../src/runtime/strategy.ts', import.meta.url)],
190
+ ].map(([name, url]) => ({ name: String(name), content: readFileSync(url as URL, 'utf8') }))
191
+
192
+ const RUNTIME_IMPLEMENTATION_FINGERPRINT = runtimeImplementationFingerprint({ runAgentic, refine })
193
+ const RUNTIME_TREE_FINGERPRINT = fingerprint([
194
+ ...sourceTreeReceipt(new URL('../../src/', import.meta.url), 'agent-runtime/src', (path) => path.endsWith('.ts')),
195
+ ...sourceTreeReceipt(
196
+ new URL('../../node_modules/@tangle-network/agent-eval/dist/', import.meta.url),
197
+ 'agent-eval/dist',
198
+ (path) => path.endsWith('.js'),
199
+ ),
200
+ {
201
+ name: 'agent-runtime/package.json',
202
+ content: readFileSync(new URL('../../package.json', import.meta.url), 'utf8'),
203
+ },
204
+ {
205
+ name: 'agent-runtime/pnpm-lock.yaml',
206
+ content: readFileSync(new URL('../../pnpm-lock.yaml', import.meta.url), 'utf8'),
207
+ },
208
+ {
209
+ name: 'agent-eval/package.json',
210
+ content: readFileSync(new URL('../../node_modules/@tangle-network/agent-eval/package.json', import.meta.url), 'utf8'),
211
+ },
212
+ ])
213
+
214
+ function makeExperimentConfig(preset: ExperimentArmPreset, taskIds: string[]): ExperimentConfigReceipt {
215
+ return {
216
+ schema: 'swe-structural-v2',
217
+ arm: preset.arm,
218
+ k: preset.k,
219
+ repairs: preset.repairs,
220
+ alwaysRunContinuation: preset.alwaysRunContinuation,
221
+ persistent: preset.persistent,
222
+ workerSessions: preset.workerSessions,
223
+ model: MODEL,
224
+ zaiBase: ZAI_BASE,
225
+ maxTokens: MAX_TOKENS,
226
+ temperature: TEMPERATURE,
227
+ innerTurns: INNER_TURNS,
228
+ concurrency: CONC,
229
+ reproTimeoutS: REPRO_TIMEOUT_S,
230
+ llmTimeoutMs: LLM_TIMEOUT_MS,
231
+ sweRunTimeoutS: SWE_RUN_TOOL_CONFIG.timeoutS,
232
+ sweRunOutputLimit: SWE_RUN_TOOL_CONFIG.outputLimit,
233
+ runTool: true,
234
+ seedPrompt: 'SWE_SEED_PROMPT_WITH_RUN',
235
+ taskIds: [...taskIds],
236
+ }
237
+ }
238
+
239
+ function commonConfig(config: ExperimentConfigReceipt): CommonConfigReceipt {
240
+ const {
241
+ arm: _arm,
242
+ k: _k,
243
+ repairs: _repairs,
244
+ alwaysRunContinuation: _alwaysRunContinuation,
245
+ persistent: _persistent,
246
+ workerSessions: _workerSessions,
247
+ ...common
248
+ } = config
249
+ return common
250
+ }
251
+
252
+ function reproReceipt(entry: ReproManifestEntry | undefined): ReproManifestEntry | null {
253
+ return entry ? { script: entry.script, source: entry.source, stage0Class: entry.stage0Class } : null
254
+ }
255
+
256
+ function expectedFingerprints(
257
+ bt: BenchTask,
258
+ config: ExperimentConfigReceipt,
259
+ tools: unknown,
260
+ repro: ReproManifestEntry | undefined,
261
+ ): Fingerprints {
262
+ return createFingerprints({
263
+ source: SOURCE_RECEIPT,
264
+ config,
265
+ commonConfig: commonConfig(config),
266
+ repro: reproReceipt(repro),
267
+ prompt: SWE_SEED_PROMPT_WITH_RUN,
268
+ tools,
269
+ task: { id: bt.id, prompt: bt.prompt, metadata: bt.metadata ?? null },
270
+ })
271
+ }
272
+
273
+ // ---------- transport: zai direct, patient ladder, leak guard at the chokepoint ----------
274
+
275
+ interface Counter {
276
+ workerSessionsStarted: number
277
+ workerSessionsCompleted: number
278
+ calls: number
279
+ httpAttempts: number
280
+ tokensIn: number
281
+ tokensOut: number
282
+ guardedMsgs: number
283
+ }
284
+
285
+ const newCounter = (): Counter => ({
286
+ workerSessionsStarted: 0,
287
+ workerSessionsCompleted: 0,
288
+ calls: 0,
289
+ httpAttempts: 0,
290
+ tokensIn: 0,
291
+ tokensOut: 0,
292
+ guardedMsgs: 0,
293
+ })
294
+
295
+ /** Distinctive content marks for the leak guard: the first substantive ADDED line of the gold patch
296
+ * and of the hidden test patch. Never shown to any model; used only to refuse outbound messages. */
297
+ function leakMarks(md: Record<string, string>): string[] {
298
+ const marks: string[] = []
299
+ for (const src of [md.patch, md.test_patch]) {
300
+ const m = String(src ?? '')
301
+ .split('\n')
302
+ .find((l) => l.startsWith('+') && !l.startsWith('+++') && l.trim().length > 12)
303
+ ?.slice(0, 80)
304
+ if (m) marks.push(m)
305
+ }
306
+ return marks
307
+ }
308
+
309
+ /** Every model call in this driver flows through here (runAgentic's `complete` seam), so the judge
310
+ * separation is asserted once, at the single chokepoint, for every arm and every round. */
311
+ const makeTransport =
312
+ (marks: string[], counter: Counter) =>
313
+ async (body: Record<string, unknown>): Promise<unknown> => {
314
+ const msgs = (body.messages ?? []) as Array<{ role?: string; content?: unknown }>
315
+ counter.guardedMsgs += assertNoHiddenLeak(marks, msgs)
316
+ const { json, attempts } = await zaiChatRaw({ base: ZAI_BASE, key: ZAI_KEY, timeoutMs: LLM_TIMEOUT_MS }, body)
317
+ counter.calls += 1
318
+ counter.httpAttempts += attempts
319
+ const u = (json as { usage?: { prompt_tokens?: number; completion_tokens?: number } }).usage
320
+ counter.tokensIn += u?.prompt_tokens ?? 0
321
+ counter.tokensOut += u?.completion_tokens ?? 0
322
+ return json
323
+ }
324
+
325
+ // ---------- one emit-patch attempt (the swe-emit-patch protocol, with an optional pre-applied
326
+ // base diff for repair rounds) ----------
327
+
328
+ interface AttemptOut {
329
+ diff: string
330
+ completions: number
331
+ tokensIn: number
332
+ tokensOut: number
333
+ calls: number
334
+ wallMs: number
335
+ error?: string
336
+ }
337
+
338
+ async function emitAttempt(
339
+ environment: AgenticSurface,
340
+ bt: BenchTask,
341
+ cfg: {
342
+ temperature: number
343
+ marks: string[]
344
+ instanceCounter: Counter
345
+ preApply?: string
346
+ promptAppendix?: string
347
+ },
348
+ ): Promise<AttemptOut> {
349
+ const t0 = Date.now()
350
+ const counter = newCounter()
351
+ // Capture the patch from inside score() (called during the refine loop, BEFORE the surface closes
352
+ // and rms the checkout). Keep the LATEST non-empty diff — the emit-patch pattern.
353
+ const capture = { patch: '' }
354
+ const proxy: AgenticSurface = {
355
+ ...environment,
356
+ async open(t: AgenticTask): Promise<ArtifactHandle> {
357
+ const h = await environment.open(t)
358
+ const pre = cfg.preApply
359
+ if (pre?.trim()) {
360
+ const f = join(h.id, '.swe-preapply.diff')
361
+ writeFileSync(f, pre.endsWith('\n') ? pre : `${pre}\n`)
362
+ try {
363
+ await exec('git', ['-C', h.id, 'apply', '--whitespace=nowarn', f], { timeout: 60_000 })
364
+ } finally {
365
+ rmSync(f, { force: true })
366
+ }
367
+ }
368
+ return h
369
+ },
370
+ async score(_t: AgenticTask, handle: ArtifactHandle): Promise<SurfaceScore> {
371
+ try {
372
+ const d = await exec('git', ['-C', handle.id, 'diff'], { maxBuffer: 40_000_000, timeout: 60_000 })
373
+ if (d.stdout.trim()) capture.patch = d.stdout
374
+ } catch {
375
+ /* workspace gone or git error → keep whatever we already captured */
376
+ }
377
+ return { passes: capture.patch.trim() ? 1 : 0, total: 1, errored: 0 }
378
+ },
379
+ }
380
+ const task: AgenticTask = {
381
+ id: bt.id,
382
+ systemPrompt: SWE_SEED_PROMPT_WITH_RUN,
383
+ userPrompt: cfg.promptAppendix ? `${bt.prompt}\n\n${cfg.promptAppendix}` : bt.prompt,
384
+ meta: { instanceId: bt.id },
385
+ }
386
+ let error: string | undefined
387
+ try {
388
+ cfg.instanceCounter.workerSessionsStarted += 1
389
+ const r = await runAgentic({
390
+ surface: proxy,
391
+ task,
392
+ strategy: refine,
393
+ routerBaseUrl: 'zai-direct', // unused: the `complete` transport short-circuits the router
394
+ routerKey: 'zai-direct',
395
+ model: MODEL,
396
+ maxTokens: MAX_TOKENS,
397
+ temperature: cfg.temperature,
398
+ innerTurns: INNER_TURNS,
399
+ budget: 1,
400
+ complete: makeTransport(cfg.marks, counter),
401
+ })
402
+ if (counter.calls < 1) throw new Error('worker session completed without a successful model call')
403
+ cfg.instanceCounter.workerSessionsCompleted += 1
404
+ cfg.instanceCounter.calls += counter.calls
405
+ cfg.instanceCounter.httpAttempts += counter.httpAttempts
406
+ cfg.instanceCounter.tokensIn += counter.tokensIn
407
+ cfg.instanceCounter.tokensOut += counter.tokensOut
408
+ cfg.instanceCounter.guardedMsgs += counter.guardedMsgs
409
+ return {
410
+ diff: capture.patch,
411
+ completions: r.completions,
412
+ tokensIn: counter.tokensIn,
413
+ tokensOut: counter.tokensOut,
414
+ calls: counter.calls,
415
+ wallMs: Date.now() - t0,
416
+ }
417
+ } catch (e) {
418
+ error = e instanceof Error ? e.message.slice(0, 300) : String(e).slice(0, 300)
419
+ cfg.instanceCounter.calls += counter.calls
420
+ cfg.instanceCounter.httpAttempts += counter.httpAttempts
421
+ cfg.instanceCounter.tokensIn += counter.tokensIn
422
+ cfg.instanceCounter.tokensOut += counter.tokensOut
423
+ cfg.instanceCounter.guardedMsgs += counter.guardedMsgs
424
+ return {
425
+ diff: capture.patch,
426
+ completions: 0,
427
+ tokensIn: counter.tokensIn,
428
+ tokensOut: counter.tokensOut,
429
+ calls: counter.calls,
430
+ wallMs: Date.now() - t0,
431
+ error,
432
+ }
433
+ }
434
+ }
435
+
436
+ // Arm composition deliberately stays outside the built-in sample/refine strategies while each
437
+ // worker session still runs through runAgentic(refine, budget=1). The built-ins cannot reproduce
438
+ // this controlled comparison: sample exposes only aggregate scores and has no stable later-on-tie
439
+ // patch receipt; refine may stop after shot one, adds an analyst call, and carries conversation
440
+ // history. This layer supplies only the missing experiment policy: exactly two fresh worker
441
+ // sessions, optional parent-patch state, shared visible selection, and exact per-session receipts.
442
+
443
+ // ---------- in-image candidate scoring ----------
444
+
445
+ /** Severity ordering for selection (lower is better): 0 repro-pass, 1 repro-fail, 2 timeout,
446
+ * 3 apply-fail, 4 empty. Both experiment arms deterministically prefer session two on a tie. */
447
+ interface CandScore {
448
+ applyOk: boolean | null
449
+ exit: number | null
450
+ timedOut: boolean
451
+ severity: number
452
+ out: string
453
+ }
454
+
455
+ const EMPTY_SCORE: CandScore = { applyOk: null, exit: null, timedOut: false, severity: 4, out: '' }
456
+ const UNSCORED: CandScore = { applyOk: null, exit: null, timedOut: false, severity: 1, out: '(no repro signal)' }
457
+
458
+ async function scoreCandidate(imageTag: string, repro: string | null, diff: string): Promise<CandScore> {
459
+ if (!diff.trim()) return EMPTY_SCORE
460
+ if (!repro) return UNSCORED
461
+ const r = await runPyInJail(imageTag, null, repro, diff, { timeoutS: REPRO_TIMEOUT_S })
462
+ if (r.infraError) throw new Error(r.infraError)
463
+ const applyOk = r.out.includes(APPLY_SENTINEL)
464
+ if (!applyOk) return { applyOk, exit: r.code, timedOut: r.timedOut, severity: 3, out: tail(r.out, 800) }
465
+ if (r.timedOut) return { applyOk, exit: r.code, timedOut: true, severity: 2, out: tail(r.out, 800) }
466
+ return { applyOk, exit: r.code, timedOut: false, severity: r.code === 0 ? 0 : 1, out: tail(r.out, 1_500) }
467
+ }
468
+
469
+ // ---------- rows ----------
470
+
471
+ interface CandidateRow {
472
+ idx: number
473
+ diff: string
474
+ diffHash: string
475
+ diffBytes: number
476
+ completions: number
477
+ calls: number
478
+ tokensIn: number
479
+ tokensOut: number
480
+ wallMs: number
481
+ attemptError: string | null
482
+ applyOk: boolean | null
483
+ reproExit: number | null
484
+ reproTimedOut: boolean
485
+ severity: number
486
+ reproOutTail: string
487
+ }
488
+
489
+ interface RepairRow {
490
+ round: number
491
+ baseFrom: string
492
+ baseSeverity: number
493
+ parentDiffHash: string
494
+ diff: string
495
+ finalDiffHash: string
496
+ changedFromParent: boolean
497
+ diffBytes: number
498
+ completions: number
499
+ calls: number
500
+ tokensIn: number
501
+ tokensOut: number
502
+ wallMs: number
503
+ attemptError: string | null
504
+ applyOk: boolean | null
505
+ reproExit: number | null
506
+ severity: number
507
+ accepted: boolean
508
+ }
509
+
510
+ interface PhaseARow {
511
+ instanceId: string
512
+ arm: ExperimentArm
513
+ config: ExperimentConfigReceipt
514
+ fingerprints: Fingerprints
515
+ repo: string
516
+ model: string
517
+ image: string | null
518
+ execution: ExecutionReceipt | null
519
+ executionFingerprint: string
520
+ execMode: 'image'
521
+ temperature: number
522
+ innerTurns: number
523
+ k: number
524
+ maxRepairs: number
525
+ // canary + repro provenance (system arm)
526
+ canaryExit: number | null
527
+ canaryPass: boolean | null
528
+ reproSource: string
529
+ reproStage0Class: string | null
530
+ reproStatus: string
531
+ reproScript: string | null
532
+ reproPreExit: number | null
533
+ reproGoldExit: number | null
534
+ reproOutcomeFingerprint: string
535
+ // candidates + selection + continuation receipts
536
+ candidates: CandidateRow[]
537
+ selection: { mode: string; selectedIdx: number; movedOffFirst: boolean } | null
538
+ repairs: RepairRow[]
539
+ repairStop: string | null
540
+ finalFrom: string
541
+ parentDiffHash: string | null
542
+ finalDiff: string
543
+ finalDiffHash: string
544
+ changedFromParent: boolean | null
545
+ // cost + guard receipts
546
+ /** Number of fresh runAgentic worker invocations, including invocations that returned an error. */
547
+ workerSessionsStarted: number
548
+ /** Number of runAgentic invocations that returned successfully after at least one model call. */
549
+ workerSessions: number
550
+ llmCalls: number
551
+ httpAttempts: number
552
+ tokensIn: number
553
+ tokensOut: number
554
+ guardedMsgs: number
555
+ wallMs: number
556
+ error?: string
557
+ }
558
+
559
+ // ---------- phase A: all arm decisions (no judge anywhere) ----------
560
+
561
+ type Env = Awaited<ReturnType<typeof createSweBenchEnvironment>>
562
+
563
+ interface PhaseAContext {
564
+ preset: ExperimentArmPreset
565
+ config: ExperimentConfigReceipt
566
+ tools: unknown
567
+ sharedExecution: SharedExecutionReceipt
568
+ expectedImageIdentities: Map<string, SweImageIdentity>
569
+ }
570
+
571
+ async function phaseA(env: Env, bt: BenchTask, ctx: PhaseAContext): Promise<PhaseARow> {
572
+ const t0 = Date.now()
573
+ const md = bt.metadata as Record<string, string>
574
+ const counter = newCounter()
575
+ const row: PhaseARow = {
576
+ instanceId: bt.id, arm: ctx.preset.arm, config: ctx.config,
577
+ fingerprints: expectedFingerprints(bt, ctx.config, ctx.tools, MANIFEST[bt.id]),
578
+ repo: md.repo, model: MODEL, image: null, execution: null, executionFingerprint: '', execMode: 'image',
579
+ temperature: TEMPERATURE, innerTurns: INNER_TURNS,
580
+ k: ctx.preset.k, maxRepairs: ctx.preset.repairs,
581
+ canaryExit: null, canaryPass: null, reproSource: 'none', reproStage0Class: null,
582
+ reproStatus: 'none', reproScript: null,
583
+ reproPreExit: null, reproGoldExit: null, reproOutcomeFingerprint: '',
584
+ candidates: [], selection: null, repairs: [],
585
+ repairStop: null, finalFrom: 'none', parentDiffHash: null, finalDiff: '',
586
+ finalDiffHash: diffFingerprint(''), changedFromParent: null,
587
+ workerSessionsStarted: 0, workerSessions: 0, llmCalls: 0, httpAttempts: 0,
588
+ tokensIn: 0, tokensOut: 0,
589
+ guardedMsgs: 0, wallMs: 0,
590
+ }
591
+ const marks = leakMarks(md)
592
+ try {
593
+ const img = await resolveImageForMetadata(bt.metadata ?? {})
594
+ if (!img.ok) throw new Error(`image missing: ${img.reason}`)
595
+ row.image = img.tag
596
+ row.execution = createExecutionReceipt(ctx.sharedExecution, img)
597
+ row.executionFingerprint = fingerprint(row.execution)
598
+ ctx.expectedImageIdentities.set(bt.id, img.identity)
599
+
600
+ // 1. EXECUTION CANARY (image substrate, gold in-container — script-side only, zero model calls).
601
+ const pkg = IMPORT_NAME[md.repo]
602
+ if (!pkg) throw new Error(`no IMPORT_NAME for ${md.repo} — canary not expressible`)
603
+ const gold = String(md.patch ?? '')
604
+ if (!gold.trim()) throw new Error('gold patch missing from metadata')
605
+ const c = await runPyInJail(img.identity.id, null, importCanaryScript(pkg), gold, { timeoutS: REPRO_TIMEOUT_S })
606
+ if (c.infraError) throw new Error(c.infraError)
607
+ row.canaryExit = c.code
608
+ row.canaryPass = c.code === 0 && c.out.includes(APPLY_SENTINEL)
609
+ if (!row.canaryPass) throw new Error(`canary failed (exit ${c.code}): this substrate cannot grade this instance`)
610
+
611
+ // 2. Repro reuse + re-verification on THIS substrate (validity without gold, soundness with).
612
+ const manifest = MANIFEST[bt.id]
613
+ let repro: string | null = null
614
+ if (manifest) {
615
+ row.reproSource = manifest.source
616
+ row.reproStage0Class = manifest.stage0Class
617
+ row.reproScript = manifest.script
618
+ const pre = await runPyInJail(img.identity.id, null, manifest.script, undefined, { timeoutS: REPRO_TIMEOUT_S })
619
+ if (pre.infraError) throw new Error(pre.infraError)
620
+ row.reproPreExit = pre.code
621
+ if (pre.timedOut) row.reproStatus = 'degraded-timeout'
622
+ else if (pre.code === 0) row.reproStatus = 'degraded-invalid'
623
+ else {
624
+ const post = await runPyInJail(img.identity.id, null, manifest.script, gold, { timeoutS: REPRO_TIMEOUT_S })
625
+ if (post.infraError) throw new Error(post.infraError)
626
+ row.reproGoldExit = post.code
627
+ if (post.code === 0 && post.out.includes(APPLY_SENTINEL)) {
628
+ row.reproStatus = 'ok'
629
+ repro = manifest.script
630
+ } else {
631
+ row.reproStatus = 'degraded-unsound'
632
+ }
633
+ }
634
+ }
635
+
636
+ // 3. k independent candidates (serial within the instance — CONC instances bound zai concurrency).
637
+ const diffs: string[] = []
638
+ for (let i = 0; i < ctx.preset.k; i += 1) {
639
+ const a = await emitAttempt(env.environment, bt, { temperature: TEMPERATURE, marks, instanceCounter: counter })
640
+ diffs.push(a.diff)
641
+ row.candidates.push({
642
+ idx: i, diff: a.diff, diffHash: diffFingerprint(a.diff), diffBytes: a.diff.length,
643
+ completions: a.completions, calls: a.calls,
644
+ tokensIn: a.tokensIn, tokensOut: a.tokensOut, wallMs: a.wallMs, attemptError: a.error ?? null,
645
+ applyOk: null, reproExit: null, reproTimedOut: false, severity: -1, reproOutTail: '',
646
+ })
647
+ }
648
+
649
+ // 4. In-image scoring + argmax.
650
+ const scores: CandScore[] = []
651
+ for (let i = 0; i < ctx.preset.k; i += 1) {
652
+ const s = await scoreCandidate(img.identity.id, repro, diffs[i] as string)
653
+ scores.push(s)
654
+ const cand = row.candidates[i] as CandidateRow
655
+ cand.applyOk = s.applyOk
656
+ cand.reproExit = s.exit
657
+ cand.reproTimedOut = s.timedOut
658
+ cand.severity = s.severity
659
+ cand.reproOutTail = s.out
660
+ }
661
+ let selectedIdx = 0
662
+ for (let i = 1; i < ctx.preset.k; i += 1) {
663
+ if (preferLaterCandidate((scores[selectedIdx] as CandScore).severity, (scores[i] as CandScore).severity)) {
664
+ selectedIdx = i
665
+ }
666
+ }
667
+ const mode = repro ? 'visible-severity-later-tie' : 'no-repro-later-tie'
668
+ row.selection = { mode, selectedIdx, movedOffFirst: selectedIdx !== 0 }
669
+
670
+ // 5. The persistent arm starts exactly one continuation from session one's cumulative patch.
671
+ // Both arms use the same later-on-visible-tie policy.
672
+ let best = {
673
+ diff: diffs[selectedIdx] as string,
674
+ score: scores[selectedIdx] as CandScore,
675
+ from: ctx.preset.persistent ? 'session:1' : `attempt:${selectedIdx + 1}`,
676
+ }
677
+ if (!ctx.preset.persistent) {
678
+ row.repairStop = 'independent-arm'
679
+ } else {
680
+ for (let round = 1; shouldRunContinuation({ round, preset: ctx.preset }); round += 1) {
681
+ const parentDiff = best.diff
682
+ const parentDiffHash = diffFingerprint(parentDiff)
683
+ row.parentDiffHash = parentDiffHash
684
+ const reproductionEvidence = repro
685
+ ? `--- REPRODUCTION SCRIPT (written from the issue; exit 0 = fixed) ---\n${tail(repro, 6_000)}\n\n` +
686
+ `--- REPRODUCTION OUTPUT on the current state (exit ${best.score.exit ?? 'n/a'}) ---\n${best.score.out}\n\n`
687
+ : '--- EXTERNAL REPRODUCTION ---\nNo external reproduction is available. Use the run tool to construct local, issue-specific checks.\n\n'
688
+ const repairInstruction = best.score.severity === 0
689
+ ? 'The visible reproduction PASSES, but it is only a partial check. Re-read the full issue and audit ' +
690
+ 'the current patch for missed cases or regressions. Keep the visible check passing while correcting ' +
691
+ 'any incomplete source behavior you find with minimal edit_file changes. Do not modify tests.'
692
+ : 'The visible reproduction still fails (or no external reproduction is available). Diagnose why the ' +
693
+ 'current state does not resolve the full issue, then correct the SOURCE with minimal edit_file changes ' +
694
+ '(you may revise or revert parts of the previous fix — it is already in the files). Do not modify tests.'
695
+ const appendix =
696
+ continuationStateNotice(best.diff) +
697
+ reproductionEvidence +
698
+ '--- REPAIR INSTRUCTIONS ---\n' +
699
+ repairInstruction
700
+ const a = await emitAttempt(env.environment, bt, {
701
+ temperature: TEMPERATURE, marks, instanceCounter: counter, preApply: best.diff, promptAppendix: appendix,
702
+ })
703
+ const ns = await scoreCandidate(img.identity.id, repro, a.diff)
704
+ const finalDiffHash = diffFingerprint(a.diff)
705
+ const changedFromParent = diffChanged(parentDiff, a.diff)
706
+ const accepted = shouldAcceptContinuation(best.score.severity, ns.severity)
707
+ const disposition = continuationDisposition(accepted, changedFromParent)
708
+ row.repairs.push({
709
+ round, baseFrom: best.from, baseSeverity: best.score.severity, parentDiffHash,
710
+ diff: a.diff, finalDiffHash, changedFromParent, diffBytes: a.diff.length,
711
+ completions: a.completions, calls: a.calls, tokensIn: a.tokensIn, tokensOut: a.tokensOut,
712
+ wallMs: a.wallMs, attemptError: a.error ?? null, applyOk: ns.applyOk, reproExit: ns.exit,
713
+ severity: ns.severity, accepted,
714
+ })
715
+ if (accepted) {
716
+ best = {
717
+ diff: a.diff,
718
+ score: ns,
719
+ from: disposition.finalFrom,
720
+ }
721
+ row.repairStop = disposition.stop
722
+ } else {
723
+ best.from = disposition.finalFrom
724
+ row.repairStop = disposition.stop
725
+ }
726
+ }
727
+ }
728
+ row.finalDiff = best.diff
729
+ row.finalDiffHash = diffFingerprint(best.diff)
730
+ row.finalFrom = best.from
731
+ row.changedFromParent = row.parentDiffHash === null
732
+ ? null
733
+ : row.finalDiffHash !== row.parentDiffHash
734
+ return row
735
+ } catch (e) {
736
+ row.error = e instanceof Error ? e.message.slice(0, 400) : String(e).slice(0, 400)
737
+ return row
738
+ } finally {
739
+ row.reproOutcomeFingerprint = fingerprint({
740
+ canaryExit: row.canaryExit,
741
+ canaryPass: row.canaryPass,
742
+ image: row.execution?.image ?? null,
743
+ reproGoldExit: row.reproGoldExit,
744
+ reproPreExit: row.reproPreExit,
745
+ reproSource: row.reproSource,
746
+ reproStage0Class: row.reproStage0Class,
747
+ reproStatus: row.reproStatus,
748
+ })
749
+ row.workerSessionsStarted = counter.workerSessionsStarted
750
+ row.workerSessions = counter.workerSessionsCompleted
751
+ row.llmCalls = counter.calls
752
+ row.httpAttempts = counter.httpAttempts
753
+ row.tokensIn = counter.tokensIn
754
+ row.tokensOut = counter.tokensOut
755
+ row.guardedMsgs = counter.guardedMsgs
756
+ row.wallMs = Date.now() - t0
757
+ }
758
+ }
759
+
760
+ // ---------- driver ----------
761
+
762
+ function loadPhaseRows(path: string, required = false): Map<string, PhaseARow> {
763
+ if (!existsSync(path)) {
764
+ if (required) throw new Error(`required Phase-A file does not exist: ${path}`)
765
+ return new Map()
766
+ }
767
+ const rows = new Map<string, PhaseARow>()
768
+ for (const [index, line] of readFileSync(path, 'utf8').split('\n').entries()) {
769
+ if (!line.trim()) continue
770
+ const row = JSON.parse(line) as PhaseARow
771
+ if (!row.instanceId) throw new Error(`${path}:${index + 1}: missing instanceId`)
772
+ if (rows.has(row.instanceId)) throw new Error(`${path}:${index + 1}: duplicate instanceId ${row.instanceId}`)
773
+ rows.set(row.instanceId, row)
774
+ }
775
+ if (required && rows.size === 0) throw new Error(`required Phase-A file is empty: ${path}`)
776
+ return rows
777
+ }
778
+
779
+ function manifestFromRow(row: PhaseARow): ReproManifestEntry | undefined {
780
+ if (row.reproScript === null) {
781
+ if (row.reproSource !== 'none' || row.reproStage0Class !== null) {
782
+ throw new Error(`${row.instanceId}: incomplete null-repro receipt`)
783
+ }
784
+ return undefined
785
+ }
786
+ if (row.reproSource === 'none' || row.reproStage0Class === null) {
787
+ throw new Error(`${row.instanceId}: incomplete repro receipt`)
788
+ }
789
+ return { script: row.reproScript, source: row.reproSource, stage0Class: row.reproStage0Class }
790
+ }
791
+
792
+ function assertPresetConfig(config: ExperimentConfigReceipt, arm: ExperimentArm, context: string): void {
793
+ const preset = resolveExperimentArm(arm)
794
+ if (
795
+ config.schema !== 'swe-structural-v2' ||
796
+ !config.model ||
797
+ !config.zaiBase ||
798
+ !Number.isFinite(config.maxTokens) ||
799
+ config.maxTokens <= 0 ||
800
+ !Number.isFinite(config.temperature) ||
801
+ !Number.isInteger(config.innerTurns) ||
802
+ config.innerTurns <= 0 ||
803
+ !Number.isInteger(config.concurrency) ||
804
+ config.concurrency < 1 ||
805
+ !Number.isFinite(config.reproTimeoutS) ||
806
+ config.reproTimeoutS <= 0 ||
807
+ !Number.isFinite(config.llmTimeoutMs) ||
808
+ config.llmTimeoutMs <= 0 ||
809
+ config.runTool !== true ||
810
+ config.seedPrompt !== 'SWE_SEED_PROMPT_WITH_RUN' ||
811
+ !Number.isFinite(config.sweRunTimeoutS) ||
812
+ config.sweRunTimeoutS <= 0 ||
813
+ !Number.isFinite(config.sweRunOutputLimit) ||
814
+ config.sweRunOutputLimit <= 0 ||
815
+ !Array.isArray(config.taskIds) ||
816
+ config.taskIds.length === 0
817
+ ) {
818
+ throw new Error(`${context}: unsupported config schema or worker surface`)
819
+ }
820
+ for (const key of ['arm', 'k', 'repairs', 'alwaysRunContinuation', 'persistent', 'workerSessions'] as const) {
821
+ if (config[key] !== preset[key]) {
822
+ throw new Error(`${context}: config ${key}=${String(config[key])}, expected ${String(preset[key])}`)
823
+ }
824
+ }
825
+ }
826
+
827
+ async function assertPhaseRow(
828
+ row: PhaseARow,
829
+ bt: BenchTask,
830
+ config: ExperimentConfigReceipt,
831
+ tools: unknown,
832
+ repro: ReproManifestEntry | undefined,
833
+ sharedExecution: SharedExecutionReceipt,
834
+ context: string,
835
+ ): Promise<void> {
836
+ if (row.instanceId !== bt.id) throw new Error(`${context}: instance mismatch ${row.instanceId} != ${bt.id}`)
837
+ if (row.arm !== config.arm) throw new Error(`${context}: arm mismatch ${row.arm} != ${config.arm}`)
838
+ if (!row.config) throw new Error(`${context}: missing config receipt`)
839
+ assertPresetConfig(row.config, row.arm, context)
840
+ if (fingerprint(row.config) !== fingerprint(config)) throw new Error(`${context}: config receipt mismatch`)
841
+ assertFingerprintsEqual(row.fingerprints, expectedFingerprints(bt, config, tools, repro), context)
842
+ if (
843
+ row.model !== config.model ||
844
+ row.temperature !== config.temperature ||
845
+ row.innerTurns !== config.innerTurns ||
846
+ row.k !== config.k ||
847
+ row.maxRepairs !== config.repairs
848
+ ) {
849
+ throw new Error(`${context}: row execution fields do not match config receipt`)
850
+ }
851
+ if (row.repo !== String((bt.metadata as Record<string, unknown> | undefined)?.repo ?? '')) {
852
+ throw new Error(`${context}: row repo does not match task metadata`)
853
+ }
854
+ if (row.error) throw new Error(`${context}: Phase A contains an error: ${row.error}`)
855
+ assertExactCompletedWorkerSessions({
856
+ started: row.workerSessionsStarted,
857
+ completed: row.workerSessions,
858
+ sessions: [...row.candidates, ...row.repairs],
859
+ context,
860
+ })
861
+ const currentImage = await resolveImageForMetadata(bt.metadata ?? {})
862
+ if (!currentImage.ok) throw new Error(`${context}: image unavailable during receipt validation: ${currentImage.reason}`)
863
+ const expectedExecution = createExecutionReceipt(sharedExecution, currentImage)
864
+ const actualExecution = row.execution
865
+ if (!actualExecution || fingerprint(actualExecution) !== fingerprint(expectedExecution)) {
866
+ throw new Error(`${context}: execution receipt mismatch`)
867
+ }
868
+ if (
869
+ row.config.sweRunTimeoutS !== actualExecution.runTool.timeoutS ||
870
+ row.config.sweRunOutputLimit !== actualExecution.runTool.outputLimit
871
+ ) {
872
+ throw new Error(`${context}: config and execution run-tool settings do not match`)
873
+ }
874
+ if (row.executionFingerprint !== fingerprint(expectedExecution)) {
875
+ throw new Error(`${context}: execution fingerprint mismatch`)
876
+ }
877
+ if (row.image !== expectedExecution.image.tag) throw new Error(`${context}: image tag receipt mismatch`)
878
+ if (row.finalDiffHash !== diffFingerprint(row.finalDiff)) throw new Error(`${context}: final diff hash mismatch`)
879
+ const expectedReproOutcome = fingerprint({
880
+ canaryExit: row.canaryExit,
881
+ canaryPass: row.canaryPass,
882
+ image: actualExecution.image,
883
+ reproGoldExit: row.reproGoldExit,
884
+ reproPreExit: row.reproPreExit,
885
+ reproSource: row.reproSource,
886
+ reproStage0Class: row.reproStage0Class,
887
+ reproStatus: row.reproStatus,
888
+ })
889
+ if (row.reproOutcomeFingerprint !== expectedReproOutcome) {
890
+ throw new Error(`${context}: reproduction outcome fingerprint mismatch`)
891
+ }
892
+ for (const candidate of row.candidates) {
893
+ if (candidate.diffHash !== diffFingerprint(candidate.diff)) {
894
+ throw new Error(`${context}: candidate ${candidate.idx} diff hash mismatch`)
895
+ }
896
+ }
897
+
898
+ const preset = resolveExperimentArm(row.arm)
899
+ if (row.candidates.length !== preset.k || row.repairs.length !== preset.repairs) {
900
+ throw new Error(
901
+ `${context}: arm shape mismatch (candidates=${row.candidates.length}, repairs=${row.repairs.length})`,
902
+ )
903
+ }
904
+ let selectedIdx = 0
905
+ for (let i = 1; i < row.candidates.length; i += 1) {
906
+ if (preferLaterCandidate(row.candidates[selectedIdx]!.severity, row.candidates[i]!.severity)) selectedIdx = i
907
+ }
908
+ const expectedMode = row.reproStatus === 'ok' ? 'visible-severity-later-tie' : 'no-repro-later-tie'
909
+ if (
910
+ row.selection?.selectedIdx !== selectedIdx ||
911
+ row.selection.mode !== expectedMode ||
912
+ row.selection.movedOffFirst !== (selectedIdx !== 0)
913
+ ) {
914
+ throw new Error(`${context}: selectedIdx violates later-on-visible-tie policy`)
915
+ }
916
+
917
+ if (!preset.persistent) {
918
+ if (row.parentDiffHash !== null || row.changedFromParent !== null) {
919
+ throw new Error(`${context}: independent arm must not claim a parent/refinement`)
920
+ }
921
+ if (row.repairStop !== 'independent-arm') throw new Error(`${context}: independent arm stop receipt mismatch`)
922
+ const selected = row.candidates[selectedIdx]!
923
+ if (row.finalDiff !== selected.diff || row.finalFrom !== `attempt:${selectedIdx + 1}`) {
924
+ throw new Error(`${context}: independent final patch does not match selected attempt`)
925
+ }
926
+ return
927
+ }
928
+
929
+ const continuation = row.repairs[0]!
930
+ const parent = row.candidates[0]!.diff
931
+ if (continuation.baseFrom !== 'session:1' || continuation.baseSeverity !== row.candidates[0]!.severity) {
932
+ throw new Error(`${context}: continuation parent receipt mismatch`)
933
+ }
934
+ if (continuation.parentDiffHash !== diffFingerprint(parent)) throw new Error(`${context}: parent diff hash mismatch`)
935
+ if (continuation.finalDiffHash !== diffFingerprint(continuation.diff)) throw new Error(`${context}: continuation diff hash mismatch`)
936
+ if (continuation.changedFromParent !== diffChanged(parent, continuation.diff)) {
937
+ throw new Error(`${context}: continuation changedFromParent mismatch`)
938
+ }
939
+ const shouldAccept = shouldAcceptContinuation(continuation.baseSeverity, continuation.severity)
940
+ if (continuation.accepted !== shouldAccept) throw new Error(`${context}: continuation violates shared tie policy`)
941
+ const expectedFinal = continuation.accepted ? continuation.diff : parent
942
+ const disposition = continuationDisposition(continuation.accepted, continuation.changedFromParent)
943
+ if (row.finalDiff !== expectedFinal || row.finalFrom !== disposition.finalFrom || row.repairStop !== disposition.stop) {
944
+ throw new Error(`${context}: persistent final patch/provenance mismatch`)
945
+ }
946
+ if (row.parentDiffHash !== continuation.parentDiffHash) throw new Error(`${context}: row parent diff hash mismatch`)
947
+ if (row.changedFromParent !== (row.finalDiffHash !== row.parentDiffHash)) {
948
+ throw new Error(`${context}: row changedFromParent mismatch`)
949
+ }
950
+ }
951
+
952
+ async function assertOfficialScoreImagePinned(row: PhaseARow, bt: BenchTask, context: string): Promise<void> {
953
+ const expected = row.execution?.image
954
+ if (!expected) throw new Error(`${context}: missing immutable image receipt`)
955
+ const current = await resolveImageForMetadata(bt.metadata ?? {})
956
+ if (!current.ok) throw new Error(`${context}: image unavailable: ${current.reason}`)
957
+ if (
958
+ current.tag !== expected.tag ||
959
+ current.namespace !== expected.namespace ||
960
+ current.identity.id !== expected.id
961
+ ) {
962
+ throw new Error(
963
+ `${context}: official-score image changed ` +
964
+ `(${expected.namespace}:${expected.tag}@${expected.id} -> ` +
965
+ `${current.namespace}:${current.tag}@${current.identity.id})`,
966
+ )
967
+ }
968
+ }
969
+
970
+ async function loadTasksAndTools(ids: string[]): Promise<{
971
+ env: Env
972
+ taskById: Map<string, BenchTask>
973
+ tools: unknown
974
+ sharedExecution: SharedExecutionReceipt
975
+ expectedImageIdentities: Map<string, SweImageIdentity>
976
+ }> {
977
+ const expectedImageIdentities = new Map<string, SweImageIdentity>()
978
+ const env = await createSweBenchEnvironment(ids.length, {
979
+ ids,
980
+ cloneCache: true,
981
+ enableRun: true,
982
+ expectedImageIdentities,
983
+ adapterOptions: { cacheLevel: OFFICIAL_SCORER_CACHE_LEVEL },
984
+ })
985
+ await env.adapter.preflight?.()
986
+ const scorerVersion = await resolveSweBenchScorerVersion()
987
+ const taskById = new Map((await env.adapter.loadTasks({ ids, split: 'test' })).map((task) => [task.id, task]))
988
+ const missing = ids.filter((id) => !taskById.has(id))
989
+ if (missing.length) throw new Error(`instances not found in SWE-bench_Verified: ${missing.join(', ')}`)
990
+ const first = taskById.get(ids[0]!)!
991
+ const fingerprintTask: AgenticTask = {
992
+ id: first.id,
993
+ systemPrompt: SWE_SEED_PROMPT_WITH_RUN,
994
+ userPrompt: first.prompt,
995
+ meta: { instanceId: first.id },
996
+ }
997
+ const fingerprintHandle: ArtifactHandle = { id: 'fingerprint-only', surface: 'swe-bench-verified' }
998
+ return {
999
+ env,
1000
+ taskById,
1001
+ tools: await env.environment.tools(fingerprintTask, fingerprintHandle),
1002
+ sharedExecution: {
1003
+ runTool: { ...SWE_RUN_TOOL_CONFIG },
1004
+ runtimeImplementationFingerprint: RUNTIME_IMPLEMENTATION_FINGERPRINT,
1005
+ runtimeTreeFingerprint: RUNTIME_TREE_FINGERPRINT,
1006
+ officialScorer: {
1007
+ package: 'swebench',
1008
+ version: scorerVersion,
1009
+ cacheLevel: OFFICIAL_SCORER_CACHE_LEVEL,
1010
+ namespacePolicy: 'phase-a-image',
1011
+ },
1012
+ },
1013
+ expectedImageIdentities,
1014
+ }
1015
+ }
1016
+
1017
+ async function generateMain(): Promise<void> {
1018
+ const preset = ARM_PRESET as ExperimentArmPreset
1019
+ const ids = process.env.IDS
1020
+ ? process.env.IDS.split(',').map((value) => value.trim()).filter(Boolean)
1021
+ : await cachedInstanceIds()
1022
+ if (!ids.length) throw new Error('no cached sweb.eval images found and no IDS given')
1023
+ if (new Set(ids).size !== ids.length) throw new Error('IDS contains duplicates')
1024
+ const out = process.env.OUT ?? `swe-stage1-${preset.arm}.phaseA.jsonl`
1025
+ const config = makeExperimentConfig(preset, ids)
1026
+ assertPresetConfig(config, preset.arm, 'generate config')
1027
+ const { env, taskById, tools, sharedExecution, expectedImageIdentities } = await loadTasksAndTools(ids)
1028
+
1029
+ console.log(`═══ SWE-bench Phase A — ${preset.arm} ═══`)
1030
+ console.log(
1031
+ `sessions=2 k=${preset.k} repairs=${preset.repairs} persistent=${preset.persistent ? 1 : 0} ` +
1032
+ `model=${MODEL} maxTokens=${MAX_TOKENS} innerTurns=${INNER_TURNS} temperature=${TEMPERATURE} runTool=1 judge=DISABLED`,
1033
+ )
1034
+ console.log(`instances=${ids.length} out=${out}`)
1035
+
1036
+ const done = loadPhaseRows(out)
1037
+ for (const [id, row] of done) {
1038
+ if (!ids.includes(id)) throw new Error(`${out}: resume row ${id} is outside current IDS`)
1039
+ await assertPhaseRow(row, taskById.get(id)!, config, tools, MANIFEST[id], sharedExecution, `${out}:${id}`)
1040
+ }
1041
+ const todo = ids.filter((id) => !done.has(id))
1042
+ if (done.size) console.log(`resume accepted: ${done.size}/${ids.length} fingerprint-matched rows`)
1043
+
1044
+ let next = 0
1045
+ const worker = async (): Promise<void> => {
1046
+ while (next < todo.length) {
1047
+ const index = next++
1048
+ const id = todo[index]!
1049
+ const row = await phaseA(env, taskById.get(id)!, {
1050
+ preset,
1051
+ config,
1052
+ tools,
1053
+ sharedExecution,
1054
+ expectedImageIdentities,
1055
+ })
1056
+ await assertPhaseRow(
1057
+ row,
1058
+ taskById.get(id)!,
1059
+ config,
1060
+ tools,
1061
+ MANIFEST[id],
1062
+ sharedExecution,
1063
+ `${preset.arm}:${id}`,
1064
+ )
1065
+ done.set(id, row)
1066
+ appendFileSync(out, `${JSON.stringify(row)}\n`)
1067
+ console.log(
1068
+ `[${index + 1}/${todo.length}] ${id} sessions=${row.workerSessions} ` +
1069
+ `severity=[${row.candidates.map((candidate) => candidate.severity).join(',')}] ` +
1070
+ `continuation=[${row.repairs.map((repair) => repair.severity).join(',')}] ` +
1071
+ `final=${row.finalFrom} changed=${row.changedFromParent ?? 'n/a'} calls=${row.llmCalls}`,
1072
+ )
1073
+ }
1074
+ }
1075
+ await Promise.all(Array.from({ length: CONC }, () => worker()))
1076
+
1077
+ const rows = ids.map((id) => done.get(id)!)
1078
+ const totalSessions = rows.reduce((sum, row) => sum + row.workerSessions, 0)
1079
+ const totalIn = rows.reduce((sum, row) => sum + row.tokensIn, 0)
1080
+ const totalOut = rows.reduce((sum, row) => sum + row.tokensOut, 0)
1081
+ const usd = (totalIn / 1e6) * PRICE_IN + (totalOut / 1e6) * PRICE_OUT
1082
+ console.log(
1083
+ `Phase A complete: rows=${rows.length}/${ids.length} sessions=${totalSessions}/${2 * ids.length} ` +
1084
+ `tokens=${totalIn}/${totalOut} assumedCost=$${usd.toFixed(2)}; no official scores were called`,
1085
+ )
1086
+ }
1087
+
1088
+ interface JudgeRow {
1089
+ schema: 'swe-structural-judge-v2'
1090
+ instanceId: string
1091
+ arm: ExperimentArm
1092
+ pairFingerprint: string
1093
+ phaseFileFingerprint: string
1094
+ inputFingerprint: string
1095
+ executionFingerprint: string
1096
+ finalDiffHash: string
1097
+ hiddenResolved: boolean
1098
+ judgeDetail: string | null
1099
+ judgeMs: number
1100
+ judgeSkipped: 'empty-patch' | null
1101
+ }
1102
+
1103
+ function loadJudgeRows(path: string): Map<string, JudgeRow> {
1104
+ if (!existsSync(path)) return new Map()
1105
+ const rows = new Map<string, JudgeRow>()
1106
+ for (const [index, line] of readFileSync(path, 'utf8').split('\n').entries()) {
1107
+ if (!line.trim()) continue
1108
+ const row = JSON.parse(line) as JudgeRow
1109
+ if (row.schema !== 'swe-structural-judge-v2') {
1110
+ throw new Error(`${path}:${index + 1}: unsupported judge row schema`)
1111
+ }
1112
+ if (typeof row.hiddenResolved !== 'boolean') {
1113
+ throw new Error(`${path}:${index + 1}: incomplete judge row must be removed and retried`)
1114
+ }
1115
+ if (row.judgeSkipped !== null && row.judgeSkipped !== 'empty-patch') {
1116
+ throw new Error(`${path}:${index + 1}: unsupported judge skip receipt ${row.judgeSkipped}`)
1117
+ }
1118
+ resolveExperimentArm(row.arm)
1119
+ const key = `${row.arm}:${row.instanceId}`
1120
+ if (rows.has(key)) throw new Error(`${path}:${index + 1}: duplicate judge row ${key}`)
1121
+ rows.set(key, row)
1122
+ }
1123
+ return rows
1124
+ }
1125
+
1126
+ function requirePath(name: string): string {
1127
+ const value = process.env[name]?.trim()
1128
+ if (!value) throw new Error(`${name} required for MODE=judge-only`)
1129
+ return value
1130
+ }
1131
+
1132
+ async function judgeOnlyMain(): Promise<void> {
1133
+ const independentPath = requirePath('INDEPENDENT_PHASE_A')
1134
+ const persistentPath = requirePath('PERSISTENT_PHASE_A')
1135
+ const out = requirePath('OUT')
1136
+ assertDistinctArtifactPaths({ INDEPENDENT_PHASE_A: independentPath, PERSISTENT_PHASE_A: persistentPath, OUT: out })
1137
+ const independent = loadPhaseRows(independentPath, true)
1138
+ const persistent = loadPhaseRows(persistentPath, true)
1139
+ const independentConfig = [...independent.values()][0]!.config
1140
+ const persistentConfig = [...persistent.values()][0]!.config
1141
+ if (!independentConfig || !persistentConfig) throw new Error('Phase-A file is missing its config receipt')
1142
+ assertPresetConfig(independentConfig, 'independent-2', independentPath)
1143
+ assertPresetConfig(persistentConfig, 'persistent-refine-2', persistentPath)
1144
+ if (fingerprint(commonConfig(independentConfig)) !== fingerprint(commonConfig(persistentConfig))) {
1145
+ throw new Error('Phase-A files have different common configuration fingerprints')
1146
+ }
1147
+ const ids = independentConfig.taskIds
1148
+ if (fingerprint(ids) !== fingerprint(persistentConfig.taskIds)) {
1149
+ throw new Error('Phase-A files have different task-id fingerprints')
1150
+ }
1151
+ for (const [path, rows] of [[independentPath, independent], [persistentPath, persistent]] as const) {
1152
+ assertCompleteTaskSet(rows.keys(), ids, path)
1153
+ }
1154
+
1155
+ // No official judge call occurs before every row in both files passes these checks.
1156
+ const { env, taskById, tools, sharedExecution } = await loadTasksAndTools(ids)
1157
+ for (const id of ids) {
1158
+ const left = independent.get(id)!
1159
+ const right = persistent.get(id)!
1160
+ await assertPhaseRow(
1161
+ left,
1162
+ taskById.get(id)!,
1163
+ independentConfig,
1164
+ tools,
1165
+ manifestFromRow(left),
1166
+ sharedExecution,
1167
+ `${independentPath}:${id}`,
1168
+ )
1169
+ await assertPhaseRow(
1170
+ right,
1171
+ taskById.get(id)!,
1172
+ persistentConfig,
1173
+ tools,
1174
+ manifestFromRow(right),
1175
+ sharedExecution,
1176
+ `${persistentPath}:${id}`,
1177
+ )
1178
+ assertPairedFingerprints(left.fingerprints, right.fingerprints, id)
1179
+ assertPairedExecutionFingerprint(left.executionFingerprint, right.executionFingerprint, id)
1180
+ if (left.reproOutcomeFingerprint !== right.reproOutcomeFingerprint) {
1181
+ throw new Error(`${id}: paired reproduction outcomes do not match`)
1182
+ }
1183
+ }
1184
+
1185
+ const phaseFileFingerprints: Record<ExperimentArm, string> = {
1186
+ 'independent-2': fingerprint({ bytes: readFileSync(independentPath, 'utf8') }),
1187
+ 'persistent-refine-2': fingerprint({ bytes: readFileSync(persistentPath, 'utf8') }),
1188
+ }
1189
+ const pairFingerprint = fingerprint({
1190
+ commonConfig: independent.get(ids[0]!)!.fingerprints.commonConfig,
1191
+ ids,
1192
+ phaseFiles: phaseFileFingerprints,
1193
+ prompt: independent.get(ids[0]!)!.fingerprints.prompt,
1194
+ source: independent.get(ids[0]!)!.fingerprints.source,
1195
+ tools: independent.get(ids[0]!)!.fingerprints.tools,
1196
+ executions: ids.map((id) => independent.get(id)!.executionFingerprint),
1197
+ })
1198
+ const judged = loadJudgeRows(out)
1199
+ const arms: Array<{ arm: ExperimentArm; path: string; rows: Map<string, PhaseARow> }> = [
1200
+ { arm: 'independent-2', path: independentPath, rows: independent },
1201
+ { arm: 'persistent-refine-2', path: persistentPath, rows: persistent },
1202
+ ]
1203
+ for (const existing of judged.values()) {
1204
+ const input = arms.find(({ arm }) => arm === existing.arm)?.rows.get(existing.instanceId)
1205
+ if (!input) throw new Error(`${out}: judge resume row has no paired Phase-A input`)
1206
+ assertJudgeCompletionMatchesInput(existing, input.finalDiff, `${out}:${existing.arm}:${existing.instanceId}`)
1207
+ assertJudgeResumeFingerprints(existing, {
1208
+ pairFingerprint,
1209
+ phaseFileFingerprint: phaseFileFingerprints[existing.arm],
1210
+ inputFingerprint: input.fingerprints.composite,
1211
+ executionFingerprint: input.executionFingerprint,
1212
+ finalDiffHash: input.finalDiffHash,
1213
+ }, `${out}:${existing.arm}:${existing.instanceId}`)
1214
+ }
1215
+
1216
+ console.log(`all ${2 * ids.length} Phase-A rows matched; official scoring starts now (serialized)`)
1217
+ for (const id of ids) {
1218
+ for (const { arm, rows } of arms) {
1219
+ const key = `${arm}:${id}`
1220
+ if (judged.has(key)) continue
1221
+ const input = rows.get(id)!
1222
+ const started = Date.now()
1223
+ // Fail without appending: a transient official-scorer error must be retried on resume.
1224
+ const { hiddenResolved, judgeDetail, judgeSkipped } = await completeJudgeScore(
1225
+ input.finalDiff,
1226
+ async () => {
1227
+ const task = taskById.get(id)!
1228
+ process.env.SWEBENCH_NAMESPACE = input.execution!.image.namespace
1229
+ await assertOfficialScoreImagePinned(input, task, `${key}:before`)
1230
+ const score = await env.adapter.judge(task, input.finalDiff)
1231
+ await assertOfficialScoreImagePinned(input, task, `${key}:after`)
1232
+ return score
1233
+ },
1234
+ )
1235
+ const row: JudgeRow = {
1236
+ schema: 'swe-structural-judge-v2',
1237
+ instanceId: id,
1238
+ arm,
1239
+ pairFingerprint,
1240
+ phaseFileFingerprint: phaseFileFingerprints[arm],
1241
+ inputFingerprint: input.fingerprints.composite,
1242
+ executionFingerprint: input.executionFingerprint,
1243
+ finalDiffHash: input.finalDiffHash,
1244
+ hiddenResolved,
1245
+ judgeDetail,
1246
+ judgeMs: Date.now() - started,
1247
+ judgeSkipped,
1248
+ }
1249
+ judged.set(key, row)
1250
+ appendFileSync(out, `${JSON.stringify(row)}\n`)
1251
+ console.log(`[judge] ${key} resolved=${hiddenResolved} skipped=${judgeSkipped ?? '-'}`)
1252
+ }
1253
+ }
1254
+ }
1255
+
1256
+ const main = MODE === 'generate' ? generateMain : judgeOnlyMain
1257
+ main().catch((e) => {
1258
+ console.error(e instanceof Error ? (e.stack ?? e.message) : String(e))
1259
+ process.exit(1)
1260
+ })