@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.
Files changed (265) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/HARNESS.md +43 -0
  3. package/dist/adapters.js +24 -24
  4. package/dist/benchmarks/_harness.d.ts +1 -1
  5. package/dist/benchmarks/_harness.js +1 -1
  6. package/dist/benchmarks/aec-bench.js +2 -2
  7. package/dist/benchmarks/agentbench.js +2 -2
  8. package/dist/benchmarks/appworld.js +2 -2
  9. package/dist/benchmarks/bfcl.js +2 -2
  10. package/dist/benchmarks/commit0.js +2 -2
  11. package/dist/benchmarks/crag.js +2 -2
  12. package/dist/benchmarks/dabstep.js +2 -2
  13. package/dist/benchmarks/enterpriseops-gym.js +2 -2
  14. package/dist/benchmarks/finresearchbench.js +2 -2
  15. package/dist/benchmarks/humaneval.d.ts +10 -1
  16. package/dist/benchmarks/humaneval.js +5 -3
  17. package/dist/benchmarks/nomiracl.js +2 -2
  18. package/dist/benchmarks/open-rag-bench.js +2 -2
  19. package/dist/benchmarks/programbench.js +2 -2
  20. package/dist/benchmarks/ragbench.js +2 -2
  21. package/dist/benchmarks/swe-bench.js +2 -2
  22. package/dist/benchmarks/t2-ragbench.js +2 -2
  23. package/dist/benchmarks/tau-bench-shared.js +2 -2
  24. package/dist/benchmarks/tau2-bench.js +3 -3
  25. package/dist/benchmarks/tau3-banking.js +3 -3
  26. package/dist/benchmarks/terminal-bench.js +2 -2
  27. package/dist/benchmarks/toollm.js +2 -2
  28. package/dist/benchmarks/webarena-verified.js +2 -2
  29. package/dist/{chunk-CKUVRZ2T.js → chunk-3U5TXJZS.js} +2 -2
  30. package/dist/{chunk-PPYSEKFM.js → chunk-5H5XV76F.js} +73 -15
  31. package/dist/chunk-5H5XV76F.js.map +1 -0
  32. package/dist/{chunk-YCGY7UIZ.js → chunk-7GRVHU22.js} +2 -2
  33. package/dist/{chunk-Z7ML6L77.js → chunk-HWST3SED.js} +2 -2
  34. package/dist/{chunk-SYDW647C.js → chunk-IA2FBTWC.js} +2 -2
  35. package/dist/{chunk-R67DFVLO.js → chunk-IFVINJ4B.js} +2 -2
  36. package/dist/{chunk-R36V2VP7.js → chunk-IZ5M6OAC.js} +2 -2
  37. package/dist/{chunk-ODT47UAY.js → chunk-K3BQGZCT.js} +2 -2
  38. package/dist/{chunk-IFAV6KEM.js → chunk-KP5KD6EN.js} +2 -2
  39. package/dist/{chunk-ZEWMTR5M.js → chunk-MQMRLGOG.js} +2 -2
  40. package/dist/{chunk-TSWPNOYM.js → chunk-NQG5XDSB.js} +2 -2
  41. package/dist/{chunk-7WSD27QQ.js → chunk-PB64GYIG.js} +2 -2
  42. package/dist/{chunk-HBSWHQNJ.js → chunk-RCYQEFNX.js} +3 -3
  43. package/dist/{chunk-J3KDJNX2.js → chunk-RH5F53JT.js} +2 -2
  44. package/dist/{chunk-UAIOHCUK.js → chunk-SFLA7OH3.js} +3 -3
  45. package/dist/{chunk-Y6O2OCUO.js → chunk-SHM6MRRF.js} +2 -2
  46. package/dist/{chunk-KDIKRJGB.js → chunk-SHYIRB7I.js} +2 -2
  47. package/dist/{chunk-HHXFIHXC.js → chunk-SVR2LKYI.js} +2 -2
  48. package/dist/{chunk-5SBJCB6W.js → chunk-V7AEBY6U.js} +22 -22
  49. package/dist/{chunk-LRRD7NAG.js → chunk-WSKWVEQB.js} +18 -2
  50. package/dist/chunk-WSKWVEQB.js.map +1 -0
  51. package/dist/{chunk-2PVVP7GN.js → chunk-XKEFIFIC.js} +2 -2
  52. package/dist/{chunk-JRWWGMK7.js → chunk-XYA4XSNU.js} +2 -2
  53. package/dist/{chunk-X5YKXC6V.js → chunk-YSMEKBTD.js} +2 -2
  54. package/dist/{chunk-2XU6OGEN.js → chunk-Z4TZ76N7.js} +2 -2
  55. package/dist/index.js +24 -24
  56. package/package.json +6 -5
  57. package/scripts/run-package-tests.mjs +30 -8
  58. package/scripts/verify-packed-consumer.mjs +1 -1
  59. package/scripts/verify-pier-agent.mts +1 -0
  60. package/src/benchmarks/_harness.ts +20 -2
  61. package/src/benchmarks/humaneval.test.mts +122 -0
  62. package/src/benchmarks/humaneval.ts +100 -27
  63. package/src/david-attribution.mts +78 -0
  64. package/src/david-goliath.mts +149 -0
  65. package/src/hev-improve.mts +25 -6
  66. package/src/humaneval-object-ablation.mts +201 -0
  67. package/src/live-improve-campaign-mbpp.mts +641 -0
  68. package/src/live-improve-campaign.mts +500 -0
  69. package/src/mbpp-structural.mts +12 -7
  70. package/src/quant-arena/README.md +144 -0
  71. package/src/quant-arena/backtest.test.mts +135 -0
  72. package/src/quant-arena/backtest.ts +218 -0
  73. package/src/quant-arena/data.test.mts +44 -0
  74. package/src/quant-arena/data.ts +141 -0
  75. package/src/quant-arena/driver.test.mts +253 -0
  76. package/src/quant-arena/driver.ts +219 -0
  77. package/src/quant-arena/fixtures/data/PROVENANCE.md +26 -0
  78. package/src/quant-arena/fixtures/data/holdout/IDX.csv +523 -0
  79. package/src/quant-arena/fixtures/data/holdout/S01.csv +523 -0
  80. package/src/quant-arena/fixtures/data/holdout/S02.csv +523 -0
  81. package/src/quant-arena/fixtures/data/holdout/S03.csv +523 -0
  82. package/src/quant-arena/fixtures/data/holdout/S04.csv +523 -0
  83. package/src/quant-arena/fixtures/data/holdout/S05.csv +523 -0
  84. package/src/quant-arena/fixtures/data/holdout/S06.csv +523 -0
  85. package/src/quant-arena/fixtures/data/holdout/S07.csv +523 -0
  86. package/src/quant-arena/fixtures/data/holdout/S08.csv +523 -0
  87. package/src/quant-arena/fixtures/data/holdout/S09.csv +523 -0
  88. package/src/quant-arena/fixtures/data/holdout/S10.csv +523 -0
  89. package/src/quant-arena/fixtures/data/insample/IDX.csv +2087 -0
  90. package/src/quant-arena/fixtures/data/insample/S01.csv +2087 -0
  91. package/src/quant-arena/fixtures/data/insample/S02.csv +2087 -0
  92. package/src/quant-arena/fixtures/data/insample/S03.csv +2087 -0
  93. package/src/quant-arena/fixtures/data/insample/S04.csv +2087 -0
  94. package/src/quant-arena/fixtures/data/insample/S05.csv +2087 -0
  95. package/src/quant-arena/fixtures/data/insample/S06.csv +2087 -0
  96. package/src/quant-arena/fixtures/data/insample/S07.csv +2087 -0
  97. package/src/quant-arena/fixtures/data/insample/S08.csv +2087 -0
  98. package/src/quant-arena/fixtures/data/insample/S09.csv +2087 -0
  99. package/src/quant-arena/fixtures/data/insample/S10.csv +2087 -0
  100. package/src/quant-arena/fixtures/demo-campaign/cost-ledger.jsonl +16 -0
  101. package/src/quant-arena/fixtures/demo-campaign/notebook.jsonl +5 -0
  102. package/src/quant-arena/fixtures/demo-campaign/rollout-manifest.json +171 -0
  103. package/src/quant-arena/fixtures/demo-campaign/strategies/cand-001-default-author/strategy.ts +119 -0
  104. package/src/quant-arena/fixtures/demo-campaign/strategies/cand-002-default-author/strategy.ts +119 -0
  105. package/src/quant-arena/fixtures/demo-campaign/strategies/cand-003-quant-researcher/strategy.ts +105 -0
  106. package/src/quant-arena/fixtures/demo-campaign/strategies/cand-004-quant-researcher/strategy.ts +102 -0
  107. package/src/quant-arena/fixtures/demo-campaign-v2/cost-ledger.jsonl +4 -0
  108. package/src/quant-arena/fixtures/demo-campaign-v2/notebook.jsonl +2 -0
  109. package/src/quant-arena/fixtures/demo-campaign-v2/rollout-manifest.json +84 -0
  110. package/src/quant-arena/fixtures/demo-campaign-v2/strategies/cand-001-quant-researcher/strategy.ts +117 -0
  111. package/src/quant-arena/holdout-certify.mts +206 -0
  112. package/src/quant-arena/holdout-certify.test.mts +82 -0
  113. package/src/quant-arena/leak-audit.test.mts +79 -0
  114. package/src/quant-arena/leak-audit.ts +95 -0
  115. package/src/quant-arena/make-fixtures.mts +161 -0
  116. package/src/quant-arena/multiplicity.test.mts +68 -0
  117. package/src/quant-arena/multiplicity.ts +87 -0
  118. package/src/quant-arena/nautilus-certify.ts +31 -0
  119. package/src/quant-arena/oms.ts +90 -0
  120. package/src/quant-arena/profiles/quant-researcher.profile.json +7 -0
  121. package/src/quant-arena/python/pyproject.toml +8 -0
  122. package/src/quant-arena/python/uv.lock +1297 -0
  123. package/src/quant-arena/python/vbt-worker.py +192 -0
  124. package/src/quant-arena/quant-loop.mts +813 -0
  125. package/src/quant-arena/quant-loop.test.mts +75 -0
  126. package/src/quant-arena/strategies/buy-hold-index/strategy.ts +11 -0
  127. package/src/quant-arena/strategies/equal-weight/strategy.ts +20 -0
  128. package/src/quant-arena/strategies/sma-crossover/strategy.ts +42 -0
  129. package/src/quant-arena/types.ts +133 -0
  130. package/src/quant-arena/vbt-client.ts +321 -0
  131. package/src/quant-arena/vbt-parity.test.mts +183 -0
  132. package/src/quant-arena/windows.test.mts +45 -0
  133. package/src/quant-arena/windows.ts +54 -0
  134. package/src/rollout-ledger/backfill-swe-arena.mts +606 -0
  135. package/src/rollout-ledger/backfill-swe-arena.test.mts +338 -0
  136. package/src/rollout-ledger/settle-capture.mts +442 -0
  137. package/src/rollout-ledger/settle-capture.test.mts +270 -0
  138. package/src/stream-observe.py +45 -0
  139. package/src/stream-observe.tpl.html +247 -0
  140. package/src/supervisor-arena.mts +816 -0
  141. package/src/swe-arena/activation.mts +228 -0
  142. package/src/swe-arena/activation.test.mts +303 -0
  143. package/src/swe-arena/analyze.ts +211 -0
  144. package/src/swe-arena/arms.ts +804 -0
  145. package/src/swe-arena/bootstrap-meta.mts +188 -0
  146. package/src/swe-arena/bootstrap-meta.test.mts +51 -0
  147. package/src/swe-arena/briefing.mts +217 -0
  148. package/src/swe-arena/briefing.test.mts +178 -0
  149. package/src/swe-arena/calibrate.ts +217 -0
  150. package/src/swe-arena/capabilities.mts +76 -0
  151. package/src/swe-arena/capabilities.test.mts +57 -0
  152. package/src/swe-arena/capacity.ts +194 -0
  153. package/src/swe-arena/cell-evidence.mts +437 -0
  154. package/src/swe-arena/cell-evidence.test.mts +248 -0
  155. package/src/swe-arena/diagnosis-ensemble.test.mts +210 -0
  156. package/src/swe-arena/diagnosis-ensemble.ts +520 -0
  157. package/src/swe-arena/execution.test.mts +1170 -0
  158. package/src/swe-arena/factory-command-container.ts +284 -0
  159. package/src/swe-arena/factory-judge-child.mts +228 -0
  160. package/src/swe-arena/factory.test.mts +643 -0
  161. package/src/swe-arena/fixtures/analyze.py +80 -0
  162. package/src/swe-arena/fixtures/excludes.txt +8 -0
  163. package/src/swe-arena/fixtures/factory/agent-eval-309/calibration.md +51 -0
  164. package/src/swe-arena/fixtures/factory/agent-eval-309/manifest.json +29 -0
  165. package/src/swe-arena/fixtures/factory/agent-eval-309/spec.md +64 -0
  166. package/src/swe-arena/fixtures/factory/agent-runtime-232/calibration.md +48 -0
  167. package/src/swe-arena/fixtures/factory/agent-runtime-232/manifest.json +29 -0
  168. package/src/swe-arena/fixtures/factory/agent-runtime-232/spec.md +48 -0
  169. package/src/swe-arena/fixtures/factory/loops-28/calibration.md +47 -0
  170. package/src/swe-arena/fixtures/factory/loops-28/manifest.json +30 -0
  171. package/src/swe-arena/fixtures/factory/loops-28/spec.md +50 -0
  172. package/src/swe-arena/fixtures/gen1-salvage/README.md +45 -0
  173. package/src/swe-arena/fixtures/gen1-salvage/cand0-e6d7361.diff +116 -0
  174. package/src/swe-arena/fixtures/gen1-salvage/cand1-76a8590.diff +293 -0
  175. package/src/swe-arena/fixtures/holdout-preregister.log +12 -0
  176. package/src/swe-arena/fixtures/holdout.json +44 -0
  177. package/src/swe-arena/fixtures/instances.json +146 -0
  178. package/src/swe-arena/fixtures/ledger.jsonl +12 -0
  179. package/src/swe-arena/fixtures/patches/pallets__flask-5014.solo.patch +36 -0
  180. package/src/swe-arena/fixtures/patches/pydata__xarray-4687.sup.patch +33 -0
  181. package/src/swe-arena/fixtures/rejudge.jsonl +15 -0
  182. package/src/swe-arena/fixtures/rematch.jsonl +3 -0
  183. package/src/swe-arena/fixtures/rematch2.jsonl +3 -0
  184. package/src/swe-arena/fixtures/rematch3.jsonl +3 -0
  185. package/src/swe-arena/fixtures/run-report/README.md +43 -0
  186. package/src/swe-arena/fixtures/run-report/factory-agent-eval-309-FSUP0.json +173 -0
  187. package/src/swe-arena/fixtures/run-report/factory-agent-eval-309-FSUP0.md +100 -0
  188. package/src/swe-arena/fixtures/run-report/gen3-rollup.json +551 -0
  189. package/src/swe-arena/fixtures/run-report/gen3-rollup.md +64 -0
  190. package/src/swe-arena/fixtures/sup-journal-true.json +19 -0
  191. package/src/swe-arena/fixtures/verify/astropy__astropy-13033.sh +48 -0
  192. package/src/swe-arena/fixtures/verify/django__django-11532.sh +50 -0
  193. package/src/swe-arena/fixtures/verify/matplotlib__matplotlib-20826.sh +76 -0
  194. package/src/swe-arena/fixtures/verify/pydata__xarray-4687.sh +44 -0
  195. package/src/swe-arena/fixtures/verify/pytest-dev__pytest-6197.sh +32 -0
  196. package/src/swe-arena/fixtures/verify/sphinx-doc__sphinx-9658.sh +51 -0
  197. package/src/swe-arena/fixtures/worker-tokens.json +42 -0
  198. package/src/swe-arena/fixtures.ts +237 -0
  199. package/src/swe-arena/gepa-seat.mts +583 -0
  200. package/src/swe-arena/gepa-seat.test.mts +635 -0
  201. package/src/swe-arena/holdout-certify.mts +408 -0
  202. package/src/swe-arena/holdout-certify.test.mts +160 -0
  203. package/src/swe-arena/judge-child.mts +37 -0
  204. package/src/swe-arena/ledger-orphans.mts +77 -0
  205. package/src/swe-arena/ledger-orphans.test.mts +147 -0
  206. package/src/swe-arena/lineage-record.mts +164 -0
  207. package/src/swe-arena/lineage-record.test.mts +115 -0
  208. package/src/swe-arena/manifest.mts +293 -0
  209. package/src/swe-arena/manifest.test.mts +169 -0
  210. package/src/swe-arena/materialize.ts +142 -0
  211. package/src/swe-arena/outer-loop.mts +2795 -0
  212. package/src/swe-arena/outer-loop.test.mts +696 -0
  213. package/src/swe-arena/parity.test.mts +87 -0
  214. package/src/swe-arena/premeasured-from-cells.mts +281 -0
  215. package/src/swe-arena/premeasured-from-cells.test.mts +180 -0
  216. package/src/swe-arena/proc.test.mts +174 -0
  217. package/src/swe-arena/proc.ts +260 -0
  218. package/src/swe-arena/profiles/default-author.profile.json +4 -0
  219. package/src/swe-arena/proposer-fanout.mts +770 -0
  220. package/src/swe-arena/proposer-fanout.test.mts +619 -0
  221. package/src/swe-arena/proposer-provenance.mts +177 -0
  222. package/src/swe-arena/proposer-provenance.test.mts +106 -0
  223. package/src/swe-arena/reconcile.ts +0 -0
  224. package/src/swe-arena/replay.mts +183 -0
  225. package/src/swe-arena/replay.test.mts +300 -0
  226. package/src/swe-arena/run-experiment.mts +727 -0
  227. package/src/swe-arena/run-report.mts +75 -0
  228. package/src/swe-arena/run-supervisor.mjs +297 -0
  229. package/src/swe-arena/run-supervisor.test.mts +500 -0
  230. package/src/swe-arena/score-split.mts +140 -0
  231. package/src/swe-arena/score-split.test.mts +123 -0
  232. package/src/swe-arena/serialized-judge.ts +414 -0
  233. package/src/swe-arena/types.ts +218 -0
  234. package/src/swe-code-improve.mts +328 -0
  235. package/src/swe-emit-patch.mts +104 -0
  236. package/src/swe-improve.mts +232 -0
  237. package/src/swe-jail.ts +2 -2
  238. package/src/swe-local-proof.mts +169 -0
  239. package/src/swe-repro-calibrate.mts +446 -0
  240. package/src/swe-stream.mts +1497 -0
  241. package/src/swe-structural.mts +245 -837
  242. package/dist/chunk-LRRD7NAG.js.map +0 -1
  243. package/dist/chunk-PPYSEKFM.js.map +0 -1
  244. /package/dist/{chunk-CKUVRZ2T.js.map → chunk-3U5TXJZS.js.map} +0 -0
  245. /package/dist/{chunk-YCGY7UIZ.js.map → chunk-7GRVHU22.js.map} +0 -0
  246. /package/dist/{chunk-Z7ML6L77.js.map → chunk-HWST3SED.js.map} +0 -0
  247. /package/dist/{chunk-SYDW647C.js.map → chunk-IA2FBTWC.js.map} +0 -0
  248. /package/dist/{chunk-R67DFVLO.js.map → chunk-IFVINJ4B.js.map} +0 -0
  249. /package/dist/{chunk-R36V2VP7.js.map → chunk-IZ5M6OAC.js.map} +0 -0
  250. /package/dist/{chunk-ODT47UAY.js.map → chunk-K3BQGZCT.js.map} +0 -0
  251. /package/dist/{chunk-IFAV6KEM.js.map → chunk-KP5KD6EN.js.map} +0 -0
  252. /package/dist/{chunk-ZEWMTR5M.js.map → chunk-MQMRLGOG.js.map} +0 -0
  253. /package/dist/{chunk-TSWPNOYM.js.map → chunk-NQG5XDSB.js.map} +0 -0
  254. /package/dist/{chunk-7WSD27QQ.js.map → chunk-PB64GYIG.js.map} +0 -0
  255. /package/dist/{chunk-HBSWHQNJ.js.map → chunk-RCYQEFNX.js.map} +0 -0
  256. /package/dist/{chunk-J3KDJNX2.js.map → chunk-RH5F53JT.js.map} +0 -0
  257. /package/dist/{chunk-UAIOHCUK.js.map → chunk-SFLA7OH3.js.map} +0 -0
  258. /package/dist/{chunk-Y6O2OCUO.js.map → chunk-SHM6MRRF.js.map} +0 -0
  259. /package/dist/{chunk-KDIKRJGB.js.map → chunk-SHYIRB7I.js.map} +0 -0
  260. /package/dist/{chunk-HHXFIHXC.js.map → chunk-SVR2LKYI.js.map} +0 -0
  261. /package/dist/{chunk-5SBJCB6W.js.map → chunk-V7AEBY6U.js.map} +0 -0
  262. /package/dist/{chunk-2PVVP7GN.js.map → chunk-XKEFIFIC.js.map} +0 -0
  263. /package/dist/{chunk-JRWWGMK7.js.map → chunk-XYA4XSNU.js.map} +0 -0
  264. /package/dist/{chunk-X5YKXC6V.js.map → chunk-YSMEKBTD.js.map} +0 -0
  265. /package/dist/{chunk-2XU6OGEN.js.map → chunk-Z4TZ76N7.js.map} +0 -0
