@tangle-network/agent-bench 0.3.6 → 0.3.8
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.
- package/CHANGELOG.md +11 -0
- package/HARNESS.md +43 -0
- package/dist/adapters.js +24 -24
- package/dist/benchmarks/_harness.d.ts +1 -1
- package/dist/benchmarks/_harness.js +1 -1
- package/dist/benchmarks/aec-bench.js +2 -2
- package/dist/benchmarks/agentbench.js +2 -2
- package/dist/benchmarks/appworld.js +2 -2
- package/dist/benchmarks/bfcl.js +2 -2
- package/dist/benchmarks/commit0.js +2 -2
- package/dist/benchmarks/crag.js +2 -2
- package/dist/benchmarks/dabstep.js +2 -2
- package/dist/benchmarks/enterpriseops-gym.js +2 -2
- package/dist/benchmarks/finresearchbench.js +2 -2
- package/dist/benchmarks/humaneval.d.ts +10 -1
- package/dist/benchmarks/humaneval.js +5 -3
- package/dist/benchmarks/nomiracl.js +2 -2
- package/dist/benchmarks/open-rag-bench.js +2 -2
- package/dist/benchmarks/programbench.js +2 -2
- package/dist/benchmarks/ragbench.js +2 -2
- package/dist/benchmarks/swe-bench.js +2 -2
- package/dist/benchmarks/t2-ragbench.js +2 -2
- package/dist/benchmarks/tau-bench-shared.js +2 -2
- package/dist/benchmarks/tau2-bench.js +3 -3
- package/dist/benchmarks/tau3-banking.js +3 -3
- package/dist/benchmarks/terminal-bench.js +2 -2
- package/dist/benchmarks/toollm.js +2 -2
- package/dist/benchmarks/webarena-verified.js +2 -2
- package/dist/{chunk-CKUVRZ2T.js → chunk-3U5TXJZS.js} +2 -2
- package/dist/{chunk-PPYSEKFM.js → chunk-5H5XV76F.js} +73 -15
- package/dist/chunk-5H5XV76F.js.map +1 -0
- package/dist/{chunk-YCGY7UIZ.js → chunk-7GRVHU22.js} +2 -2
- package/dist/{chunk-Z7ML6L77.js → chunk-HWST3SED.js} +2 -2
- package/dist/{chunk-SYDW647C.js → chunk-IA2FBTWC.js} +2 -2
- package/dist/{chunk-R67DFVLO.js → chunk-IFVINJ4B.js} +2 -2
- package/dist/{chunk-R36V2VP7.js → chunk-IZ5M6OAC.js} +2 -2
- package/dist/{chunk-ODT47UAY.js → chunk-K3BQGZCT.js} +2 -2
- package/dist/{chunk-IFAV6KEM.js → chunk-KP5KD6EN.js} +2 -2
- package/dist/{chunk-ZEWMTR5M.js → chunk-MQMRLGOG.js} +2 -2
- package/dist/{chunk-TSWPNOYM.js → chunk-NQG5XDSB.js} +2 -2
- package/dist/{chunk-7WSD27QQ.js → chunk-PB64GYIG.js} +2 -2
- package/dist/{chunk-HBSWHQNJ.js → chunk-RCYQEFNX.js} +3 -3
- package/dist/{chunk-J3KDJNX2.js → chunk-RH5F53JT.js} +2 -2
- package/dist/{chunk-UAIOHCUK.js → chunk-SFLA7OH3.js} +3 -3
- package/dist/{chunk-Y6O2OCUO.js → chunk-SHM6MRRF.js} +2 -2
- package/dist/{chunk-KDIKRJGB.js → chunk-SHYIRB7I.js} +2 -2
- package/dist/{chunk-HHXFIHXC.js → chunk-SVR2LKYI.js} +2 -2
- package/dist/{chunk-5SBJCB6W.js → chunk-V7AEBY6U.js} +22 -22
- package/dist/{chunk-LRRD7NAG.js → chunk-WSKWVEQB.js} +18 -2
- package/dist/chunk-WSKWVEQB.js.map +1 -0
- package/dist/{chunk-2PVVP7GN.js → chunk-XKEFIFIC.js} +2 -2
- package/dist/{chunk-JRWWGMK7.js → chunk-XYA4XSNU.js} +2 -2
- package/dist/{chunk-X5YKXC6V.js → chunk-YSMEKBTD.js} +2 -2
- package/dist/{chunk-2XU6OGEN.js → chunk-Z4TZ76N7.js} +2 -2
- package/dist/index.js +24 -24
- package/package.json +6 -5
- package/scripts/run-package-tests.mjs +30 -8
- package/scripts/verify-packed-consumer.mjs +1 -1
- package/scripts/verify-pier-agent.mts +1 -0
- package/src/benchmarks/_harness.ts +20 -2
- package/src/benchmarks/humaneval.test.mts +122 -0
- package/src/benchmarks/humaneval.ts +100 -27
- package/src/david-attribution.mts +78 -0
- package/src/david-goliath.mts +149 -0
- package/src/hev-improve.mts +25 -6
- package/src/humaneval-object-ablation.mts +201 -0
- package/src/live-improve-campaign-mbpp.mts +641 -0
- package/src/live-improve-campaign.mts +500 -0
- package/src/mbpp-structural.mts +12 -7
- package/src/quant-arena/README.md +144 -0
- package/src/quant-arena/backtest.test.mts +135 -0
- package/src/quant-arena/backtest.ts +218 -0
- package/src/quant-arena/data.test.mts +44 -0
- package/src/quant-arena/data.ts +141 -0
- package/src/quant-arena/driver.test.mts +253 -0
- package/src/quant-arena/driver.ts +219 -0
- package/src/quant-arena/fixtures/data/PROVENANCE.md +26 -0
- package/src/quant-arena/fixtures/data/holdout/IDX.csv +523 -0
- package/src/quant-arena/fixtures/data/holdout/S01.csv +523 -0
- package/src/quant-arena/fixtures/data/holdout/S02.csv +523 -0
- package/src/quant-arena/fixtures/data/holdout/S03.csv +523 -0
- package/src/quant-arena/fixtures/data/holdout/S04.csv +523 -0
- package/src/quant-arena/fixtures/data/holdout/S05.csv +523 -0
- package/src/quant-arena/fixtures/data/holdout/S06.csv +523 -0
- package/src/quant-arena/fixtures/data/holdout/S07.csv +523 -0
- package/src/quant-arena/fixtures/data/holdout/S08.csv +523 -0
- package/src/quant-arena/fixtures/data/holdout/S09.csv +523 -0
- package/src/quant-arena/fixtures/data/holdout/S10.csv +523 -0
- package/src/quant-arena/fixtures/data/insample/IDX.csv +2087 -0
- package/src/quant-arena/fixtures/data/insample/S01.csv +2087 -0
- package/src/quant-arena/fixtures/data/insample/S02.csv +2087 -0
- package/src/quant-arena/fixtures/data/insample/S03.csv +2087 -0
- package/src/quant-arena/fixtures/data/insample/S04.csv +2087 -0
- package/src/quant-arena/fixtures/data/insample/S05.csv +2087 -0
- package/src/quant-arena/fixtures/data/insample/S06.csv +2087 -0
- package/src/quant-arena/fixtures/data/insample/S07.csv +2087 -0
- package/src/quant-arena/fixtures/data/insample/S08.csv +2087 -0
- package/src/quant-arena/fixtures/data/insample/S09.csv +2087 -0
- package/src/quant-arena/fixtures/data/insample/S10.csv +2087 -0
- package/src/quant-arena/fixtures/demo-campaign/cost-ledger.jsonl +16 -0
- package/src/quant-arena/fixtures/demo-campaign/notebook.jsonl +5 -0
- package/src/quant-arena/fixtures/demo-campaign/rollout-manifest.json +171 -0
- package/src/quant-arena/fixtures/demo-campaign/strategies/cand-001-default-author/strategy.ts +119 -0
- package/src/quant-arena/fixtures/demo-campaign/strategies/cand-002-default-author/strategy.ts +119 -0
- package/src/quant-arena/fixtures/demo-campaign/strategies/cand-003-quant-researcher/strategy.ts +105 -0
- package/src/quant-arena/fixtures/demo-campaign/strategies/cand-004-quant-researcher/strategy.ts +102 -0
- package/src/quant-arena/fixtures/demo-campaign-v2/cost-ledger.jsonl +4 -0
- package/src/quant-arena/fixtures/demo-campaign-v2/notebook.jsonl +2 -0
- package/src/quant-arena/fixtures/demo-campaign-v2/rollout-manifest.json +84 -0
- package/src/quant-arena/fixtures/demo-campaign-v2/strategies/cand-001-quant-researcher/strategy.ts +117 -0
- package/src/quant-arena/holdout-certify.mts +206 -0
- package/src/quant-arena/holdout-certify.test.mts +82 -0
- package/src/quant-arena/leak-audit.test.mts +79 -0
- package/src/quant-arena/leak-audit.ts +95 -0
- package/src/quant-arena/make-fixtures.mts +161 -0
- package/src/quant-arena/multiplicity.test.mts +68 -0
- package/src/quant-arena/multiplicity.ts +87 -0
- package/src/quant-arena/nautilus-certify.ts +31 -0
- package/src/quant-arena/oms.ts +90 -0
- package/src/quant-arena/profiles/quant-researcher.profile.json +7 -0
- package/src/quant-arena/python/pyproject.toml +8 -0
- package/src/quant-arena/python/uv.lock +1297 -0
- package/src/quant-arena/python/vbt-worker.py +192 -0
- package/src/quant-arena/quant-loop.mts +813 -0
- package/src/quant-arena/quant-loop.test.mts +75 -0
- package/src/quant-arena/strategies/buy-hold-index/strategy.ts +11 -0
- package/src/quant-arena/strategies/equal-weight/strategy.ts +20 -0
- package/src/quant-arena/strategies/sma-crossover/strategy.ts +42 -0
- package/src/quant-arena/types.ts +133 -0
- package/src/quant-arena/vbt-client.ts +321 -0
- package/src/quant-arena/vbt-parity.test.mts +183 -0
- package/src/quant-arena/windows.test.mts +45 -0
- package/src/quant-arena/windows.ts +54 -0
- package/src/rollout-ledger/backfill-swe-arena.mts +606 -0
- package/src/rollout-ledger/backfill-swe-arena.test.mts +338 -0
- package/src/rollout-ledger/settle-capture.mts +442 -0
- package/src/rollout-ledger/settle-capture.test.mts +270 -0
- package/src/stream-observe.py +45 -0
- package/src/stream-observe.tpl.html +247 -0
- package/src/supervisor-arena.mts +816 -0
- package/src/swe-arena/activation.mts +228 -0
- package/src/swe-arena/activation.test.mts +303 -0
- package/src/swe-arena/analyze.ts +211 -0
- package/src/swe-arena/arms.ts +804 -0
- package/src/swe-arena/bootstrap-meta.mts +188 -0
- package/src/swe-arena/bootstrap-meta.test.mts +51 -0
- package/src/swe-arena/briefing.mts +217 -0
- package/src/swe-arena/briefing.test.mts +178 -0
- package/src/swe-arena/calibrate.ts +217 -0
- package/src/swe-arena/capabilities.mts +76 -0
- package/src/swe-arena/capabilities.test.mts +57 -0
- package/src/swe-arena/capacity.ts +194 -0
- package/src/swe-arena/cell-evidence.mts +437 -0
- package/src/swe-arena/cell-evidence.test.mts +248 -0
- package/src/swe-arena/diagnosis-ensemble.test.mts +210 -0
- package/src/swe-arena/diagnosis-ensemble.ts +520 -0
- package/src/swe-arena/execution.test.mts +1170 -0
- package/src/swe-arena/factory-command-container.ts +284 -0
- package/src/swe-arena/factory-judge-child.mts +228 -0
- package/src/swe-arena/factory.test.mts +643 -0
- package/src/swe-arena/fixtures/analyze.py +80 -0
- package/src/swe-arena/fixtures/excludes.txt +8 -0
- package/src/swe-arena/fixtures/factory/agent-eval-309/calibration.md +51 -0
- package/src/swe-arena/fixtures/factory/agent-eval-309/manifest.json +29 -0
- package/src/swe-arena/fixtures/factory/agent-eval-309/spec.md +64 -0
- package/src/swe-arena/fixtures/factory/agent-runtime-232/calibration.md +48 -0
- package/src/swe-arena/fixtures/factory/agent-runtime-232/manifest.json +29 -0
- package/src/swe-arena/fixtures/factory/agent-runtime-232/spec.md +48 -0
- package/src/swe-arena/fixtures/factory/loops-28/calibration.md +47 -0
- package/src/swe-arena/fixtures/factory/loops-28/manifest.json +30 -0
- package/src/swe-arena/fixtures/factory/loops-28/spec.md +50 -0
- package/src/swe-arena/fixtures/gen1-salvage/README.md +45 -0
- package/src/swe-arena/fixtures/gen1-salvage/cand0-e6d7361.diff +116 -0
- package/src/swe-arena/fixtures/gen1-salvage/cand1-76a8590.diff +293 -0
- package/src/swe-arena/fixtures/holdout-preregister.log +12 -0
- package/src/swe-arena/fixtures/holdout.json +44 -0
- package/src/swe-arena/fixtures/instances.json +146 -0
- package/src/swe-arena/fixtures/ledger.jsonl +12 -0
- package/src/swe-arena/fixtures/patches/pallets__flask-5014.solo.patch +36 -0
- package/src/swe-arena/fixtures/patches/pydata__xarray-4687.sup.patch +33 -0
- package/src/swe-arena/fixtures/rejudge.jsonl +15 -0
- package/src/swe-arena/fixtures/rematch.jsonl +3 -0
- package/src/swe-arena/fixtures/rematch2.jsonl +3 -0
- package/src/swe-arena/fixtures/rematch3.jsonl +3 -0
- package/src/swe-arena/fixtures/run-report/README.md +43 -0
- package/src/swe-arena/fixtures/run-report/factory-agent-eval-309-FSUP0.json +173 -0
- package/src/swe-arena/fixtures/run-report/factory-agent-eval-309-FSUP0.md +100 -0
- package/src/swe-arena/fixtures/run-report/gen3-rollup.json +551 -0
- package/src/swe-arena/fixtures/run-report/gen3-rollup.md +64 -0
- package/src/swe-arena/fixtures/sup-journal-true.json +19 -0
- package/src/swe-arena/fixtures/verify/astropy__astropy-13033.sh +48 -0
- package/src/swe-arena/fixtures/verify/django__django-11532.sh +50 -0
- package/src/swe-arena/fixtures/verify/matplotlib__matplotlib-20826.sh +76 -0
- package/src/swe-arena/fixtures/verify/pydata__xarray-4687.sh +44 -0
- package/src/swe-arena/fixtures/verify/pytest-dev__pytest-6197.sh +32 -0
- package/src/swe-arena/fixtures/verify/sphinx-doc__sphinx-9658.sh +51 -0
- package/src/swe-arena/fixtures/worker-tokens.json +42 -0
- package/src/swe-arena/fixtures.ts +237 -0
- package/src/swe-arena/gepa-seat.mts +583 -0
- package/src/swe-arena/gepa-seat.test.mts +635 -0
- package/src/swe-arena/holdout-certify.mts +408 -0
- package/src/swe-arena/holdout-certify.test.mts +160 -0
- package/src/swe-arena/judge-child.mts +37 -0
- package/src/swe-arena/ledger-orphans.mts +77 -0
- package/src/swe-arena/ledger-orphans.test.mts +147 -0
- package/src/swe-arena/lineage-record.mts +164 -0
- package/src/swe-arena/lineage-record.test.mts +115 -0
- package/src/swe-arena/manifest.mts +293 -0
- package/src/swe-arena/manifest.test.mts +169 -0
- package/src/swe-arena/materialize.ts +142 -0
- package/src/swe-arena/outer-loop.mts +2795 -0
- package/src/swe-arena/outer-loop.test.mts +696 -0
- package/src/swe-arena/parity.test.mts +87 -0
- package/src/swe-arena/premeasured-from-cells.mts +281 -0
- package/src/swe-arena/premeasured-from-cells.test.mts +180 -0
- package/src/swe-arena/proc.test.mts +174 -0
- package/src/swe-arena/proc.ts +260 -0
- package/src/swe-arena/profiles/default-author.profile.json +4 -0
- package/src/swe-arena/proposer-fanout.mts +770 -0
- package/src/swe-arena/proposer-fanout.test.mts +619 -0
- package/src/swe-arena/proposer-provenance.mts +177 -0
- package/src/swe-arena/proposer-provenance.test.mts +106 -0
- package/src/swe-arena/reconcile.ts +0 -0
- package/src/swe-arena/replay.mts +183 -0
- package/src/swe-arena/replay.test.mts +300 -0
- package/src/swe-arena/run-experiment.mts +727 -0
- package/src/swe-arena/run-report.mts +75 -0
- package/src/swe-arena/run-supervisor.mjs +297 -0
- package/src/swe-arena/run-supervisor.test.mts +500 -0
- package/src/swe-arena/score-split.mts +140 -0
- package/src/swe-arena/score-split.test.mts +123 -0
- package/src/swe-arena/serialized-judge.ts +414 -0
- package/src/swe-arena/types.ts +218 -0
- package/src/swe-code-improve.mts +328 -0
- package/src/swe-emit-patch.mts +104 -0
- package/src/swe-improve.mts +232 -0
- package/src/swe-jail.ts +2 -2
- package/src/swe-local-proof.mts +169 -0
- package/src/swe-repro-calibrate.mts +446 -0
- package/src/swe-stream.mts +1497 -0
- package/src/swe-structural.mts +245 -837
- package/dist/chunk-LRRD7NAG.js.map +0 -1
- package/dist/chunk-PPYSEKFM.js.map +0 -1
- /package/dist/{chunk-CKUVRZ2T.js.map → chunk-3U5TXJZS.js.map} +0 -0
- /package/dist/{chunk-YCGY7UIZ.js.map → chunk-7GRVHU22.js.map} +0 -0
- /package/dist/{chunk-Z7ML6L77.js.map → chunk-HWST3SED.js.map} +0 -0
- /package/dist/{chunk-SYDW647C.js.map → chunk-IA2FBTWC.js.map} +0 -0
- /package/dist/{chunk-R67DFVLO.js.map → chunk-IFVINJ4B.js.map} +0 -0
- /package/dist/{chunk-R36V2VP7.js.map → chunk-IZ5M6OAC.js.map} +0 -0
- /package/dist/{chunk-ODT47UAY.js.map → chunk-K3BQGZCT.js.map} +0 -0
- /package/dist/{chunk-IFAV6KEM.js.map → chunk-KP5KD6EN.js.map} +0 -0
- /package/dist/{chunk-ZEWMTR5M.js.map → chunk-MQMRLGOG.js.map} +0 -0
- /package/dist/{chunk-TSWPNOYM.js.map → chunk-NQG5XDSB.js.map} +0 -0
- /package/dist/{chunk-7WSD27QQ.js.map → chunk-PB64GYIG.js.map} +0 -0
- /package/dist/{chunk-HBSWHQNJ.js.map → chunk-RCYQEFNX.js.map} +0 -0
- /package/dist/{chunk-J3KDJNX2.js.map → chunk-RH5F53JT.js.map} +0 -0
- /package/dist/{chunk-UAIOHCUK.js.map → chunk-SFLA7OH3.js.map} +0 -0
- /package/dist/{chunk-Y6O2OCUO.js.map → chunk-SHM6MRRF.js.map} +0 -0
- /package/dist/{chunk-KDIKRJGB.js.map → chunk-SHYIRB7I.js.map} +0 -0
- /package/dist/{chunk-HHXFIHXC.js.map → chunk-SVR2LKYI.js.map} +0 -0
- /package/dist/{chunk-5SBJCB6W.js.map → chunk-V7AEBY6U.js.map} +0 -0
- /package/dist/{chunk-2PVVP7GN.js.map → chunk-XKEFIFIC.js.map} +0 -0
- /package/dist/{chunk-JRWWGMK7.js.map → chunk-XYA4XSNU.js.map} +0 -0
- /package/dist/{chunk-X5YKXC6V.js.map → chunk-YSMEKBTD.js.map} +0 -0
- /package/dist/{chunk-2XU6OGEN.js.map → chunk-Z4TZ76N7.js.map} +0 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage 0 of the SWE-bench frontier push — the REPRODUCTION-ORACLE CALIBRATOR
|
|
3
|
+
* (contract: supervisor-lab/docs/results/PREREG-swe-frontier.md, Stage 0 only).
|
|
4
|
+
*
|
|
5
|
+
* Question it answers: can glm-5.2, given ONLY the issue text (+ up to 3 requested file reads),
|
|
6
|
+
* author a self-contained repro script that (a) FAILS on the unpatched tree — "validity" — and
|
|
7
|
+
* (b) PASSES after the GOLD patch — "soundness"? GATE: ≥60% of instances valid+sound (1 retry).
|
|
8
|
+
*
|
|
9
|
+
* No cheating by construction: the GOLD patch is used strictly script-side (applied host-side to a
|
|
10
|
+
* COPY of the tree, then run in the jail); a hard assert refuses to send any model message that
|
|
11
|
+
* contains gold-patch content. The repro runs in the instance's cached swebench Docker image with
|
|
12
|
+
* the tree mounted READ-ONLY — the byte-identical invocation pattern of swe-bench-env's `run` tool
|
|
13
|
+
* (conda testbed, cwd=/testbed, --network none, dual timeout) — so calibration measures the same
|
|
14
|
+
* substrate Stage 1/2 will select patches on.
|
|
15
|
+
*
|
|
16
|
+
* cd ~/company/devops/secrets && dotenvx run -f agent-state.env -f tangle-router.env -- bash -c \
|
|
17
|
+
* 'cd ~/code/agent-runtime-swe && OUT=/path/swe-stage0.jsonl node_modules/.bin/tsx bench/src/swe-repro-calibrate.mts'
|
|
18
|
+
*
|
|
19
|
+
* Env: ZAI_API_KEY (required unless CANARY_ONLY), ZAI_BASE, MODEL=glm-5.2, MAX_TOKENS=12000, TEMP=0.2,
|
|
20
|
+
* CONC=3, REPRO_TIMEOUT=120 (s), LLM_TIMEOUT_MS=480000, IDS=comma-list override, OUT=jsonl path,
|
|
21
|
+
* REPRO_EXEC=mount|image (execution substrate; see the constant below),
|
|
22
|
+
* CANARY_ONLY=1 (run ONLY the per-instance execution canary — no model calls, no grading —
|
|
23
|
+
* to decide which substrate is trustworthy per instance before spending on authoring).
|
|
24
|
+
*/
|
|
25
|
+
import { execFile } from 'node:child_process'
|
|
26
|
+
import { appendFileSync, cpSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
|
27
|
+
import { tmpdir } from 'node:os'
|
|
28
|
+
import { join } from 'node:path'
|
|
29
|
+
import { promisify } from 'node:util'
|
|
30
|
+
import type { AgenticTask, ArtifactHandle } from '@tangle-network/agent-runtime/loops'
|
|
31
|
+
import type { BenchTask } from './benchmarks/types'
|
|
32
|
+
import { createSweBenchEnvironment, resolveImageForMetadata } from './swe-bench-env'
|
|
33
|
+
import {
|
|
34
|
+
APPLY_SENTINEL,
|
|
35
|
+
cachedInstanceIds,
|
|
36
|
+
extractReadRequests as extractReads,
|
|
37
|
+
extractReproScript as extractScript,
|
|
38
|
+
IMPORT_NAME,
|
|
39
|
+
importCanaryScript,
|
|
40
|
+
type JailRun,
|
|
41
|
+
reproAuthorSystem,
|
|
42
|
+
runPyInJail,
|
|
43
|
+
tail,
|
|
44
|
+
zaiChatRaw,
|
|
45
|
+
} from './swe-jail'
|
|
46
|
+
|
|
47
|
+
const exec = promisify(execFile)
|
|
48
|
+
|
|
49
|
+
// ---------- config ----------
|
|
50
|
+
|
|
51
|
+
const ZAI_BASE = process.env.ZAI_BASE ?? 'https://api.z.ai/api/coding/paas/v4'
|
|
52
|
+
const ZAI_KEY = process.env.ZAI_API_KEY ?? ''
|
|
53
|
+
const MODEL = process.env.MODEL ?? 'glm-5.2'
|
|
54
|
+
// glm-5.2 is a reasoning model: hidden reasoning consumes max_tokens, so <8000 starves content.
|
|
55
|
+
const MAX_TOKENS = Number(process.env.MAX_TOKENS ?? 12_000)
|
|
56
|
+
const TEMP = Number(process.env.TEMP ?? 0.2)
|
|
57
|
+
const CONC = Math.max(1, Math.min(3, Number(process.env.CONC ?? 3)))
|
|
58
|
+
const REPRO_TIMEOUT_S = Number(process.env.REPRO_TIMEOUT ?? 120)
|
|
59
|
+
const LLM_TIMEOUT_MS = Number(process.env.LLM_TIMEOUT_MS ?? 480_000)
|
|
60
|
+
const OUT = process.env.OUT ?? 'swe-stage0.jsonl'
|
|
61
|
+
/** Repro EXECUTION substrate. `mount` (the prereg default) mounts the fresh host clone :ro over
|
|
62
|
+
* /testbed — the run tool's exact pattern. `image` executes against the image's OWN /testbed
|
|
63
|
+
* (base_commit, BUILT — compiled extensions and generated version files present), applying the
|
|
64
|
+
* gold patch in-container instead of host-side. Measured on the 23 cached instances: `mount`
|
|
65
|
+
* kills 6 (astropy×2/matplotlib/sklearn×2/pytest) with import errors a fresh un-built clone
|
|
66
|
+
* cannot avoid; the SAME scripts were all valid+sound under `image`. */
|
|
67
|
+
const EXEC = process.env.REPRO_EXEC ?? 'mount'
|
|
68
|
+
if (EXEC !== 'mount' && EXEC !== 'image') throw new Error(`REPRO_EXEC must be mount|image, got ${EXEC}`)
|
|
69
|
+
/** Canary-only sweep: measure per-instance substrate trustworthiness (gold applied, import resolves
|
|
70
|
+
* into the patched tree) across all instances with ZERO model calls. */
|
|
71
|
+
const CANARY_ONLY = process.env.CANARY_ONLY === '1'
|
|
72
|
+
|
|
73
|
+
// ---------- model client (swe-jail's zaiChatRaw: patient 429 ladder + empty-content retry —
|
|
74
|
+
// the glm reasoning path starves `content` when reasoning eats max_tokens) ----------
|
|
75
|
+
|
|
76
|
+
interface ChatMsg {
|
|
77
|
+
role: 'system' | 'user' | 'assistant'
|
|
78
|
+
content: string
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface Completion {
|
|
82
|
+
content: string
|
|
83
|
+
attempts: number
|
|
84
|
+
tokensIn: number
|
|
85
|
+
tokensOut: number
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function complete(messages: ChatMsg[]): Promise<Completion> {
|
|
89
|
+
const { json, attempts } = await zaiChatRaw(
|
|
90
|
+
{ base: ZAI_BASE, key: ZAI_KEY, timeoutMs: LLM_TIMEOUT_MS },
|
|
91
|
+
{ model: MODEL, max_tokens: MAX_TOKENS, temperature: TEMP, messages },
|
|
92
|
+
)
|
|
93
|
+
const d = json as {
|
|
94
|
+
choices?: Array<{ message?: { content?: string } }>
|
|
95
|
+
usage?: { prompt_tokens?: number; completion_tokens?: number }
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
content: d.choices?.[0]?.message?.content ?? '',
|
|
99
|
+
attempts,
|
|
100
|
+
tokensIn: d.usage?.prompt_tokens ?? 0,
|
|
101
|
+
tokensOut: d.usage?.completion_tokens ?? 0,
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ---------- authoring protocol (one optional read round, plain-text READ: lines) ----------
|
|
106
|
+
// The protocol constants/parsers now live in swe-jail.ts (shared with the stream driver);
|
|
107
|
+
// behavior here is byte-identical to the in-file originals.
|
|
108
|
+
|
|
109
|
+
const AUTHOR_SYSTEM = reproAuthorSystem(REPRO_TIMEOUT_S)
|
|
110
|
+
|
|
111
|
+
// ---------- per-instance row ----------
|
|
112
|
+
|
|
113
|
+
interface Row {
|
|
114
|
+
instanceId: string
|
|
115
|
+
repo: string
|
|
116
|
+
execMode: string
|
|
117
|
+
image: string | null
|
|
118
|
+
imagePresent: boolean
|
|
119
|
+
canaryExit: number | null
|
|
120
|
+
canaryOut: string
|
|
121
|
+
/** true = gold applied AND import resolved into the patched tree; false = this substrate cannot
|
|
122
|
+
* grade this instance; null = repo not in IMPORT_NAME (canary not applicable). */
|
|
123
|
+
canaryPass: boolean | null
|
|
124
|
+
readsRequested: string[]
|
|
125
|
+
authorCalls: number
|
|
126
|
+
retryUsed: boolean
|
|
127
|
+
preExitFirst: number | null
|
|
128
|
+
preExitFinal: number | null
|
|
129
|
+
preOut: string
|
|
130
|
+
valid: boolean
|
|
131
|
+
goldApplyOk: boolean | null
|
|
132
|
+
postExit: number | null
|
|
133
|
+
postOut: string
|
|
134
|
+
sound: boolean
|
|
135
|
+
validAndSound: boolean
|
|
136
|
+
autoClass: string
|
|
137
|
+
script: string | null
|
|
138
|
+
scriptFirst: string | null
|
|
139
|
+
tokensIn: number
|
|
140
|
+
tokensOut: number
|
|
141
|
+
wallMs: number
|
|
142
|
+
error?: string
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function calibrateInstance(
|
|
146
|
+
env: Awaited<ReturnType<typeof createSweBenchEnvironment>>,
|
|
147
|
+
bt: BenchTask,
|
|
148
|
+
): Promise<Row> {
|
|
149
|
+
const t0 = Date.now()
|
|
150
|
+
const id = bt.id
|
|
151
|
+
const row: Row = {
|
|
152
|
+
instanceId: id, repo: '', execMode: EXEC, image: null, imagePresent: false, canaryExit: null, canaryOut: '',
|
|
153
|
+
canaryPass: null, readsRequested: [], authorCalls: 0, retryUsed: false, preExitFirst: null, preExitFinal: null,
|
|
154
|
+
preOut: '', valid: false, goldApplyOk: null, postExit: null, postOut: '', sound: false,
|
|
155
|
+
validAndSound: false, autoClass: 'infra-error', script: null, scriptFirst: null,
|
|
156
|
+
tokensIn: 0, tokensOut: 0, wallMs: 0,
|
|
157
|
+
}
|
|
158
|
+
let handle: ArtifactHandle | null = null
|
|
159
|
+
let patchedDir: string | null = null
|
|
160
|
+
try {
|
|
161
|
+
// Metadata (issue + gold) comes from the adapter's task row, never the model path.
|
|
162
|
+
const md = bt.metadata as Record<string, string>
|
|
163
|
+
row.repo = md.repo
|
|
164
|
+
const gold = String(md.patch ?? '')
|
|
165
|
+
if (!gold.trim()) throw new Error('gold patch missing from metadata')
|
|
166
|
+
|
|
167
|
+
// 1. Hard-assert the cached docker image BEFORE paying for a clone or a model call.
|
|
168
|
+
const img = await resolveImageForMetadata(bt.metadata ?? {})
|
|
169
|
+
if (!img.ok) {
|
|
170
|
+
row.autoClass = 'image-missing'
|
|
171
|
+
row.error = img.reason
|
|
172
|
+
return row
|
|
173
|
+
}
|
|
174
|
+
row.image = img.tag
|
|
175
|
+
row.imagePresent = true
|
|
176
|
+
|
|
177
|
+
// 2. Open the environment: host clone at base_commit. The `mount` substrate jails against this
|
|
178
|
+
// tree :ro; the `image` substrate uses it only for list_files/read_file during authoring — so a
|
|
179
|
+
// canary-only image sweep skips the clone (and its network cost) entirely.
|
|
180
|
+
let treeDir: string | null = null
|
|
181
|
+
if (EXEC === 'mount' || !CANARY_ONLY) {
|
|
182
|
+
const h = await env.environment.open({ id, systemPrompt: '', userPrompt: '', meta: {} } as AgenticTask)
|
|
183
|
+
handle = h
|
|
184
|
+
treeDir = h.id
|
|
185
|
+
}
|
|
186
|
+
const execTree = EXEC === 'image' ? null : treeDir
|
|
187
|
+
|
|
188
|
+
// Mount substrate: apply the gold patch host-side to a COPY of the tree UP FRONT — the canary
|
|
189
|
+
// must observe the tree exactly as the soundness run will mount it. A failed apply is terminal
|
|
190
|
+
// before any model call is spent.
|
|
191
|
+
if (EXEC === 'mount') {
|
|
192
|
+
patchedDir = mkdtempSync(join(tmpdir(), 'swe-gold-'))
|
|
193
|
+
cpSync(treeDir as string, patchedDir, { recursive: true })
|
|
194
|
+
const goldFile = join(patchedDir, '.swe-gold.patch')
|
|
195
|
+
writeFileSync(goldFile, gold.endsWith('\n') ? gold : `${gold}\n`)
|
|
196
|
+
try {
|
|
197
|
+
await exec('git', ['-C', patchedDir, 'apply', '--whitespace=nowarn', goldFile], { timeout: 60_000 })
|
|
198
|
+
row.goldApplyOk = true
|
|
199
|
+
} catch {
|
|
200
|
+
// Official-harness fallback: GNU patch with fuzz.
|
|
201
|
+
try {
|
|
202
|
+
await exec('patch', ['-p1', '--fuzz=5', '-i', goldFile], { cwd: patchedDir, timeout: 60_000 })
|
|
203
|
+
row.goldApplyOk = true
|
|
204
|
+
} catch (e2) {
|
|
205
|
+
row.goldApplyOk = false
|
|
206
|
+
row.autoClass = 'gold-apply-failed'
|
|
207
|
+
row.error = `gold patch failed to apply: ${(e2 as Error).message.slice(0, 200)}`
|
|
208
|
+
return row
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
rmSync(goldFile, { force: true })
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// EXECUTION CANARY (mode-deciding, zero model calls): with the gold patch applied to the tree
|
|
215
|
+
// under test, `import <pkg>` must succeed AND resolve INTO that tree. PYTHONPATH=/testbed is
|
|
216
|
+
// already pinned by runPyInJail, so a site-packages resolution here (exit 3) means this substrate
|
|
217
|
+
// would grade code the patch never reaches — the instance is env-unresolvable in this mode.
|
|
218
|
+
const pkg = IMPORT_NAME[md.repo]
|
|
219
|
+
if (pkg) {
|
|
220
|
+
const canaryScript = importCanaryScript(pkg)
|
|
221
|
+
const c = EXEC === 'image'
|
|
222
|
+
? await runPyInJail(img.tag, null, canaryScript, gold, { timeoutS: REPRO_TIMEOUT_S })
|
|
223
|
+
: await runPyInJail(img.tag, patchedDir, canaryScript, undefined, { timeoutS: REPRO_TIMEOUT_S })
|
|
224
|
+
if (c.infraError) throw new Error(c.infraError)
|
|
225
|
+
row.canaryExit = c.code
|
|
226
|
+
row.canaryOut = tail(c.out, 200)
|
|
227
|
+
if (EXEC === 'image') {
|
|
228
|
+
row.goldApplyOk = c.out.includes(APPLY_SENTINEL)
|
|
229
|
+
if (!row.goldApplyOk) {
|
|
230
|
+
row.autoClass = 'gold-apply-failed'
|
|
231
|
+
row.error = `gold patch failed to apply in-container: ${tail(c.out, 200)}`
|
|
232
|
+
return row
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
row.canaryPass = c.code === 0
|
|
236
|
+
if (!row.canaryPass) {
|
|
237
|
+
row.autoClass = 'env-unresolvable'
|
|
238
|
+
row.error = `canary: import ${pkg} did not resolve into the patched tree (exit ${c.code})`
|
|
239
|
+
return row
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (CANARY_ONLY) {
|
|
243
|
+
row.autoClass = row.canaryPass === true ? 'canary-pass' : 'canary-unknown'
|
|
244
|
+
return row
|
|
245
|
+
}
|
|
246
|
+
const h = handle as ArtifactHandle
|
|
247
|
+
|
|
248
|
+
// 3. Author the repro: issue text + top-level listing; ONE optional read round (≤3 files).
|
|
249
|
+
const listing = String(await env.environment.call(h, 'list_files', { dir: '' })).slice(0, 5_000)
|
|
250
|
+
const issue = String(md.problem_statement ?? '').slice(0, 20_000)
|
|
251
|
+
const messages: ChatMsg[] = [
|
|
252
|
+
{ role: 'system', content: AUTHOR_SYSTEM },
|
|
253
|
+
{
|
|
254
|
+
role: 'user',
|
|
255
|
+
content:
|
|
256
|
+
`Repository: ${md.repo} (checked out at the commit where the bug is PRESENT).\n\n` +
|
|
257
|
+
`Repository file listing (top levels):\n${listing}\n\n--- Issue ---\n${issue}\n\n--- Instructions ---\n` +
|
|
258
|
+
'If you need to see specific source files before writing the script, reply with ONLY read requests, ' +
|
|
259
|
+
'one per line, at most 3, in the form:\nREAD: path/relative/to/repo/root\n' +
|
|
260
|
+
'Otherwise reply now with the final script in a single ```python fenced block.',
|
|
261
|
+
},
|
|
262
|
+
]
|
|
263
|
+
// Leak guard: no model message may carry gold-patch content. A distinctive added line is the sentinel.
|
|
264
|
+
const goldMark = gold.split('\n').find((l) => l.startsWith('+') && !l.startsWith('+++') && l.trim().length > 12)?.slice(0, 80)
|
|
265
|
+
const guardedComplete = async (msgs: ChatMsg[]): Promise<Completion> => {
|
|
266
|
+
if (goldMark && msgs.some((m) => m.content.includes(goldMark))) {
|
|
267
|
+
throw new Error('REFUSED: gold patch content leaked into model messages')
|
|
268
|
+
}
|
|
269
|
+
const c = await complete(msgs)
|
|
270
|
+
row.authorCalls += 1
|
|
271
|
+
row.tokensIn += c.tokensIn
|
|
272
|
+
row.tokensOut += c.tokensOut
|
|
273
|
+
return c
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
let resp = await guardedComplete(messages)
|
|
277
|
+
let script = extractScript(resp.content)
|
|
278
|
+
if (!script) {
|
|
279
|
+
const reads = extractReads(resp.content)
|
|
280
|
+
row.readsRequested = reads
|
|
281
|
+
messages.push({ role: 'assistant', content: resp.content })
|
|
282
|
+
if (reads.length) {
|
|
283
|
+
const bodies: string[] = []
|
|
284
|
+
for (const p of reads) {
|
|
285
|
+
const c = String(await env.environment.call(h, 'read_file', { path: p }))
|
|
286
|
+
bodies.push(`----- ${p} -----\n${c.slice(0, 12_000)}${c.length > 12_000 ? '\n…[truncated]' : ''}`)
|
|
287
|
+
}
|
|
288
|
+
messages.push({
|
|
289
|
+
role: 'user',
|
|
290
|
+
content: `${bodies.join('\n\n')}\n\nNow reply with the final script in a single \`\`\`python fenced block.`,
|
|
291
|
+
})
|
|
292
|
+
} else {
|
|
293
|
+
messages.push({ role: 'user', content: 'Reply with ONLY the final Python script in a single ```python fenced block.' })
|
|
294
|
+
}
|
|
295
|
+
resp = await guardedComplete(messages)
|
|
296
|
+
script = extractScript(resp.content)
|
|
297
|
+
}
|
|
298
|
+
if (!script) {
|
|
299
|
+
row.autoClass = 'authoring-failed'
|
|
300
|
+
row.error = `no script in response: ${resp.content.slice(0, 200)}`
|
|
301
|
+
return row
|
|
302
|
+
}
|
|
303
|
+
row.script = script
|
|
304
|
+
|
|
305
|
+
// 4. VALIDITY: the script must indicate bug-present (nonzero, non-timeout) on the UNPATCHED tree.
|
|
306
|
+
let pre = await runPyInJail(img.tag, execTree, script, undefined, { timeoutS: REPRO_TIMEOUT_S })
|
|
307
|
+
if (pre.infraError) throw new Error(pre.infraError)
|
|
308
|
+
row.preExitFirst = pre.code
|
|
309
|
+
let detected = pre.code !== 0 && !pre.timedOut
|
|
310
|
+
if (!detected) {
|
|
311
|
+
// One retry with feedback, per the prereg.
|
|
312
|
+
row.retryUsed = true
|
|
313
|
+
row.scriptFirst = script
|
|
314
|
+
const feedback = pre.timedOut
|
|
315
|
+
? `your script timed out after ${REPRO_TIMEOUT_S}s on the known-buggy code. Write a faster, simpler script that still detects the bug.`
|
|
316
|
+
: 'your script did not detect the bug on the known-buggy code: it exited 0 on the UNPATCHED repository. ' +
|
|
317
|
+
`Its output was:\n${tail(pre.out, 1_500)}\nWrite a corrected script that FAILS (nonzero exit) on the buggy code.`
|
|
318
|
+
messages.push({ role: 'assistant', content: `\`\`\`python\n${script}\n\`\`\`` }, { role: 'user', content: feedback })
|
|
319
|
+
const retry = await guardedComplete(messages)
|
|
320
|
+
const script2 = extractScript(retry.content)
|
|
321
|
+
if (script2) {
|
|
322
|
+
script = script2
|
|
323
|
+
row.script = script2
|
|
324
|
+
pre = await runPyInJail(img.tag, execTree, script2, undefined, { timeoutS: REPRO_TIMEOUT_S })
|
|
325
|
+
if (pre.infraError) throw new Error(pre.infraError)
|
|
326
|
+
detected = pre.code !== 0 && !pre.timedOut
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
row.preExitFinal = pre.code
|
|
330
|
+
row.preOut = tail(pre.out, 1_500)
|
|
331
|
+
row.valid = detected
|
|
332
|
+
if (!row.valid) {
|
|
333
|
+
row.autoClass = pre.timedOut ? 'invalid-timeout' : 'invalid-exit0'
|
|
334
|
+
return row
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// 5. SOUNDNESS (script-side only): gold patch applied, same jail, must exit 0.
|
|
338
|
+
let post: JailRun
|
|
339
|
+
if (EXEC === 'image') {
|
|
340
|
+
// Gold applied in-container to the image's built /testbed; a failed apply surfaces as exit≠0
|
|
341
|
+
// with git's message in the output.
|
|
342
|
+
post = await runPyInJail(img.tag, null, script, gold, { timeoutS: REPRO_TIMEOUT_S })
|
|
343
|
+
if (post.infraError) throw new Error(post.infraError)
|
|
344
|
+
row.goldApplyOk = post.out.includes(APPLY_SENTINEL)
|
|
345
|
+
if (!row.goldApplyOk) {
|
|
346
|
+
row.autoClass = 'gold-apply-failed'
|
|
347
|
+
row.error = `gold patch failed to apply in-container: ${tail(post.out, 200)}`
|
|
348
|
+
return row
|
|
349
|
+
}
|
|
350
|
+
} else {
|
|
351
|
+
// Mount substrate: gold was already applied host-side to the canary-verified copy up front.
|
|
352
|
+
post = await runPyInJail(img.tag, patchedDir as string, script, undefined, { timeoutS: REPRO_TIMEOUT_S })
|
|
353
|
+
if (post.infraError) throw new Error(post.infraError)
|
|
354
|
+
}
|
|
355
|
+
row.postExit = post.code
|
|
356
|
+
row.postOut = tail(post.out, 1_500)
|
|
357
|
+
row.sound = post.code === 0
|
|
358
|
+
row.validAndSound = row.valid && row.sound
|
|
359
|
+
if (row.validAndSound) row.autoClass = 'ok'
|
|
360
|
+
else if (post.timedOut) row.autoClass = 'unsound-timeout'
|
|
361
|
+
else if (/ModuleNotFoundError|ImportError/.test(post.out)) row.autoClass = 'unsound-import-error'
|
|
362
|
+
else row.autoClass = 'unsound-still-failing'
|
|
363
|
+
return row
|
|
364
|
+
} catch (e) {
|
|
365
|
+
row.autoClass = row.autoClass === 'ok' ? 'infra-error' : row.autoClass
|
|
366
|
+
row.error = e instanceof Error ? e.message.slice(0, 400) : String(e).slice(0, 400)
|
|
367
|
+
return row
|
|
368
|
+
} finally {
|
|
369
|
+
row.wallMs = Date.now() - t0
|
|
370
|
+
if (patchedDir) rmSync(patchedDir, { recursive: true, force: true })
|
|
371
|
+
if (handle) await env.environment.close(handle).catch(() => {})
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// ---------- driver ----------
|
|
376
|
+
|
|
377
|
+
async function main(): Promise<void> {
|
|
378
|
+
if (!ZAI_KEY && !CANARY_ONLY) throw new Error('ZAI_API_KEY required (run under dotenvx: agent-state.env)')
|
|
379
|
+
const ids = process.env.IDS
|
|
380
|
+
? process.env.IDS.split(',').map((s) => s.trim()).filter(Boolean)
|
|
381
|
+
: await cachedInstanceIds()
|
|
382
|
+
if (!ids.length) throw new Error('no cached sweb.eval images found and no IDS given')
|
|
383
|
+
|
|
384
|
+
console.log(`═══ SWE-bench Stage 0 — ${CANARY_ONLY ? 'execution-canary sweep (no model calls)' : 'reproduction-oracle calibration'} ═══`)
|
|
385
|
+
console.log(`model=${MODEL} base=${ZAI_BASE} maxTokens=${MAX_TOKENS} temp=${TEMP} conc=${CONC} reproTimeout=${REPRO_TIMEOUT_S}s exec=${EXEC}`)
|
|
386
|
+
console.log(`instances (${ids.length}): ${ids.join(', ')}`)
|
|
387
|
+
console.log(`out=${OUT}`)
|
|
388
|
+
|
|
389
|
+
const env = await createSweBenchEnvironment(ids.length, { ids })
|
|
390
|
+
// One dataset scan for all instances; per-instance metadata (issue + gold) rides the BenchTask.
|
|
391
|
+
const taskById = new Map((await env.adapter.loadTasks({ ids, split: 'test' })).map((t) => [t.id, t]))
|
|
392
|
+
const missing = ids.filter((id) => !taskById.has(id))
|
|
393
|
+
if (missing.length) throw new Error(`instances not found in SWE-bench_Verified: ${missing.join(', ')}`)
|
|
394
|
+
const rows: Row[] = []
|
|
395
|
+
let next = 0
|
|
396
|
+
const worker = async (): Promise<void> => {
|
|
397
|
+
while (next < ids.length) {
|
|
398
|
+
const i = next++
|
|
399
|
+
const id = ids[i]
|
|
400
|
+
console.log(`[${i + 1}/${ids.length}] ${id} …`)
|
|
401
|
+
const row = await calibrateInstance(env, taskById.get(id) as BenchTask)
|
|
402
|
+
rows.push(row)
|
|
403
|
+
appendFileSync(OUT, `${JSON.stringify(row)}\n`)
|
|
404
|
+
console.log(
|
|
405
|
+
`[${i + 1}/${ids.length}] ${id} → ${row.autoClass}` +
|
|
406
|
+
` (pre=${row.preExitFinal ?? '-'} post=${row.postExit ?? '-'} retry=${row.retryUsed ? 'y' : 'n'}` +
|
|
407
|
+
` calls=${row.authorCalls} tok=${row.tokensIn}/${row.tokensOut} wall=${Math.round(row.wallMs / 1000)}s)` +
|
|
408
|
+
(row.error ? ` err=${row.error.slice(0, 120)}` : ''),
|
|
409
|
+
)
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
await Promise.all(Array.from({ length: CONC }, () => worker()))
|
|
413
|
+
|
|
414
|
+
// ---------- summary ----------
|
|
415
|
+
const n = rows.length
|
|
416
|
+
const present = rows.filter((r) => r.imagePresent).length
|
|
417
|
+
const valid = rows.filter((r) => r.valid).length
|
|
418
|
+
const sound = rows.filter((r) => r.validAndSound).length
|
|
419
|
+
const retried = rows.filter((r) => r.retryUsed).length
|
|
420
|
+
const classes = new Map<string, number>()
|
|
421
|
+
for (const r of rows) classes.set(r.autoClass, (classes.get(r.autoClass) ?? 0) + 1)
|
|
422
|
+
|
|
423
|
+
console.log('\n══ per-instance ══')
|
|
424
|
+
console.log('instance | class | canary | pre1 | preF | valid | goldApply | post | sound | retry | calls | tokIn/out | wall_s')
|
|
425
|
+
for (const r of [...rows].sort((a, b) => a.instanceId.localeCompare(b.instanceId))) {
|
|
426
|
+
const canary = r.canaryPass === null ? `?(${r.canaryExit ?? '-'})` : r.canaryPass ? 'pass' : `FAIL(${r.canaryExit})`
|
|
427
|
+
console.log(
|
|
428
|
+
`${r.instanceId} | ${r.autoClass} | ${canary} | ${r.preExitFirst ?? '-'} | ${r.preExitFinal ?? '-'} | ` +
|
|
429
|
+
`${r.valid ? 1 : 0} | ${r.goldApplyOk === null ? '-' : r.goldApplyOk ? 1 : 0} | ${r.postExit ?? '-'} | ${r.sound ? 1 : 0} | ` +
|
|
430
|
+
`${r.retryUsed ? 1 : 0} | ${r.authorCalls} | ${r.tokensIn}/${r.tokensOut} | ${Math.round(r.wallMs / 1000)}`,
|
|
431
|
+
)
|
|
432
|
+
}
|
|
433
|
+
console.log('\n══ summary ══')
|
|
434
|
+
console.log(`n=${n} imagePresent=${present} canaryPass=${rows.filter((r) => r.canaryPass === true).length} valid(bug detected pre-patch)=${valid} valid+sound=${sound} retryUsed=${retried}`)
|
|
435
|
+
console.log(`failure modes: ${[...classes.entries()].map(([k, v]) => `${k}=${v}`).join(' ')}`)
|
|
436
|
+
if (!CANARY_ONLY) {
|
|
437
|
+
const rate = n ? sound / n : 0
|
|
438
|
+
const pct = (100 * rate).toFixed(1)
|
|
439
|
+
console.log(`\nSTAGE-0 GATE (>=60% valid+sound): ${rate >= 0.6 ? 'PASS' : 'FAIL'} — ${sound}/${n} = ${pct}%`)
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
main().catch((e) => {
|
|
444
|
+
console.error(e instanceof Error ? (e.stack ?? e.message) : String(e))
|
|
445
|
+
process.exit(1)
|
|
446
|
+
})
|