@@ -0,0 +1,218 @@
1
+ /**
2
+ * swe-arena — typed replay of the committed SOLO-vs-SUPERVISOR head-to-head
3
+ * artifacts (SWE-bench Verified, glm-5.2 both arms).
4
+ *
5
+ * MILESTONE 1: these types mirror the fixture files byte-for-byte semantics.
6
+ * They are the proof-of-faithfulness layer: `reconcile.ts` + `analyze.ts`
7
+ * must reproduce the reference `fixtures/analyze.py` output exactly (pinned in
8
+ * `replay.test.mts`) before any typed execution path is built on top.
9
+ */
10
+
11
+ /**
12
+ * The fields of one SWE-bench Verified instance we actually consume from
13
+ * `task-meta.json` (generated by the experiment's `load_meta.py` from
14
+ * princeton-nlp/SWE-bench_Verified). `FAIL_TO_PASS` / `PASS_TO_PASS` are
15
+ * JSON-encoded string arrays as shipped by the HF dataset — kept as raw
16
+ * strings here; decode at the point of use.
17
+ */
18
+ export interface SweInstance {
19
+ instance_id: string
20
+ repo: string
21
+ base_commit: string
22
+ problem_statement: string
23
+ patch: string
24
+ test_patch: string
25
+ /** JSON-encoded string[] (raw HF dataset encoding). */
26
+ FAIL_TO_PASS: string
27
+ /** JSON-encoded string[] (raw HF dataset encoding). */
28
+ PASS_TO_PASS: string
29
+ version: string | null
30
+ environment_setup_commit: string | null
31
+ }
32
+
33
+ /**
34
+ * One factory-bench instance — a merged feature PR from our own repo history
35
+ * turned into a gradable end-to-end feature-building task (see
36
+ * supervisor-lab/factory-bench/docs/design.md). The worker sees only the tree
37
+ * at `base_commit` (archive export, synthetic git history) plus the rewritten
38
+ * spec; the PR's own added test files are the hidden judge, overlaid from
39
+ * `judge_ref` at judge time. Field names mirror the instance dirs'
40
+ * `manifest.json` byte-for-byte, same policy as SweInstance vs task-meta.json.
41
+ */
42
+ export interface FactoryInstance {
43
+ /** `factory.<repo>.<pr>` */
44
+ id: string
45
+ /** `owner/name` */
46
+ repo: string
47
+ /** Judge-side local mirror; NEVER exposed to the worker workspace. */
48
+ repo_local_mirror: string
49
+ /** The worker's world — the PR's base commit. */
50
+ base_commit: string
51
+ /** Merge commit the judge tests are read from (`git show <judge_ref>:<path>`). */
52
+ judge_ref: string
53
+ /** Instance-dir-relative spec file (PM-ticket grade rewrite of the PR body). */
54
+ spec_md: string
55
+ /** Hidden judge test files, overlaid at judge time only. */
56
+ judge_tests: string[]
57
+ /** Flaky/env-dependent tests excluded at calibration, reasons in calibration.md. */
58
+ excluded_tests: string[]
59
+ /** Immutable Node container image used for setup and judge commands. */
60
+ command_image: string
61
+ setup_cmds: string[]
62
+ judge_cmds: string[]
63
+ /** e.g. "all 30 judge tests pass; partial score = passed/30" — the /NN is parsed. */
64
+ resolved_criterion: string
65
+ timeout_s: number
66
+ worker_visible_paths_note?: string
67
+ runtime?: string
68
+ calibration?: { gold: string; base: string; receipts: string }
69
+ }
70
+
71
+ /**
72
+ * Discriminated instance union for the seams that used to assume SweInstance.
73
+ * A tagged wrapper (not a structural union) because both shapes mirror their
74
+ * on-disk artifacts byte-for-byte and neither may grow a discriminant field.
75
+ */
76
+ export type ArenaInstance =
77
+ | { kind: 'swe'; instance: SweInstance }
78
+ | { kind: 'factory'; instance: FactoryInstance }
79
+
80
+ /** The ledger/judge identity: SWE `instance_id` or factory `id`. */
81
+ export function arenaInstanceId(a: ArenaInstance): string {
82
+ return a.kind === 'swe' ? a.instance.instance_id : a.instance.id
83
+ }
84
+
85
+ /** Per-run opencode usage breakdown captured on the SOLO arm. */
86
+ export interface SoloUsage {
87
+ steps: number
88
+ in: number
89
+ out: number
90
+ reasoning: number
91
+ cache_w: number
92
+ cache_r: number
93
+ max_ctx: number
94
+ oc_cost: number
95
+ total_io: number
96
+ }
97
+
98
+ /**
99
+ * One paired row of `ledger.jsonl` — exactly the schema the experiment wrote.
100
+ * `null` values are real telemetry gaps (e.g. `sup_spentTokens: null` when the
101
+ * supervisor driver exited rc=3 mid-run), not absent data to be defaulted.
102
+ */
103
+ export interface LedgerRow {
104
+ iid: string
105
+ solo_resolved: boolean
106
+ sup_resolved: boolean
107
+ solo_verify_pass: boolean
108
+ sup_verify_pass: boolean
109
+ solo_patch_lines: number
110
+ sup_patch_lines: number
111
+ solo_wall_s: number
112
+ sup_wall_s: number
113
+ solo_tokens: number
114
+ solo_usage: SoloUsage
115
+ sup_spentTokens: number | null
116
+ sup_spentUsd: number | null
117
+ sup_spawned: number
118
+ /** Missing on rows written before the field was added (pallets__flask-5014). */
119
+ sup_workers?: number
120
+ sup_settled: number
121
+ sup_subtasks: string[]
122
+ sup_delivered: boolean | null
123
+ /**
124
+ * The fixture ledger observed only completed/running; the driver can also
125
+ * settle failed/cancelled (M2 widened the union — the typed execution path
126
+ * records those honestly instead of coercing them).
127
+ */
128
+ sup_status: 'completed' | 'running' | 'failed' | 'cancelled' | null
129
+ sup_verdict: 'delivered' | 'no-winner' | 'best-effort' | null
130
+ solo_oc_rc: number
131
+ sup_driver_rc: number
132
+ solo_patch: string
133
+ sup_patch: string
134
+ /** Free-form correction note (e.g. psf__requests-1766 sup re-judge). */
135
+ _note?: string
136
+ }
137
+
138
+ /**
139
+ * Tags carried by `rejudge.jsonl` rows. Gold-family tags grade the OFFICIAL
140
+ * gold patch (calibrating the judge itself); final/my-reverify tags are the
141
+ * personal authoritative re-judgements of arm patches that override the
142
+ * automated ledger verdicts.
143
+ */
144
+ export type RejudgeTag =
145
+ | 'gold-control'
146
+ | 'gold'
147
+ | 'gold2'
148
+ | 'solo-final'
149
+ | 'sup-final'
150
+ | 'solo-final2'
151
+ | 'sup-final2'
152
+ | 'my-reverify'
153
+
154
+ /** One row of `rejudge.jsonl`. `resolved: null` = the judge run failed to parse (inconclusive). */
155
+ export interface RejudgeRow {
156
+ iid: string
157
+ tag: RejudgeTag
158
+ patch: string
159
+ resolved: boolean | null
160
+ score?: number
161
+ secs?: number
162
+ patch_bytes?: number
163
+ error?: string
164
+ raw?: string
165
+ }
166
+
167
+ /** Evolution-round labels: SUP2/3/4 = rematch.jsonl / rematch2.jsonl / rematch3.jsonl. */
168
+ export type RematchArm = 'SUP2' | 'SUP3' | 'SUP4'
169
+
170
+ /** One row of a rematch*.jsonl evolution round. */
171
+ export interface RematchRow {
172
+ iid: string
173
+ arm: RematchArm
174
+ resolved: boolean
175
+ verify_pass: boolean
176
+ patch_lines: number
177
+ wall_s: number
178
+ spawned: number
179
+ workers: number
180
+ sup_status: 'completed' | 'running'
181
+ sup_verdict: 'delivered' | 'no-winner' | 'best-effort' | null
182
+ delivered: boolean | null
183
+ spentTokens: number | null
184
+ }
185
+
186
+ /** Declarative arm identity for typed execution paths built on this module. */
187
+ export interface ArmSpec {
188
+ name: string
189
+ kind: 'solo' | 'supervisor'
190
+ env: Record<string, string>
191
+ provenance: { repo: string; commit: string }
192
+ }
193
+
194
+ /** One pre-registered holdout instance from `holdout.json`. */
195
+ export interface HoldoutEntry {
196
+ iid: string
197
+ repo: string
198
+ gold_official_resolved: boolean
199
+ verify_calibrated: boolean
200
+ selected_at_commit: string
201
+ }
202
+
203
+ /**
204
+ * The holdout registry: instances selected BEFORE any arm ran (see
205
+ * `holdout-preregister.log`), each with its gold patch verified against the
206
+ * calibrated judge. Only entries passing both checks are usable.
207
+ */
208
+ export interface HoldoutRegistry {
209
+ entries: HoldoutEntry[]
210
+ /** Commit of the supervisor runtime (`loops`) at selection time. */
211
+ selectedAtCommit: string
212
+ }
213
+
214
+ /** Per-instance supervisor worker-session spend from `worker-tokens.json`. */
215
+ export interface WorkerTokens {
216
+ worker_sessions: number
217
+ worker_tok: number
218
+ }
@@ -0,0 +1,328 @@
1
+ /**
2
+ * META-HARNESS on the SWE scaffold — improve({ surface: 'code' }).
3
+ *
4
+ * A coding agent (Claude Code) REWRITES the scaffold LOGIC under bench/src (the seed prompt/playbook,
5
+ * runAgentic strategy/params, context handling, retry/patch synthesis) with the MODEL (glm worker) +
6
+ * the TOOL surface (list/read/edit[/run]) + the JUDGE held FIXED, judged on the official swebench
7
+ * Docker verdict, gated on a held-out instance split. This is the DGM/meta-harness recipe: let the
8
+ * SYSTEM find the scaffold lever from the RAW failure traces, not hand-build it.
9
+ *
10
+ * Wiring (all verified in this worktree):
11
+ * - improve()/codeProposerFor + rawTraceContext come from the LOCAL agent-runtime build, linked into
12
+ * this bench's node_modules (bench/node_modules/@tangle-network/agent-runtime -> /home/drew/code/agent-runtime).
13
+ * - The candidate proposer is agenticGenerator(harness:'claude'), BUT the shipped runLocalHarness
14
+ * spawns `claude --headless -p` and --headless is an unknown option on the current CLI (exit 1, no
15
+ * edits ever). We pass code.generator with a corrected runHarness that spawns
16
+ * `claude -p <prompt> --dangerously-skip-permissions` so the coding agent can actually edit the
17
+ * worktree. This is a harness-spawn fix, NOT a hand-authored scaffold edit — Claude still finds the
18
+ * lever itself from the traces.
19
+ * - Each candidate is a git worktree the driver forks off baseRef; Claude edits bench/src in place;
20
+ * `verify` (an import smoke of the edited scaffold) gates it before the expensive measurement.
21
+ * - MEASUREMENT: the code-aware agent fn shells into the candidate scaffold's OWN judge-free emit
22
+ * entrypoint (swe-emit-patch.mts) with cwd = the worktree, captures the unified diff, and returns
23
+ * it. improve()'s FIXED swebench judge scores that diff OUTSIDE the candidate, so the scaffold can
24
+ * never game its own axis. Baseline (empty surface) runs the UNEDITED scaffold from the main tree.
25
+ *
26
+ * Run (router WAF: keep example commands OUT of backticks):
27
+ * TANGLE_API_KEY=... dotenvx run --quiet -f .../agent-state.env --
28
+ * TRAIN_IDS=... HOLDOUT_IDS=... WORKER_MODEL=glm-4.6 GENERATIONS=1 POPULATION=2
29
+ * RUN_DIR=/abs/run BASE_REF=meta/swe-scaffold-baseline
30
+ * node_modules/.bin/tsx bench/src/swe-code-improve.mts
31
+ */
32
+ import { spawn, spawnSync } from 'node:child_process'
33
+ import { existsSync, mkdirSync, symlinkSync } from 'node:fs'
34
+ import { join } from 'node:path'
35
+ import { improve, agenticGenerator } from '@tangle-network/agent-runtime'
36
+ import type { AgentProfile } from '@tangle-network/agent-interface'
37
+ import type { DispatchContext, JudgeConfig, Scenario } from '@tangle-network/agent-eval/contract'
38
+ import { createSweBenchAdapter } from './benchmarks/swe-bench'
39
+ import type { BenchTask } from './benchmarks/types'
40
+
41
+ /** The agent-runtime repo the worktree adapter forks candidate checkouts from (agent-runtime-swe is a
42
+ * worktree of it, so bench/src is tracked here). */
43
+ const REPO_ROOT = process.env.REPO_ROOT ?? '/home/drew/code/agent-runtime'
44
+ /** The main working tree = the baseline scaffold (its bench has the linked node_modules). */
45
+ const SWE_MAIN_ROOT = process.env.SWE_MAIN_ROOT ?? '/home/drew/code/agent-runtime-swe'
46
+ const MAIN_BENCH = join(SWE_MAIN_ROOT, 'bench')
47
+ const TSX_BIN = join(MAIN_BENCH, 'node_modules/.bin/tsx')
48
+
49
+ /** A candidate worktree is a fresh checkout with NO node_modules. Symlink the main bench's (already
50
+ * carrying the linked local runtime) so both the verifier and the measurement can run the scaffold. */
51
+ function ensureNodeModules(rootDir: string): void {
52
+ const target = join(rootDir, 'bench', 'node_modules')
53
+ if (existsSync(target)) return
54
+ try {
55
+ symlinkSync(join(MAIN_BENCH, 'node_modules'), target, 'dir')
56
+ } catch {
57
+ /* concurrent create / already exists — fine */
58
+ }
59
+ }
60
+
61
+ /** Run the scaffold's judge-free emit entrypoint on ONE instance, from `rootDir`'s bench/src. Returns
62
+ * the unified diff (stdout, kept clean of any banner) + the tokens the worker reported (parsed from
63
+ * the [emit] stderr line). NO judge — the judge is held outside, in this file. */
64
+ function runEmit(
65
+ rootDir: string,
66
+ id: string,
67
+ env: Record<string, string>,
68
+ timeoutMs: number,
69
+ ): Promise<{ patch: string; tokIn: number; tokOut: number; usd: number; code: number | null }> {
70
+ ensureNodeModules(rootDir)
71
+ const benchDir = join(rootDir, 'bench')
72
+ return new Promise((resolve) => {
73
+ const child = spawn(TSX_BIN, [join(benchDir, 'src/swe-emit-patch.mts')], {
74
+ cwd: benchDir,
75
+ env: { ...process.env, ...env, IDS: id },
76
+ stdio: ['ignore', 'pipe', 'pipe'],
77
+ })
78
+ let out = ''
79
+ let err = ''
80
+ child.stdout.on('data', (d) => (out += String(d)))
81
+ child.stderr.on('data', (d) => (err += String(d)))
82
+ const timer = setTimeout(() => {
83
+ if (!child.killed) child.kill('SIGKILL')
84
+ }, timeoutMs)
85
+ ;(timer as { unref?: () => void }).unref?.()
86
+ child.on('error', () => {
87
+ clearTimeout(timer)
88
+ resolve({ patch: '', tokIn: 0, tokOut: 0, usd: 0, code: 1 })
89
+ })
90
+ child.on('close', (code) => {
91
+ clearTimeout(timer)
92
+ const m = /tok=in:(\d+)\/out:(\d+)/.exec(err)
93
+ const u = /usd=([0-9.]+)/.exec(err)
94
+ if (code !== 0) console.error(` [emit ${id}] exit=${code} stderr: ${err.slice(-400).replace(/\n/g, ' ')}`)
95
+ resolve({
96
+ patch: out,
97
+ tokIn: m ? Number(m[1]) : 0,
98
+ tokOut: m ? Number(m[2]) : 0,
99
+ usd: u ? Number(u[1]) : 0,
100
+ code,
101
+ })
102
+ })
103
+ })
104
+ }
105
+
106
+ async function main(): Promise<void> {
107
+ const routerKey = process.env.TANGLE_API_KEY
108
+ if (!routerKey) throw new Error('TANGLE_API_KEY required (worker calls the router)')
109
+ const routerBaseUrl = process.env.ROUTER_BASE ?? 'https://router.tangle.tools/v1'
110
+ const workerModel = process.env.WORKER_MODEL ?? 'glm-4.6'
111
+ const reflectModel = process.env.REFLECT_MODEL ?? 'glm-4.6'
112
+ const trainIds = (process.env.TRAIN_IDS ?? 'psf__requests-2931,pallets__flask-5014').split(',').map((s) => s.trim()).filter(Boolean)
113
+ const holdoutIds = (process.env.HOLDOUT_IDS ?? 'psf__requests-1142,psf__requests-1921').split(',').map((s) => s.trim()).filter(Boolean)
114
+ const generations = Number(process.env.GENERATIONS ?? 1)
115
+ const population = Number(process.env.POPULATION ?? 2)
116
+ const innerTurns = Number(process.env.INNER_TURNS ?? 40)
117
+ const maxTokens = Number(process.env.MAX_TOKENS ?? 12000)
118
+ const enableRun = ['1', 'true', 'yes'].includes((process.env.RUN_TOOL ?? '').toLowerCase())
119
+ const baseRef = process.env.BASE_REF ?? 'meta/swe-scaffold-baseline'
120
+ const worktreeDir = process.env.WORKTREE_DIR ?? '/tmp/claude-1000/-home-drew-code-supervisor-lab/9ee6a456-a94f-474c-9888-b4afc9bc26bd/scratchpad/mh-worktrees'
121
+ const runDir = process.env.RUN_DIR ?? '/tmp/claude-1000/-home-drew-code-supervisor-lab/9ee6a456-a94f-474c-9888-b4afc9bc26bd/scratchpad/mh-run'
122
+ const emitTimeoutMs = Number(process.env.EMIT_TIMEOUT_MS ?? 600_000)
123
+ const harnessTimeoutMs = Number(process.env.HARNESS_TIMEOUT_MS ?? 900_000)
124
+ mkdirSync(worktreeDir, { recursive: true })
125
+ mkdirSync(runDir, { recursive: true })
126
+
127
+ const allIds = [...new Set([...trainIds, ...holdoutIds])]
128
+
129
+ console.log('=== META-HARNESS on the SWE scaffold — improve(surface:code) ===')
130
+ console.log(`worker=${workerModel} reflect=${reflectModel} router=${routerBaseUrl} runTool=${enableRun}`)
131
+ console.log(`train=[${trainIds.join(', ')}] holdout=[${holdoutIds.join(', ')}]`)
132
+ console.log(`generations=${generations} population=${population} innerTurns=${innerTurns} maxTokens=${maxTokens}`)
133
+ console.log(`repoRoot=${REPO_ROOT} baseRef=${baseRef}`)
134
+ console.log(`runDir=${runDir} worktreeDir=${worktreeDir}`)
135
+
136
+ // Fixed swebench Docker judge (held OUTSIDE every candidate) + task pool.
137
+ const adapter = createSweBenchAdapter()
138
+ const pool = await adapter.loadTasks({ ids: allIds, split: 'test' })
139
+ const byId = new Map<string, BenchTask>(pool.map((t) => [t.id, t]))
140
+ for (const id of allIds) if (!byId.has(id)) throw new Error(`instance not found in Verified: ${id}`)
141
+
142
+ const workerEnv: Record<string, string> = {
143
+ WORKER_MODEL: workerModel,
144
+ MAX_TOKENS: String(maxTokens),
145
+ INNER_TURNS: String(innerTurns),
146
+ ROUTER_BASE: routerBaseUrl,
147
+ TANGLE_API_KEY: routerKey,
148
+ RUN_TOOL: enableRun ? '1' : '0',
149
+ }
150
+
151
+ // The code-aware measurement agent. A CodeSurface -> run the candidate scaffold in its worktree; an
152
+ // empty/string surface (the baseline arm) -> run the UNEDITED scaffold from the main tree. Same path,
153
+ // so baseline and candidates are measured identically.
154
+ const agent = async (surface: unknown, scenario: Scenario, ctx: DispatchContext): Promise<string | null> => {
155
+ const isCode = !!surface && typeof surface === 'object' && (surface as { kind?: string }).kind === 'code'
156
+ const worktreeRef = isCode ? String((surface as { worktreeRef?: string }).worktreeRef ?? '') : ''
157
+ const rootDir = isCode && worktreeRef && existsSync(worktreeRef) ? worktreeRef : SWE_MAIN_ROOT
158
+ const t0 = Date.now()
159
+ const r = await runEmit(rootDir, scenario.id, workerEnv, emitTimeoutMs)
160
+ const hasPatch = r.patch.trim().length > 0
161
+ // Report real usage; floor a patch-bearing zero-usage cell so the stub-guard cannot abort on a
162
+ // router telemetry gap (lift is judge-derived, so this only affects cost accounting).
163
+ const zeroUsage = r.tokIn === 0 && r.tokOut === 0
164
+ ctx.cost.observe(zeroUsage && hasPatch ? Math.max(r.usd, 0.0001) : r.usd, workerModel)
165
+ ctx.cost.observeTokens(
166
+ zeroUsage && hasPatch ? { input: Math.max(r.tokIn, 1), output: Math.max(r.tokOut, 1) } : { input: r.tokIn, output: r.tokOut },
167
+ )
168
+ const files = hasPatch ? [...r.patch.matchAll(/^diff --git a\/(\S+)/gm)].map((m) => m[1]) : []
169
+ console.log(
170
+ ` [measure] ${isCode ? 'cand' : 'base'} ${scenario.id} patch=${r.patch.length}b files=[${files.join(', ') || 'none'}] ` +
171
+ `tok=in:${r.tokIn}/out:${r.tokOut} ${Math.round((Date.now() - t0) / 1000)}s${isCode ? ` @ ${worktreeRef}` : ''}`,
172
+ )
173
+ return hasPatch ? r.patch : null
174
+ }
175
+
176
+ const judge: JudgeConfig<string, Scenario> = {
177
+ name: 'swebench-docker',
178
+ dimensions: [{ key: 'resolved', description: 'FAIL_TO_PASS + PASS_TO_PASS resolved by the official swebench Docker harness' }],
179
+ async score({ artifact, scenario }) {
180
+ const patch = String(artifact ?? '')
181
+ if (!patch.trim()) {
182
+ console.log(` [judge] ${scenario.id} resolved=0 (no patch)`)
183
+ return { dimensions: { resolved: 0 }, composite: 0, notes: 'no patch emitted' }
184
+ }
185
+ const bt = byId.get(scenario.id)
186
+ if (!bt) throw new Error(`judge: unknown scenario ${scenario.id}`)
187
+ const s = await adapter.judge(bt, patch)
188
+ console.log(` [judge] ${scenario.id} resolved=${s.resolved ? 1 : 0}`)
189
+ return { dimensions: { resolved: s.resolved ? 1 : 0 }, composite: s.resolved ? 1 : 0, notes: (s.detail ?? '').slice(0, 200) }
190
+ },
191
+ }
192
+
193
+ // The corrected coding-harness spawn: `claude -p <prompt> --dangerously-skip-permissions`. The shipped
194
+ // runLocalHarness uses `claude --headless -p` (unknown option on this CLI). agenticGenerator ignores
195
+ // the return value (it reads worktree dirtiness), so a minimal result shape is enough.
196
+ const runHarness = (o: { cwd: string; taskPrompt: string; timeoutMs?: number; signal?: AbortSignal }): Promise<{ exitCode: number | null; stdout: string; stderr: string; killedBySignal: NodeJS.Signals | null; durationMs: number; timedOut: boolean }> => {
197
+ const started = Date.now()
198
+ return new Promise((resolve) => {
199
+ const child = spawn('claude', ['-p', o.taskPrompt, '--dangerously-skip-permissions'], {
200
+ cwd: o.cwd,
201
+ env: process.env,
202
+ stdio: ['ignore', 'pipe', 'pipe'],
203
+ })
204
+ let stdout = ''
205
+ let stderr = ''
206
+ let timedOut = false
207
+ child.stdout?.on('data', (d) => (stdout += String(d)))
208
+ child.stderr?.on('data', (d) => (stderr += String(d)))
209
+ const timer = setTimeout(() => {
210
+ timedOut = true
211
+ if (!child.killed) child.kill('SIGTERM')
212
+ }, o.timeoutMs ?? harnessTimeoutMs)
213
+ ;(timer as { unref?: () => void }).unref?.()
214
+ const onAbort = () => {
215
+ if (!child.killed) child.kill('SIGTERM')
216
+ }
217
+ o.signal?.addEventListener('abort', onAbort, { once: true })
218
+ child.on('error', () => {
219
+ clearTimeout(timer)
220
+ resolve({ exitCode: 1, stdout, stderr: `${stderr}\n[spawn error]`, killedBySignal: null, durationMs: Date.now() - started, timedOut })
221
+ })
222
+ child.on('close', (code, signal) => {
223
+ clearTimeout(timer)
224
+ o.signal?.removeEventListener('abort', onAbort)
225
+ console.error(` [proposer:claude] exit=${code} wall=${Math.round((Date.now() - started) / 1000)}s out=${stdout.length}b`)
226
+ resolve({ exitCode: code, stdout, stderr, killedBySignal: signal, durationMs: Date.now() - started, timedOut })
227
+ })
228
+ })
229
+ }
230
+
231
+ // Domain prompt: name the EDIT BOUNDARY (scaffold logic only) + keep the raw-trace evidence discipline
232
+ // (agenticGenerator discards a raw-trace candidate that doesn't inspect a trace + write the diagnosis).
233
+ const buildPrompt = (args: { report: unknown; findings: Array<{ severity?: string; claim?: string; recommended_action?: string }> }): string => {
234
+ const lines: string[] = [
235
+ 'You are improving a SWE-bench coding SCAFFOLD: a harness that drives a FIXED worker model to fix real GitHub bugs via list_files/read_file/edit_file tools. Your job is to rewrite the SCAFFOLD LOGIC so the SAME worker model resolves MORE instances on a held-out split.',
236
+ '',
237
+ 'EDIT ONLY the scaffold logic under bench/src:',
238
+ ' - the seed prompt / playbook: SWE_SEED_PROMPT and SWE_SEED_PROMPT_WITH_RUN in bench/src/swe-bench-env.ts',
239
+ ' - the exploration/context handling in bench/src/swe-bench-env.ts: list_files walk depth and 240-entry cap, the read_file 24000-char truncation, edit_file retry messaging, patch synthesis (git diff)',
240
+ ' - the runAgentic strategy/params in bench/src/swe-emit-patch.mts: innerTurns default, budget, how the patch is captured',
241
+ '',
242
+ 'DO NOT change (FIXED for this search):',
243
+ ' - the TOOL surface: the list_files/read_file/edit_file/run tool NAMES, JSON signatures, or the path jail. Do not add or remove a tool.',
244
+ ' - the worker MODEL or MAX_TOKENS (passed via env — never hardcode a different model).',
245
+ ' - the swebench Docker JUDGE.',
246
+ ' - the swe-emit-patch.mts I/O contract: it still reads IDS + WORKER_MODEL + router env and prints ONLY the unified diff to stdout (diagnostics to stderr). You may change HOW the patch is produced, never this stdin/stdout contract.',
247
+ '',
248
+ 'Make the smallest set of edits that addresses the failure evidence below, then stop. Leave changes in the working tree; do NOT commit.',
249
+ '',
250
+ 'Failure evidence from the previous generation (its RAW run traces are on disk):',
251
+ ]
252
+ for (const f of args.findings) {
253
+ lines.push(`- (${f.severity ?? 'info'}) ${f.claim ?? ''}`)
254
+ if (f.recommended_action) lines.push(` -> ${f.recommended_action}`)
255
+ }
256
+ lines.push(
257
+ '',
258
+ 'Raw-trace evidence requirement (enforced — a candidate that skips this is discarded):',
259
+ ' - Inspect at least one raw trace path named above (grep/cat/ls it) BEFORE editing.',
260
+ ' - Write .improve/raw-trace-diagnosis.md in this worktree containing: the exact trace path(s) you inspected, the failure mechanism you found, and the scaffold-logic change you made.',
261
+ ' - A candidate with ONLY that file changed (no real scaffold edit) is discarded.',
262
+ )
263
+ return lines.join('\n')
264
+ }
265
+
266
+ const verify = (worktreePath: string): { ok: boolean; feedback?: string } => {
267
+ ensureNodeModules(worktreePath)
268
+ const res = spawnSync(TSX_BIN, [join(worktreePath, 'bench/src/swe-emit-patch.mts')], {
269
+ cwd: join(worktreePath, 'bench'),
270
+ env: { ...process.env, SWE_EMIT_SMOKE: '1' },
271
+ encoding: 'utf-8',
272
+ timeout: 180_000,
273
+ })
274
+ if (res.status === 0) return { ok: true }
275
+ const out = `${res.stdout ?? ''}${res.stderr ?? ''}`.trim()
276
+ return { ok: false, feedback: `edited scaffold failed import smoke (tsx swe-emit-patch SWE_EMIT_SMOKE=1):\n${out.slice(0, 3000)}` }
277
+ }
278
+
279
+ const generator = agenticGenerator({
280
+ harness: 'claude',
281
+ verify,
282
+ timeoutMs: harnessTimeoutMs,
283
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
284
+ buildPrompt: buildPrompt as any,
285
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
286
+ runHarness: runHarness as any,
287
+ })
288
+
289
+ const profile: AgentProfile = { name: 'swe-scaffold', prompt: { systemPrompt: '' } }
290
+ const scenarios: Scenario[] = allIds.map((id) => ({ id, kind: 'swe-bench-verified' }))
291
+ const holdoutScenarios: Scenario[] = holdoutIds.map((id) => ({ id, kind: 'swe-bench-verified' }))
292
+
293
+ const out = await improve(profile, [], {
294
+ surface: 'code',
295
+ gate: 'holdout',
296
+ code: { repoRoot: REPO_ROOT, baseRef, worktreeDir, generator },
297
+ rawTraceContext: true,
298
+ runDir,
299
+ scenarios,
300
+ judge,
301
+ agent,
302
+ expectUsage: 'warn',
303
+ budget: { generations, populationSize: population, holdoutScenarios, maxConcurrency: 1, reps: 1 },
304
+ llm: { baseUrl: routerBaseUrl, apiKey: routerKey, model: reflectModel },
305
+ })
306
+
307
+ console.log('\n=== RESULT ===')
308
+ console.log(`gateDecision=${out.gateDecision} shipped=${out.shipped} lift=${out.lift}`)
309
+ console.log(`baseline holdout composite = ${out.raw.baseline.compositeMean}`)
310
+ console.log(`winner holdout composite = ${out.raw.winner.compositeMean}`)
311
+ console.log(`baseline per-scenario: ${JSON.stringify(out.raw.baseline.perScenario)}`)
312
+ console.log(`winner per-scenario: ${JSON.stringify(out.raw.winner.perScenario)}`)
313
+ if (out.raw.winner.label) console.log(`winner label: ${out.raw.winner.label}`)
314
+ if (out.raw.winner.summary) console.log(`winner summary: ${out.raw.winner.summary}`)
315
+ for (const gen of out.raw.generations ?? []) {
316
+ console.log(`\n-- generation ${gen.record.generationIndex} candidates --`)
317
+ for (const c of gen.record.candidates) {
318
+ const perScenario = (c as { scenarios?: Array<{ scenarioId: string; composite: number }> }).scenarios ?? []
319
+ const detail = perScenario.map((s) => `${s.scenarioId}=${s.composite}`).join(' ')
320
+ console.log(` candidate ${c.surfaceHash.slice(0, 8)} composite=${c.composite}${c.label ? ` "${c.label}"` : ''} [${detail}]`)
321
+ }
322
+ }
323
+ }
324
+
325
+ main().catch((e) => {
326
+ console.error(e instanceof Error ? (e.stack ?? e.message) : String(e))
327
+ process.exit(1)
328
+ })
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Judge-FREE patch emitter for the SWE scaffold — the FIXED measurement entrypoint.
3
+ *
4
+ * Given ONE instance id (IDS) + worker model + router env, this runs the candidate scaffold's OWN
5
+ * `createSweBenchEnvironment` + `runAgentic` IN THIS worktree and prints the unified `git diff` of
6
+ * the agent's edits to STDOUT. It does NOT judge — the swebench Docker judge is held OUTSIDE the
7
+ * candidate (in swe-code-improve.mts) so the scaffold can never grade its own axis.
8
+ *
9
+ * This is the seam the code-aware improve() agent shells into. Its I/O contract is FIXED and the
10
+ * scaffold proposer must NOT change it:
11
+ * IN (env): IDS=<one instance id>, WORKER_MODEL, MAX_TOKENS, ROUTER_BASE, TANGLE_API_KEY,
12
+ * INNER_TURNS, BUDGET, RUN_TOOL
13
+ * OUT (fd1): the unified diff (empty string when the agent made no edit)
14
+ * diagnostics go to STDERR only, so stdout stays a clean patch.
15
+ *
16
+ * SWE_EMIT_SMOKE=1 → import/wiring check only: the module (and swe-bench-env) loaded, print READY on
17
+ * stderr and exit 0 WITHOUT a clone / model call / dataset read. This is what the candidate verifier
18
+ * runs to discard a scaffold edit that no longer imports.
19
+ *
20
+ * Command examples in prompts are kept OUT of backticks on purpose (router WAF 403s backtick-wrapped
21
+ * command text) — see swe-bench-env.ts.
22
+ */
23
+ import { execFile } from 'node:child_process'
24
+ import { promisify } from 'node:util'
25
+ import type { AgenticSurface, ArtifactHandle, SurfaceScore } from '@tangle-network/agent-runtime/loops'
26
+ import { refine, runAgentic } from '@tangle-network/agent-runtime/loops'
27
+ import { createSweBenchEnvironment, SWE_SEED_PROMPT, SWE_SEED_PROMPT_WITH_RUN } from './swe-bench-env'
28
+
29
+ const exec = promisify(execFile)
30
+
31
+ async function main(): Promise<void> {
32
+ const smoke = ['1', 'true', 'yes'].includes((process.env.SWE_EMIT_SMOKE ?? '').toLowerCase())
33
+ if (smoke) {
34
+ // The import graph (this file + swe-bench-env + the linked runtime) resolved by the time we get
35
+ // here. That is the whole check — no clone, no model call, no dataset read.
36
+ console.error('SWE_EMIT_SMOKE ok: swe-emit-patch + swe-bench-env import graph loaded')
37
+ return
38
+ }
39
+
40
+ const routerKey = process.env.TANGLE_API_KEY
41
+ if (!routerKey) throw new Error('TANGLE_API_KEY required (the worker calls the router)')
42
+ const routerBaseUrl = process.env.ROUTER_BASE ?? 'https://router.tangle.tools/v1'
43
+ const model = process.env.WORKER_MODEL ?? 'glm-5.2'
44
+ const ids = (process.env.IDS ?? '').split(',').map((s) => s.trim()).filter(Boolean)
45
+ if (ids.length !== 1) throw new Error(`swe-emit-patch: exactly one IDS required, got [${ids.join(', ')}]`)
46
+ const id = ids[0]!
47
+ const innerTurns = Number(process.env.INNER_TURNS ?? 40)
48
+ const maxTokens = Number(process.env.MAX_TOKENS ?? 12000)
49
+ const budget = Number(process.env.BUDGET ?? 1)
50
+ const enableRun = ['1', 'true', 'yes'].includes((process.env.RUN_TOOL ?? '').toLowerCase())
51
+
52
+ const { environment, adapter } = await createSweBenchEnvironment(1, { ids, enableRun })
53
+ const pool = await adapter.loadTasks({ ids, split: 'test' })
54
+ const bt = pool.find((t) => t.id === id)
55
+ if (!bt) throw new Error(`swe-emit-patch: instance not found in Verified: ${id}`)
56
+
57
+ const task = {
58
+ id: bt.id,
59
+ systemPrompt: enableRun ? SWE_SEED_PROMPT_WITH_RUN : SWE_SEED_PROMPT,
60
+ userPrompt: bt.prompt,
61
+ meta: { instanceId: bt.id },
62
+ }
63
+
64
+ // Capture the patch from inside score() (called during the refine loop, BEFORE the surface closes
65
+ // and rms the checkout). Keep the LATEST non-empty diff so accumulated refinements win and a later
66
+ // empty read never clobbers a real patch.
67
+ let capturedPatch = ''
68
+ const proxy: AgenticSurface = {
69
+ ...environment,
70
+ async score(_t, handle: ArtifactHandle): Promise<SurfaceScore> {
71
+ try {
72
+ const d = await exec('git', ['-C', handle.id, 'diff'], { maxBuffer: 40_000_000, timeout: 60_000 })
73
+ if (d.stdout.trim()) capturedPatch = d.stdout
74
+ } catch {
75
+ /* workspace gone or git error → keep whatever we already captured */
76
+ }
77
+ return { passes: capturedPatch.trim() ? 1 : 0, total: 1, errored: 0 }
78
+ },
79
+ }
80
+
81
+ const t0 = Date.now()
82
+ const r = await runAgentic({
83
+ surface: proxy,
84
+ task,
85
+ strategy: refine,
86
+ routerBaseUrl,
87
+ routerKey,
88
+ model,
89
+ maxTokens,
90
+ innerTurns,
91
+ budget,
92
+ })
93
+ const files = capturedPatch ? [...capturedPatch.matchAll(/^diff --git a\/(\S+)/gm)].map((m) => m[1]) : []
94
+ console.error(
95
+ `[emit] ${id} shots=${r.shots} completions=${r.completions} tok=in:${r.tokens.input}/out:${r.tokens.output} ` +
96
+ `patch=${capturedPatch.length}b files=[${files.join(', ') || 'none'}] ${Math.round((Date.now() - t0) / 1000)}s`,
97
+ )
98
+ process.stdout.write(capturedPatch)
99
+ }
100
+
101
+ main().catch((e) => {
102
+ console.error(e instanceof Error ? (e.stack ?? e.message) : String(e))
103
+ process.exit(1)
104
+ })