@tangle-network/agent-bench 0.3.7 → 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 +4 -0
- package/HARNESS.md +43 -0
- package/dist/adapters.js +23 -23
- 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/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-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-PWQVGAJB.js → chunk-V7AEBY6U.js} +21 -21
- 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 +23 -23
- package/package.json +4 -4
- package/scripts/verify-packed-consumer.mjs +1 -1
- package/src/benchmarks/_harness.ts +20 -2
- package/src/benchmarks/humaneval.test.mts +2 -2
- 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/swe-arena/activation.mts +228 -0
- package/src/swe-arena/activation.test.mts +303 -0
- package/src/swe-arena/arms.ts +30 -14
- package/src/swe-arena/briefing.mts +217 -0
- package/src/swe-arena/briefing.test.mts +178 -0
- package/src/swe-arena/calibrate.ts +102 -1
- package/src/swe-arena/cell-evidence.mts +41 -9
- 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/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/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.ts +135 -2
- package/src/swe-arena/gepa-seat.mts +583 -0
- package/src/swe-arena/gepa-seat.test.mts +635 -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/outer-loop.mts +677 -27
- 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/proposer-fanout.mts +295 -14
- package/src/swe-arena/proposer-fanout.test.mts +247 -0
- package/src/swe-arena/proposer-provenance.mts +177 -0
- package/src/swe-arena/proposer-provenance.test.mts +106 -0
- package/src/swe-arena/run-experiment.mts +367 -1
- package/src/swe-arena/run-report.mts +75 -0
- package/src/swe-arena/run-supervisor.test.mts +5 -3
- package/src/swe-arena/score-split.mts +140 -0
- package/src/swe-arena/score-split.test.mts +123 -0
- package/src/swe-arena/types.ts +52 -0
- package/src/swe-structural.mts +245 -837
- package/dist/chunk-LRRD7NAG.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-PWQVGAJB.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
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
* generator's evidence gate requires).
|
|
60
60
|
*/
|
|
61
61
|
|
|
62
|
-
import { appendFile, mkdir, readFile, rm, symlink, unlink, writeFile } from 'node:fs/promises'
|
|
62
|
+
import { appendFile, mkdir, readdir, readFile, rm, symlink, unlink, writeFile } from 'node:fs/promises'
|
|
63
63
|
import { existsSync } from 'node:fs'
|
|
64
64
|
import process from 'node:process'
|
|
65
65
|
import { join } from 'node:path'
|
|
@@ -122,13 +122,47 @@ import {
|
|
|
122
122
|
import {
|
|
123
123
|
defaultProposers,
|
|
124
124
|
fanOutLoopsGenerator,
|
|
125
|
+
materializeParetoParents,
|
|
125
126
|
proposerShotHooks,
|
|
127
|
+
type ParetoParentContext,
|
|
128
|
+
type ParetoParentSeed,
|
|
126
129
|
type PrefilterConfig,
|
|
127
130
|
type PrefilterKill,
|
|
128
131
|
type ProposerSpec,
|
|
129
132
|
type SmokeRunner,
|
|
130
133
|
type SmokeVerdict,
|
|
131
134
|
} from './proposer-fanout.mts'
|
|
135
|
+
import { captureProposerProvenance } from './proposer-provenance.mts'
|
|
136
|
+
import { CRASH_ORPHAN_REASON, reconcileCrashOrphansOnDisk } from './ledger-orphans.mts'
|
|
137
|
+
import {
|
|
138
|
+
AUTHOR_BRIEFING_VERSION,
|
|
139
|
+
resolveAuthorBriefing,
|
|
140
|
+
writeEvidenceIndex,
|
|
141
|
+
type BriefingContext,
|
|
142
|
+
} from './briefing.mts'
|
|
143
|
+
import {
|
|
144
|
+
readCommittedPredicate,
|
|
145
|
+
runActivationPredicate,
|
|
146
|
+
ACTIVATION_PREDICATE_RELPATH,
|
|
147
|
+
type ActivationRecord,
|
|
148
|
+
} from './activation.mts'
|
|
149
|
+
import {
|
|
150
|
+
loadOrCreateScoreSplit,
|
|
151
|
+
subScores,
|
|
152
|
+
type ScoreSplit,
|
|
153
|
+
type ScoreSplitConfig,
|
|
154
|
+
} from './score-split.mts'
|
|
155
|
+
import { recordLineageGeneration, type LineageCandidateInput } from './lineage-record.mts'
|
|
156
|
+
import {
|
|
157
|
+
reportSupervisorRound,
|
|
158
|
+
writeSupervisorRunReportSafe,
|
|
159
|
+
} from '@tangle-network/agent-eval/supervisor-run'
|
|
160
|
+
import {
|
|
161
|
+
campaignCoordsFromCellPath,
|
|
162
|
+
createSettleCapture,
|
|
163
|
+
type SettleCapture,
|
|
164
|
+
} from '../rollout-ledger/settle-capture.mts'
|
|
165
|
+
import { findSupervisorRunDir } from './arms.ts'
|
|
132
166
|
import { installProcessSignalAbort, run, runOk } from './proc.ts'
|
|
133
167
|
import { loadInstanceImages } from './run-experiment.mts'
|
|
134
168
|
import {
|
|
@@ -480,6 +514,16 @@ export interface StaircaseRow {
|
|
|
480
514
|
armProvenance: { repo: string; commit: string } | null
|
|
481
515
|
diffPath: string | null
|
|
482
516
|
diffSha256: string | null
|
|
517
|
+
/** GEN-5 public/private sub-scores (selection stays on the combined count;
|
|
518
|
+
* the private sub-score is never surfaced to proposers). */
|
|
519
|
+
split?: {
|
|
520
|
+
publicInstances: string[]
|
|
521
|
+
privateInstances: string[]
|
|
522
|
+
publicResolvedCount: number
|
|
523
|
+
privateResolvedCount: number
|
|
524
|
+
}
|
|
525
|
+
/** GEN-5 activation-gate outcome for this candidate. */
|
|
526
|
+
activation?: ActivationRecord
|
|
483
527
|
}
|
|
484
528
|
|
|
485
529
|
const STAIRCASE_VERDICTS: ReadonlySet<string> = new Set([
|
|
@@ -489,6 +533,7 @@ const STAIRCASE_VERDICTS: ReadonlySet<string> = new Set([
|
|
|
489
533
|
'rejected-out-of-space',
|
|
490
534
|
'rejected-incomplete',
|
|
491
535
|
'rejected-prefilter',
|
|
536
|
+
'quarantined-inactive',
|
|
492
537
|
])
|
|
493
538
|
|
|
494
539
|
/** Parse + validate one staircase JSONL row. Throws on schema drift. */
|
|
@@ -598,12 +643,22 @@ export interface OuterLoopConfig {
|
|
|
598
643
|
* an AgentProfile-pinned harness invocation (see proposer-fanout.mts).
|
|
599
644
|
* When set, `populationSize` MUST equal `proposers.length` (one candidate
|
|
600
645
|
* slot per proposer — enforced at launch). Unset = the legacy
|
|
601
|
-
* single-author generator (`proposerHarness` + bare invocation).
|
|
646
|
+
* single-author generator (`proposerHarness` + bare invocation).
|
|
647
|
+
* GEN-6: a spec with `engine` set is a GEPA seat (gepa-seat.mts) — the
|
|
648
|
+
* agent-eval external-GEPA adapter optimizes ONE change-space file as a
|
|
649
|
+
* string against the pre-filter smoke cell; requires `prefilter.enabled`. */
|
|
602
650
|
proposers?: ProposerSpec[]
|
|
603
651
|
/** GEN-3 cheap pre-filter: per candidate, change-space + tsc (the authoring
|
|
604
652
|
* verifier) plus ONE smoke arm cell before any full-evaluation spend.
|
|
605
653
|
* Killed candidates become `rejected-prefilter` staircase dots. */
|
|
606
654
|
prefilter?: PrefilterConfig
|
|
655
|
+
/** GEN-4 Pareto parents: prior-run frontier candidates (loops commits +
|
|
656
|
+
* measured per-instance results) seeded into every author's prompt and
|
|
657
|
+
* the merge seat's explicit input. Seeded at OUR buildPrompt seam, not the
|
|
658
|
+
* lib's `ctx.paretoParents` — the lib frontier is within-run only and a
|
|
659
|
+
* prior campaign cannot be injected without its runDir + ledger receipts
|
|
660
|
+
* (see proposer-fanout.mts). */
|
|
661
|
+
paretoParents?: ParetoParentSeed[]
|
|
607
662
|
/** Replicates per holdout instance in the operator-approved certification
|
|
608
663
|
* run (holdout-certify.mts). Default 2 — the gen-2 winner failed 3/6 vs
|
|
609
664
|
* 4/6 on a 1-rep holdout with exactly one discordant cell, a known
|
|
@@ -614,6 +669,29 @@ export interface OuterLoopConfig {
|
|
|
614
669
|
* reps/fail-closed protocol, or 'measure' — the incumbent runs the same
|
|
615
670
|
* 2-rep holdout first in the certification run. */
|
|
616
671
|
holdoutBaseline?: Record<string, boolean> | 'measure'
|
|
672
|
+
/** GEN-5 public/private score split (score-split.mts): proposers + the
|
|
673
|
+
* pre-filter see only PUBLIC instances' scores/evidence; selection stays
|
|
674
|
+
* on the combined set. Unset = everything public (pre-gen-5 behavior). */
|
|
675
|
+
scoreSplit?: ScoreSplitConfig
|
|
676
|
+
/** GEN-5 MAP+TOOLBOX briefing (briefing.mts): write the per-run evidence
|
|
677
|
+
* index and append the toolbox/permission briefing (change-space
|
|
678
|
+
* overridable) to every author prompt. */
|
|
679
|
+
briefing?: typeof AUTHOR_BRIEFING_VERSION
|
|
680
|
+
/** GEN-5 activation gate (activation.mts): require a machine-checkable
|
|
681
|
+
* activation predicate per candidate (prefilter-enforced) and quarantine
|
|
682
|
+
* candidates whose mechanism never fired in their own campaign traces. */
|
|
683
|
+
activationGate?: boolean
|
|
684
|
+
/** GEN-5 settle-time rollout-ledger capture (rollout-ledger/settle-capture.mts):
|
|
685
|
+
* emit tangle.rollout.v1 lines live after each cell judges, with label-v2
|
|
686
|
+
* rewards. Default path: <outDir>/rollout-ledger.jsonl. */
|
|
687
|
+
rolloutLedger?: { enabled: boolean; path?: string; opencodeDb?: string }
|
|
688
|
+
/** GEN-5 lineage DAG (lineage-record.mts): record every candidate as a
|
|
689
|
+
* LineageNode at <outDir>/.evolve/lineage.jsonl and put the governor's
|
|
690
|
+
* continuation decision in the round summary. */
|
|
691
|
+
lineage?: boolean
|
|
692
|
+
/** GEN-5 evidence map: prior run outDirs whose arm-runs/judge/candidate
|
|
693
|
+
* evidence the authors may mine (rendered into the evidence index). */
|
|
694
|
+
priorEvidenceDirs?: string[]
|
|
617
695
|
/** Router model ids for the blind diagnosis ensemble (config, never a
|
|
618
696
|
* hardcoded unrouted model). */
|
|
619
697
|
analystModels: string[]
|
|
@@ -804,6 +882,118 @@ export function defaultGen3Config(
|
|
|
804
882
|
}
|
|
805
883
|
}
|
|
806
884
|
|
|
885
|
+
// ---------------------------------------------------------------------------
|
|
886
|
+
// GEN-4 configuration — pinned per-proposer models (recorded in provenance),
|
|
887
|
+
// Pareto-parent seeding from the gen-3 frontier, and a dedicated merge seat.
|
|
888
|
+
// ---------------------------------------------------------------------------
|
|
889
|
+
|
|
890
|
+
/** The gen-3 frontier (run r4-mrwc0awe): winner + runner-up, both 2/6 vs the
|
|
891
|
+
* 1/6 baseline on DIFFERENT instances — complementary lessons, the merge
|
|
892
|
+
* seat's input. Per-instance verdicts are the fail-closed all-reps values
|
|
893
|
+
* from `.evolve/rounds/gen-0.jsonl`. */
|
|
894
|
+
export const GEN3_PARETO_PARENTS: ParetoParentSeed[] = [
|
|
895
|
+
{
|
|
896
|
+
commit: 'cc0d95584c7ea14324cd57c21fe946c7c0f53827',
|
|
897
|
+
label: 'default-author',
|
|
898
|
+
resolvedInstances: ['pydata__xarray-4687', 'sphinx-doc__sphinx-9658'],
|
|
899
|
+
note:
|
|
900
|
+
'mechanical patch-risk scan (patchRiskWarnings in src/worker-evidence.ts, threaded through ' +
|
|
901
|
+
'extensions/pi/loops.ts) + never-reword / test-seam / run-the-neighbors worker rules + 3-check ' +
|
|
902
|
+
'reviewer; pytest-dev__pytest-6197 split 0/1 across reps (near-miss)',
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
commit: 'a7a2a982e51551de3a8e796ee2efc448ed405e6a',
|
|
906
|
+
label: 'prompts-author',
|
|
907
|
+
resolvedInstances: ['django__django-11532', 'pydata__xarray-4687'],
|
|
908
|
+
note:
|
|
909
|
+
'prompt-only: hidden-suite bullet in the supervisor GOAL-authoring section (the django seam), ' +
|
|
910
|
+
'frozen-behavior worker section + run-the-repo-tests discipline, 2-check reviewer; ' +
|
|
911
|
+
'sphinx-doc__sphinx-9658 split 0/1 across reps (near-miss)',
|
|
912
|
+
},
|
|
913
|
+
]
|
|
914
|
+
|
|
915
|
+
/**
|
|
916
|
+
* The gen-4 config: protocol round 4 continues (frozen arm, same holdout
|
|
917
|
+
* registry, same roundsDir staircase) with three changes as a unit:
|
|
918
|
+
*
|
|
919
|
+
* 1. PINNED PER-PROPOSER MODELS — four seats: claude-author (claude CLI on
|
|
920
|
+
* its own login; the resolved model + CLI version are captured into
|
|
921
|
+
* `<outDir>/proposer-provenance.json` at t=0), glm-author (opencode
|
|
922
|
+
* pinned to zai-coding-plan/glm-5.2 via `-m`), codex-author (codex CLI on
|
|
923
|
+
* its ChatGPT login, auth provenance-gated at launch; drop the seat via
|
|
924
|
+
* `includeCodex: false` when the CLI is absent), and merge-author (claude,
|
|
925
|
+
* merge seat).
|
|
926
|
+
* 2. PARETO PARENTS — the gen-3 winner + runner-up diffs and their measured
|
|
927
|
+
* per-instance results seed every author's prompt; the merge seat's task
|
|
928
|
+
* is their coherent union. Seeded at the buildPrompt seam (our seam): the
|
|
929
|
+
* lib's `ctx.paretoParents` frontier is within-run only, and a prior
|
|
930
|
+
* campaign cannot cross runs without its runDir + ledger receipts.
|
|
931
|
+
* 3. PINNED BASELINE — the premeasured artifact at `hh/gen4/` is BUILT from
|
|
932
|
+
* gen-3's measured baseline cells (premeasured-from-cells.mts; gen-3
|
|
933
|
+
* measured astropy F, django F, matplotlib F, xarray F, pytest F,
|
|
934
|
+
* sphinx T — matplotlib/django false under current weather), so gen-4
|
|
935
|
+
* spends nothing re-measuring and fails loud if the loops tip moved.
|
|
936
|
+
*/
|
|
937
|
+
export function defaultGen4Config(
|
|
938
|
+
hh = DEFAULT_HH_SCRATCHPAD,
|
|
939
|
+
opts: { outDirName?: string; includeCodex?: boolean } = {},
|
|
940
|
+
): OuterLoopConfig {
|
|
941
|
+
const base = defaultGen3Config(hh, { outDirName: opts.outDirName ?? 'gen4' })
|
|
942
|
+
const proposers: ProposerSpec[] = [
|
|
943
|
+
{ name: 'claude-author', profile: 'default-author.profile.json', harness: 'claude' },
|
|
944
|
+
{ name: 'glm-author', harness: 'opencode', model: 'zai-coding-plan/glm-5.2' },
|
|
945
|
+
...(opts.includeCodex === false ? [] : [{ name: 'codex-author', harness: 'codex' } satisfies ProposerSpec]),
|
|
946
|
+
{ name: 'merge-author', profile: 'default-author.profile.json', harness: 'claude', merge: true },
|
|
947
|
+
]
|
|
948
|
+
return {
|
|
949
|
+
...base,
|
|
950
|
+
populationSize: proposers.length,
|
|
951
|
+
proposers,
|
|
952
|
+
paretoParents: [...GEN3_PARETO_PARENTS],
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// ---------------------------------------------------------------------------
|
|
957
|
+
// GEN-5 configuration — gen-4's shape (4 proposers incl. the merge seat,
|
|
958
|
+
// Pareto parents, premeasured baseline carried forward per the same
|
|
959
|
+
// cell-derivation, 2 reps, deferred holdout) PLUS the gen-5 integration
|
|
960
|
+
// bundle as a unit:
|
|
961
|
+
//
|
|
962
|
+
// 1. MAP+TOOLBOX briefing — per-run evidence index + toolbox/permission
|
|
963
|
+
// briefing (change-space overridable at extensions/pi/author-briefing.md);
|
|
964
|
+
// the 3-analyst diagnosis stays as ONE input among the named tools.
|
|
965
|
+
// 2. PUBLIC/PRIVATE SPLIT — 4 public / 2 private of the 6 instances,
|
|
966
|
+
// deterministically seeded by runId and persisted per outDir; proposers +
|
|
967
|
+
// prefilter see public only, selection stays combined. Small-n caveat
|
|
968
|
+
// documented in score-split.mts.
|
|
969
|
+
// 3. ACTIVATION GATE — required machine-checkable predicate per candidate;
|
|
970
|
+
// never-fired mechanisms are quarantined even on an improved score.
|
|
971
|
+
// 4. SETTLE-TIME ROLLOUT LEDGER — tangle.rollout.v1 lines live per cell,
|
|
972
|
+
// label v2 (contribution-aware workers, baseline-relative proposers).
|
|
973
|
+
// 5. LINEAGE DAG — agent-eval Lineage at <outDir>/.evolve/lineage.jsonl +
|
|
974
|
+
// governor continuation decision in the round summary; staircase rows
|
|
975
|
+
// unchanged (observatory contract).
|
|
976
|
+
// ---------------------------------------------------------------------------
|
|
977
|
+
|
|
978
|
+
export function defaultGen5Config(
|
|
979
|
+
hh = DEFAULT_HH_SCRATCHPAD,
|
|
980
|
+
opts: { outDirName?: string; includeCodex?: boolean } = {},
|
|
981
|
+
): OuterLoopConfig {
|
|
982
|
+
const base = defaultGen4Config(hh, {
|
|
983
|
+
outDirName: opts.outDirName ?? 'gen5',
|
|
984
|
+
...(opts.includeCodex !== undefined ? { includeCodex: opts.includeCodex } : {}),
|
|
985
|
+
})
|
|
986
|
+
return {
|
|
987
|
+
...base,
|
|
988
|
+
scoreSplit: { publicCount: 4 },
|
|
989
|
+
briefing: AUTHOR_BRIEFING_VERSION,
|
|
990
|
+
activationGate: true,
|
|
991
|
+
rolloutLedger: { enabled: true },
|
|
992
|
+
lineage: true,
|
|
993
|
+
priorEvidenceDirs: [join(hh, 'gen4'), join(hh, 'gen3')],
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
807
997
|
// ---------------------------------------------------------------------------
|
|
808
998
|
// Round recorder — dispatch-time change-space fail-closed + diff writing ONLY.
|
|
809
999
|
// NOT a scoring source: scoring reads the lib's campaign cells
|
|
@@ -1059,11 +1249,21 @@ export function loopsCandidateVerifier(loopsRepo: string): Verifier {
|
|
|
1059
1249
|
* only — the rest of the run keeps its env untouched. */
|
|
1060
1250
|
const CLAUDE_AMBIENT_AUTH_VARS = ['ANTHROPIC_API_KEY', 'ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_BASE_URL'] as const
|
|
1061
1251
|
|
|
1252
|
+
/** Same failure class for the gen-4 codex seat: agent-state.env injects an
|
|
1253
|
+
* OPENAI_API_KEY meant for other tooling, and the codex CLI prefers env-key
|
|
1254
|
+
* auth over its ChatGPT login. The codex author shot must run on the CLI's
|
|
1255
|
+
* own login (`codex login status` is provenance-gated at launch), so the
|
|
1256
|
+
* leaked auth is stripped for the shot subprocess only. */
|
|
1257
|
+
const CODEX_AMBIENT_AUTH_VARS = ['OPENAI_API_KEY', 'OPENAI_BASE_URL'] as const
|
|
1258
|
+
|
|
1062
1259
|
export function proposerShotEnv(harness: OuterLoopConfig['proposerHarness']): NodeJS.ProcessEnv {
|
|
1063
1260
|
const env: NodeJS.ProcessEnv = { ...process.env }
|
|
1064
1261
|
if (harness === 'claude') {
|
|
1065
1262
|
for (const name of CLAUDE_AMBIENT_AUTH_VARS) delete env[name]
|
|
1066
1263
|
}
|
|
1264
|
+
if (harness === 'codex') {
|
|
1265
|
+
for (const name of CODEX_AMBIENT_AUTH_VARS) delete env[name]
|
|
1266
|
+
}
|
|
1067
1267
|
return env
|
|
1068
1268
|
}
|
|
1069
1269
|
|
|
@@ -1151,6 +1351,33 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1151
1351
|
// premeasured baseline and pin the depth dial (see capabilities.mts).
|
|
1152
1352
|
assertSubstratePassthroughs(log)
|
|
1153
1353
|
|
|
1354
|
+
// GEN-4 model-identity provenance at t=0: harness CLI versions, the claude
|
|
1355
|
+
// seat's resolved settings model, codex auth, and every explicit model pin.
|
|
1356
|
+
// Fails loud on a missing/unauthed harness binary — populationSize equals
|
|
1357
|
+
// proposers.length, so a dead seat cannot be skipped mid-run.
|
|
1358
|
+
if (config.proposers !== undefined) {
|
|
1359
|
+
const provenance = await captureProposerProvenance(config.proposers)
|
|
1360
|
+
await mkdir(config.outDir, { recursive: true })
|
|
1361
|
+
await writeFile(join(config.outDir, 'proposer-provenance.json'), JSON.stringify(provenance, null, 2))
|
|
1362
|
+
for (const p of provenance.proposers) {
|
|
1363
|
+
log(
|
|
1364
|
+
`proposer ${p.name} (${p.harness}${p.merge ? ', merge seat' : ''}): ` +
|
|
1365
|
+
`model=${p.pinnedModel ?? `cli-default${p.settingsModel ? `:${p.settingsModel}` : ''}`} ` +
|
|
1366
|
+
`version=${p.harnessVersion.split('\n')[0]}`,
|
|
1367
|
+
)
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
// GEN-4 Pareto parents: materialize the configured prior-run frontier
|
|
1372
|
+
// (commit existence + full diffs) before any authoring.
|
|
1373
|
+
const paretoParents: ParetoParentContext[] =
|
|
1374
|
+
config.paretoParents !== undefined && config.paretoParents.length > 0
|
|
1375
|
+
? await materializeParetoParents(config.loopsRepo, config.paretoParents)
|
|
1376
|
+
: []
|
|
1377
|
+
if (paretoParents.length > 0) {
|
|
1378
|
+
log(`pareto parents: ${paretoParents.map((p) => `${p.label}@${p.commit.slice(0, 10)}`).join(', ')}`)
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1154
1381
|
// The gate's only denominator: a stored prior baseline campaign the LIB
|
|
1155
1382
|
// validates (surface hash, seed, reps, split digest, coverage) before
|
|
1156
1383
|
// skipping the baseline campaign. A missing artifact = the BOOTSTRAP run —
|
|
@@ -1179,14 +1406,41 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1179
1406
|
const excludes = await loadExcludes()
|
|
1180
1407
|
const images = await loadInstanceImages(config.instanceImagesPath)
|
|
1181
1408
|
const adapter = createSweBenchAdapter()
|
|
1409
|
+
const runId = `r${config.round}-${Date.now().toString(36)}`
|
|
1410
|
+
await mkdir(config.outDir, { recursive: true })
|
|
1411
|
+
|
|
1412
|
+
// GEN-5 public/private split — deterministic (seeded by runId), PERSISTED
|
|
1413
|
+
// per outDir so a resume can never rotate private instances into view.
|
|
1414
|
+
// Scored identically; selection stays combined; proposers + prefilter see
|
|
1415
|
+
// public only.
|
|
1416
|
+
const split: ScoreSplit | null =
|
|
1417
|
+
config.scoreSplit !== undefined
|
|
1418
|
+
? await loadOrCreateScoreSplit({
|
|
1419
|
+
outDir: config.outDir,
|
|
1420
|
+
runId,
|
|
1421
|
+
instances: config.instances,
|
|
1422
|
+
publicCount: config.scoreSplit.publicCount,
|
|
1423
|
+
})
|
|
1424
|
+
: null
|
|
1425
|
+
const privateIids = new Set(split?.privateInstances ?? [])
|
|
1426
|
+
if (split !== null) {
|
|
1427
|
+
log(
|
|
1428
|
+
`score split (seeded by ${split.seededBy}): public [${split.publicInstances.join(', ')}] + ` +
|
|
1429
|
+
`${split.privateInstances.length} private instance(s) (identities withheld from proposers; ` +
|
|
1430
|
+
`selection uses public+private combined; small-n caveat: 2 private of 6 is a direction check, not certification)`,
|
|
1431
|
+
)
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1182
1434
|
// The pre-filter's smoke instance may sit outside the improvement set (e.g.
|
|
1183
1435
|
// a designated cheap instance) — it needs the same problem/image/verify
|
|
1184
|
-
// validation and rides the same loaded-task map.
|
|
1436
|
+
// validation and rides the same loaded-task map. Under the gen-5 split the
|
|
1437
|
+
// smoke choice is restricted to PUBLIC instances (the prefilter surfaces
|
|
1438
|
+
// its verdict to the kill log the authors can mine).
|
|
1185
1439
|
const smokeIid =
|
|
1186
1440
|
config.proposers !== undefined && config.prefilter?.enabled
|
|
1187
1441
|
? resolveSmokeInstance(
|
|
1188
1442
|
config.prefilter.smokeInstance,
|
|
1189
|
-
config.instances,
|
|
1443
|
+
split !== null ? split.publicInstances : config.instances,
|
|
1190
1444
|
premeasured ? cellsFromCampaign(premeasured.campaign) : null,
|
|
1191
1445
|
)
|
|
1192
1446
|
: null
|
|
@@ -1208,12 +1462,57 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1208
1462
|
const judge: SerializedJudge = createSerializedJudge(
|
|
1209
1463
|
config.judgeTimeoutMs !== undefined ? { timeoutMs: config.judgeTimeoutMs } : {},
|
|
1210
1464
|
)
|
|
1211
|
-
const runId = `r${config.round}-${Date.now().toString(36)}`
|
|
1212
|
-
await mkdir(config.outDir, { recursive: true })
|
|
1213
1465
|
await mkdir(config.roundsDir, { recursive: true })
|
|
1214
1466
|
const recorder = new RoundRecorder(config.loopsRepo, join(config.outDir, 'candidates'))
|
|
1215
1467
|
const analysts: AnalystSpec[] = config.analystModels.map((model, i) => ({ id: `${model}#${i + 1}`, model }))
|
|
1216
1468
|
|
|
1469
|
+
// GEN-5 MAP+TOOLBOX briefing: persist the Pareto parent diffs, write the
|
|
1470
|
+
// per-run evidence index (a map — one line per evidence path, private
|
|
1471
|
+
// instances excluded), and resolve the briefing text (the change-space
|
|
1472
|
+
// override at extensions/pi/author-briefing.md wins over the default).
|
|
1473
|
+
let briefingCtx: BriefingContext | undefined
|
|
1474
|
+
if (config.briefing === AUTHOR_BRIEFING_VERSION) {
|
|
1475
|
+
const parentPatches: Array<{ label: string; path: string }> = []
|
|
1476
|
+
if (paretoParents.length > 0) {
|
|
1477
|
+
const parentsDir = join(config.outDir, 'pareto-parents')
|
|
1478
|
+
await mkdir(parentsDir, { recursive: true })
|
|
1479
|
+
for (const parent of paretoParents) {
|
|
1480
|
+
const patchPath = join(parentsDir, `${parent.label}.patch`)
|
|
1481
|
+
await writeFile(patchPath, parent.diff)
|
|
1482
|
+
parentPatches.push({ label: parent.label, path: patchPath })
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
const index = await writeEvidenceIndex({
|
|
1486
|
+
outDir: config.outDir,
|
|
1487
|
+
roundsDir: config.roundsDir,
|
|
1488
|
+
seedArtifactRuns: config.seedArtifactRuns,
|
|
1489
|
+
...(config.priorEvidenceDirs !== undefined ? { priorEvidenceDirs: config.priorEvidenceDirs } : {}),
|
|
1490
|
+
paretoParentPatches: parentPatches,
|
|
1491
|
+
split,
|
|
1492
|
+
})
|
|
1493
|
+
const briefing = await resolveAuthorBriefing(config.loopsRepo, config.loopsBaseRef)
|
|
1494
|
+
briefingCtx = { indexPath: index.path, briefingText: briefing.text, briefingSource: briefing.source }
|
|
1495
|
+
log(
|
|
1496
|
+
`briefing ${AUTHOR_BRIEFING_VERSION}: evidence index → ${index.path} (${index.rows.length} row(s)); ` +
|
|
1497
|
+
`briefing text source: ${briefing.source}`,
|
|
1498
|
+
)
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
// GEN-5 settle-time rollout ledger — tangle.rollout.v1 lines appended live
|
|
1502
|
+
// after each cell judges (label v2); capture failure logs loud but never
|
|
1503
|
+
// kills a cell.
|
|
1504
|
+
const settleCapture: SettleCapture | null =
|
|
1505
|
+
config.rolloutLedger?.enabled === true
|
|
1506
|
+
? createSettleCapture({
|
|
1507
|
+
ledgerPath: config.rolloutLedger.path ?? join(config.outDir, 'rollout-ledger.jsonl'),
|
|
1508
|
+
runId,
|
|
1509
|
+
instanceCount: config.instances.length,
|
|
1510
|
+
...(config.rolloutLedger.opencodeDb !== undefined ? { opencodeDb: config.rolloutLedger.opencodeDb } : {}),
|
|
1511
|
+
log,
|
|
1512
|
+
})
|
|
1513
|
+
: null
|
|
1514
|
+
if (settleCapture !== null) log(`rollout-ledger: settle-time capture ON → ${settleCapture.path}`)
|
|
1515
|
+
|
|
1217
1516
|
const sweScenarios: Scenario[] = config.instances.map((iid) => ({ id: iid, kind: 'swe-instance' }))
|
|
1218
1517
|
|
|
1219
1518
|
// Capacity gates on BOTH paths the supervisor arm rides (worker + router).
|
|
@@ -1337,6 +1636,8 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1337
1636
|
resolved: outcome.resolved,
|
|
1338
1637
|
patchLines: outcome.armRes.patch_lines,
|
|
1339
1638
|
wallS,
|
|
1639
|
+
// GEN-6: the GEPA seat's inner-score tiebreak.
|
|
1640
|
+
verifyPass: outcome.armRes.verify_pass,
|
|
1340
1641
|
}
|
|
1341
1642
|
await mkdir(armOutDir, { recursive: true })
|
|
1342
1643
|
await writeFile(join(armOutDir, 'smoke.json'), JSON.stringify(result, null, 2))
|
|
@@ -1431,6 +1732,14 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1431
1732
|
await writeFile(join(runDir, 'judge.json'), JSON.stringify({ ...verdict, wallS: judgeWallS }, null, 1))
|
|
1432
1733
|
log(`${config.armName} ${rec.tag} ${iid} judged: resolved=${verdict.resolved} (attempts=${verdict.attempts})`)
|
|
1433
1734
|
|
|
1735
|
+
// Deterministic run observability, per cell: steer count, waves, concurrency,
|
|
1736
|
+
// idle, evidence→respawn, cost by role. The headline lands in the run log so
|
|
1737
|
+
// the answers are in the tail without a follow-up command.
|
|
1738
|
+
await writeSupervisorRunReportSafe(runDir, {
|
|
1739
|
+
appendHeadlineTo: join(config.outDir, 'run.log'),
|
|
1740
|
+
patchPath: armRes.patchPath,
|
|
1741
|
+
})
|
|
1742
|
+
|
|
1434
1743
|
const spend = armRes.recoveredSpend
|
|
1435
1744
|
const recovered =
|
|
1436
1745
|
armRes.spentTokens === null && (spend?.workerTokSqlite ?? null) === null
|
|
@@ -1454,7 +1763,61 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1454
1763
|
recoveredTokens: recovered,
|
|
1455
1764
|
}) + '\n',
|
|
1456
1765
|
)
|
|
1457
|
-
await ctx.artifacts.writeJson('arm-summary.json', {
|
|
1766
|
+
const summaryPath = await ctx.artifacts.writeJson('arm-summary.json', {
|
|
1767
|
+
runDir,
|
|
1768
|
+
patchPath: armRes.patchPath,
|
|
1769
|
+
verdict,
|
|
1770
|
+
})
|
|
1771
|
+
|
|
1772
|
+
// GEN-5 settle-time rollout capture: emit supervisor + worker lines
|
|
1773
|
+
// NOW, while the opencode store still holds the worker transcripts.
|
|
1774
|
+
// Attribution comes from the campaign cell path (never dispatch
|
|
1775
|
+
// order); a capture failure logs loud but never kills the cell.
|
|
1776
|
+
if (settleCapture !== null) {
|
|
1777
|
+
try {
|
|
1778
|
+
const coords = campaignCoordsFromCellPath(summaryPath)
|
|
1779
|
+
if (coords === null) {
|
|
1780
|
+
log(`rollout-ledger: cannot derive campaign coords from ${summaryPath} — cell ${iid} r${ctx.rep} skipped`)
|
|
1781
|
+
} else {
|
|
1782
|
+
const supRunDir = await findSupervisorRunDir(armRes.ws)
|
|
1783
|
+
const deliveredPatch = await readFile(armRes.patchPath, 'utf8').catch(() => '')
|
|
1784
|
+
await settleCapture.captureCell({
|
|
1785
|
+
generation: coords.generation,
|
|
1786
|
+
candidateIndex: coords.candidateIndex,
|
|
1787
|
+
iid,
|
|
1788
|
+
rep: ctx.rep,
|
|
1789
|
+
seed: ctx.seed,
|
|
1790
|
+
splitVisibility: split === null ? null : privateIids.has(iid) ? 'private' : 'public',
|
|
1791
|
+
commit: cs.candidateCommit,
|
|
1792
|
+
resolved: verdict.resolved,
|
|
1793
|
+
judgeVerdict: { ...verdict, wallS: judgeWallS },
|
|
1794
|
+
runDir,
|
|
1795
|
+
patchPath: armRes.patchPath,
|
|
1796
|
+
supRunDir,
|
|
1797
|
+
deliveredPatch,
|
|
1798
|
+
workerModel: config.arm.workerModel,
|
|
1799
|
+
metrics: {
|
|
1800
|
+
resolved: verdict.resolved,
|
|
1801
|
+
verify_pass: armRes.verify_pass,
|
|
1802
|
+
patch_lines: armRes.patch_lines,
|
|
1803
|
+
judge_attempts: verdict.attempts ?? null,
|
|
1804
|
+
judge_wall_s: judgeWallS,
|
|
1805
|
+
spent_tokens: armRes.spentTokens,
|
|
1806
|
+
spent_usd: armRes.spentUsd,
|
|
1807
|
+
recovered_tokens: recovered,
|
|
1808
|
+
sup_status: armRes.sup_status,
|
|
1809
|
+
sup_verdict: armRes.sup_verdict,
|
|
1810
|
+
spawned: armRes.spawned,
|
|
1811
|
+
workers: armRes.workers,
|
|
1812
|
+
settled: armRes.settled,
|
|
1813
|
+
},
|
|
1814
|
+
cost: { usd: armRes.spentUsd, wallS: armRes.wall_s, spentTokens: armRes.spentTokens },
|
|
1815
|
+
})
|
|
1816
|
+
}
|
|
1817
|
+
} catch (cause) {
|
|
1818
|
+
log(`rollout-ledger: settle-time capture FAILED for ${iid} r${ctx.rep}: ${(cause as Error).message}`)
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1458
1821
|
|
|
1459
1822
|
if (verdict.resolved === null) {
|
|
1460
1823
|
// Inconclusive judge (double flake / infra) — the cell must FAIL, not
|
|
@@ -1557,6 +1920,7 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1557
1920
|
const runs: SupRunArtifacts[] = []
|
|
1558
1921
|
if (input.generation === -1) {
|
|
1559
1922
|
for (const seed of config.seedArtifactRuns) {
|
|
1923
|
+
if (privateIids.has(seed.iid)) continue // gen-5 split: never surfaced to proposers
|
|
1560
1924
|
if (!existsSync(seed.dir)) {
|
|
1561
1925
|
// A wiped scratchpad (host reboot) must not feed EMPTY bundles to the
|
|
1562
1926
|
// analysts as if they were real artifacts — skip loudly.
|
|
@@ -1581,6 +1945,7 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1581
1945
|
for (const cell of cells) {
|
|
1582
1946
|
const a = cell.artifact
|
|
1583
1947
|
if (a === null || a.kind !== 'swe-arm' || !a.runDir) continue
|
|
1948
|
+
if (privateIids.has(a.iid)) continue // gen-5 split: never surfaced to proposers
|
|
1584
1949
|
runs.push({
|
|
1585
1950
|
iid: a.iid,
|
|
1586
1951
|
arm: config.armName,
|
|
@@ -1618,8 +1983,25 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1618
1983
|
log(`diagnosis ensemble FAILED for gen ${input.generation}: ${(cause as Error).message}`)
|
|
1619
1984
|
}
|
|
1620
1985
|
}
|
|
1986
|
+
// GEN-5 split: the raw-trace distiller must not hand private-instance
|
|
1987
|
+
// cells' path context to the authors either — censor them out of the
|
|
1988
|
+
// candidates' campaigns before distillation.
|
|
1989
|
+
const censoredInput =
|
|
1990
|
+
split === null
|
|
1991
|
+
? input
|
|
1992
|
+
: {
|
|
1993
|
+
...input,
|
|
1994
|
+
candidates: input.candidates.map((cand) => {
|
|
1995
|
+
const campaign = cand.campaign as { cells?: Array<{ scenarioId: string }> } | null
|
|
1996
|
+
if (campaign === null || typeof campaign !== 'object' || !Array.isArray(campaign.cells)) return cand
|
|
1997
|
+
return {
|
|
1998
|
+
...cand,
|
|
1999
|
+
campaign: { ...campaign, cells: campaign.cells.filter((c) => !privateIids.has(c.scenarioId)) },
|
|
2000
|
+
}
|
|
2001
|
+
}),
|
|
2002
|
+
}
|
|
1621
2003
|
signal?.throwIfAborted()
|
|
1622
|
-
const rawFindings = (await rawTrace(
|
|
2004
|
+
const rawFindings = (await rawTrace(censoredInput as Parameters<typeof rawTrace>[0])) as unknown[]
|
|
1623
2005
|
signal?.throwIfAborted()
|
|
1624
2006
|
return [steeringFinding, ...ensembleFindings, ...rawFindings]
|
|
1625
2007
|
}
|
|
@@ -1638,12 +2020,36 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1638
2020
|
'tsx src/swe-arena/holdout-certify.mts <config.json> --candidate <winner-loops-commit>'
|
|
1639
2021
|
const improveRunDir = join(config.outDir, 'improve-run')
|
|
1640
2022
|
|
|
2023
|
+
// ── crash recovery: a killed run leaves its in-flight paid call 'pending'
|
|
2024
|
+
// in the durable cost ledger, and the ledger's fail-closed guard then
|
|
2025
|
+
// refuses ALL new paid work on resume. Under the outDir instance lock
|
|
2026
|
+
// (sole runner), every pending call restored from disk is provably from a
|
|
2027
|
+
// dead process — settle each as a $0 failure receipt (reason
|
|
2028
|
+
// 'process-crash-orphan') so the guard passes without erasing the crash
|
|
2029
|
+
// from the durable record. ───────────────────────────────────────────
|
|
2030
|
+
for (const receipt of reconcileCrashOrphansOnDisk(improveRunDir)) {
|
|
2031
|
+
log(
|
|
2032
|
+
`cost-ledger: reconciled crash-orphaned call '${receipt.callId}' ` +
|
|
2033
|
+
`(${receipt.actor}, ${receipt.phase}) as ${CRASH_ORPHAN_REASON}`,
|
|
2034
|
+
)
|
|
2035
|
+
}
|
|
2036
|
+
|
|
1641
2037
|
// ── generator: the gen-3 proposer fan-out (parallel AgentProfile-pinned
|
|
1642
2038
|
// authors + pre-filter) when `proposers` is configured; the legacy
|
|
1643
2039
|
// single-author generator otherwise. ─────────────────────────────────
|
|
1644
2040
|
const fanout =
|
|
1645
2041
|
config.proposers !== undefined
|
|
1646
|
-
? fanOutLoopsGenerator(config, {
|
|
2042
|
+
? fanOutLoopsGenerator(config, {
|
|
2043
|
+
...(smokeRunner ? { smokeRunner } : {}),
|
|
2044
|
+
...(paretoParents.length > 0 ? { parents: paretoParents } : {}),
|
|
2045
|
+
...(briefingCtx !== undefined ? { briefing: briefingCtx } : {}),
|
|
2046
|
+
// GEN-6: the GEPA seat's inner evaluator rides the SAME public-only
|
|
2047
|
+
// smoke instance; the split guards the never-surfaced invariant at
|
|
2048
|
+
// the bridge boundary too.
|
|
2049
|
+
...(smokeIid !== null ? { smokeInstanceId: smokeIid } : {}),
|
|
2050
|
+
scoreSplit: split,
|
|
2051
|
+
log,
|
|
2052
|
+
})
|
|
1647
2053
|
: null
|
|
1648
2054
|
const generator = withParentCancellation(fanout ?? constrainedLoopsGenerator(config), signal)
|
|
1649
2055
|
|
|
@@ -1737,10 +2143,25 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1737
2143
|
}
|
|
1738
2144
|
}
|
|
1739
2145
|
|
|
2146
|
+
// Collected per-candidate facts for the gen-5 machinery (activation by
|
|
2147
|
+
// surface hash for the winner brief, lineage nodes, proposer v2 rewards).
|
|
2148
|
+
const activationBySurface = new Map<string, ActivationRecord>()
|
|
2149
|
+
const lineageCandidates: LineageCandidateInput[] = []
|
|
2150
|
+
interface ProposerOutcomeFact {
|
|
2151
|
+
generation: number
|
|
2152
|
+
candidateIndex: number
|
|
2153
|
+
label: string
|
|
2154
|
+
commit: string | null
|
|
2155
|
+
resolvedCount: number
|
|
2156
|
+
diffPath: string | null
|
|
2157
|
+
}
|
|
2158
|
+
const proposerFacts: ProposerOutcomeFact[] = []
|
|
2159
|
+
|
|
1740
2160
|
for (let g = 0; g < loop.generations.length; g++) {
|
|
1741
2161
|
const gen = loop.generations[g]!
|
|
1742
2162
|
const rows: StaircaseRow[] = []
|
|
1743
|
-
for (
|
|
2163
|
+
for (let candIndex = 0; candIndex < gen.record.candidates.length; candIndex++) {
|
|
2164
|
+
const cand = gen.record.candidates[candIndex]!
|
|
1744
2165
|
const surface = gen.surfaces.find((s) => s.surfaceHash === cand.surfaceHash)?.surface
|
|
1745
2166
|
const cs = surface && typeof surface === 'object' && surface.kind === 'code' ? surface : null
|
|
1746
2167
|
const desc = cs ? await recorder.ensure(cs) : undefined
|
|
@@ -1764,6 +2185,71 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1764
2185
|
const parentResolvedCount =
|
|
1765
2186
|
parentCampaign !== undefined ? resolvedCountOf(parentCampaign) : measuredBaselineCount
|
|
1766
2187
|
const violations = desc?.violations ?? []
|
|
2188
|
+
|
|
2189
|
+
// GEN-5 activation gate: run the candidate's own committed predicate
|
|
2190
|
+
// over its own cell run dirs. Fail-closed — a missing/unparseable
|
|
2191
|
+
// predicate (the prefilter should have killed it) quarantines.
|
|
2192
|
+
let activation: ActivationRecord | undefined
|
|
2193
|
+
if (config.activationGate === true && cs !== null) {
|
|
2194
|
+
const committed = await readCommittedPredicate(config.loopsRepo, cs.candidateCommit)
|
|
2195
|
+
if (committed === null || !committed.parsed.ok) {
|
|
2196
|
+
const why =
|
|
2197
|
+
committed === null
|
|
2198
|
+
? `no ${ACTIVATION_PREDICATE_RELPATH} at ${cs.candidateCommit.slice(0, 10)}`
|
|
2199
|
+
: `unparseable activation predicate: ${committed.parsed.ok ? '' : committed.parsed.error}`
|
|
2200
|
+
activation = {
|
|
2201
|
+
present: false,
|
|
2202
|
+
description: null,
|
|
2203
|
+
fired: false,
|
|
2204
|
+
evidence: [],
|
|
2205
|
+
warnings: [`${why} — fail-closed quarantine`],
|
|
2206
|
+
}
|
|
2207
|
+
} else {
|
|
2208
|
+
const runDirs = [
|
|
2209
|
+
...new Set(
|
|
2210
|
+
cells
|
|
2211
|
+
.map((c) => (c.artifact !== null && c.artifact.kind === 'swe-arm' ? c.artifact.runDir : null))
|
|
2212
|
+
.filter((d): d is string => typeof d === 'string' && d.length > 0),
|
|
2213
|
+
),
|
|
2214
|
+
]
|
|
2215
|
+
const res = await runActivationPredicate(committed.parsed.predicate, runDirs)
|
|
2216
|
+
activation = {
|
|
2217
|
+
present: true,
|
|
2218
|
+
description: committed.parsed.predicate.description,
|
|
2219
|
+
fired: res.fired,
|
|
2220
|
+
evidence: res.evidence,
|
|
2221
|
+
warnings: res.warnings,
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
activationBySurface.set(cand.surfaceHash, activation)
|
|
2225
|
+
log(
|
|
2226
|
+
`activation ${cand.label ?? cand.surfaceHash.slice(0, 10)}: present=${activation.present} ` +
|
|
2227
|
+
`fired=${activation.fired}${activation.fired ? ` — ${activation.evidence[0] ?? ''}` : ''}` +
|
|
2228
|
+
`${activation.warnings.length > 0 ? ` (warnings: ${activation.warnings.join('; ')})` : ''}`,
|
|
2229
|
+
)
|
|
2230
|
+
}
|
|
2231
|
+
|
|
2232
|
+
// GEN-5 split sub-scores: both halves logged per candidate; the
|
|
2233
|
+
// selection rule stays combined (candResolved over ALL instances).
|
|
2234
|
+
const verdicts = instanceVerdictsFromCells(cells, config.instances, reps)
|
|
2235
|
+
const splitScores = split !== null ? subScores(verdicts, split) : null
|
|
2236
|
+
if (split !== null && splitScores !== null) {
|
|
2237
|
+
log(
|
|
2238
|
+
`split scores ${cand.label ?? cand.surfaceHash.slice(0, 10)}: ` +
|
|
2239
|
+
`public ${splitScores.publicResolvedCount}/${split.publicInstances.length}, ` +
|
|
2240
|
+
`private ${splitScores.privateResolvedCount}/${split.privateInstances.length} (combined ${candResolved}/${config.instances.length})`,
|
|
2241
|
+
)
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
const verdict = decideVerdict({
|
|
2245
|
+
violations,
|
|
2246
|
+
coverageComplete,
|
|
2247
|
+
resolvedCount: candResolved,
|
|
2248
|
+
parentResolvedCount,
|
|
2249
|
+
costRatio,
|
|
2250
|
+
costGuardRatio: config.costGuardRatio,
|
|
2251
|
+
...(activation !== undefined ? { activationFired: activation.fired } : {}),
|
|
2252
|
+
})
|
|
1767
2253
|
rows.push({
|
|
1768
2254
|
schema: STAIRCASE_SCHEMA,
|
|
1769
2255
|
round: config.round,
|
|
@@ -1786,18 +2272,39 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1786
2272
|
costRatio,
|
|
1787
2273
|
costGuardRatio: config.costGuardRatio,
|
|
1788
2274
|
internallyPromoted: gen.record.promoted.includes(cand.surfaceHash),
|
|
1789
|
-
verdict
|
|
1790
|
-
violations,
|
|
1791
|
-
coverageComplete,
|
|
1792
|
-
resolvedCount: candResolved,
|
|
1793
|
-
parentResolvedCount,
|
|
1794
|
-
costRatio,
|
|
1795
|
-
costGuardRatio: config.costGuardRatio,
|
|
1796
|
-
}),
|
|
2275
|
+
verdict,
|
|
1797
2276
|
holdout: 'operator-approval-required',
|
|
1798
2277
|
armProvenance: desc?.armProvenance ?? null,
|
|
1799
2278
|
diffPath: desc?.diffPath ?? null,
|
|
1800
2279
|
diffSha256: desc?.diffSha256 ?? null,
|
|
2280
|
+
...(split !== null && splitScores !== null
|
|
2281
|
+
? {
|
|
2282
|
+
split: {
|
|
2283
|
+
publicInstances: split.publicInstances,
|
|
2284
|
+
privateInstances: split.privateInstances,
|
|
2285
|
+
...splitScores,
|
|
2286
|
+
},
|
|
2287
|
+
}
|
|
2288
|
+
: {}),
|
|
2289
|
+
...(activation !== undefined ? { activation } : {}),
|
|
2290
|
+
})
|
|
2291
|
+
|
|
2292
|
+
const label = cand.label ?? cs?.candidateCommit?.slice(0, 10) ?? cand.surfaceHash.slice(0, 10)
|
|
2293
|
+
lineageCandidates.push({
|
|
2294
|
+
label,
|
|
2295
|
+
commit: cs?.candidateCommit ?? null,
|
|
2296
|
+
resolvedCount: candResolved,
|
|
2297
|
+
verdicts,
|
|
2298
|
+
merge: config.proposers?.find((p) => p.name === cand.label)?.merge === true,
|
|
2299
|
+
verdict,
|
|
2300
|
+
})
|
|
2301
|
+
proposerFacts.push({
|
|
2302
|
+
generation: g,
|
|
2303
|
+
candidateIndex: candIndex,
|
|
2304
|
+
label,
|
|
2305
|
+
commit: cs?.candidateCommit ?? null,
|
|
2306
|
+
resolvedCount: candResolved,
|
|
2307
|
+
diffPath: desc?.diffPath ?? null,
|
|
1801
2308
|
})
|
|
1802
2309
|
}
|
|
1803
2310
|
const genFile = join(config.roundsDir, `gen-${g}.jsonl`)
|
|
@@ -1823,7 +2330,7 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1823
2330
|
parent: premeasured?.surfaceHash ?? 'baseline',
|
|
1824
2331
|
parentResolvedCount: measuredBaselineCount,
|
|
1825
2332
|
label: kill.proposer,
|
|
1826
|
-
rationale: `prefilter kill at stage '${kill.stage}' (${kill.harness})`,
|
|
2333
|
+
rationale: `prefilter kill at stage '${kill.stage}' (${kill.harness ?? 'engine'})`,
|
|
1827
2334
|
changedFiles: [],
|
|
1828
2335
|
changeSpaceViolations: kill.stage === 'change-space' ? [kill.reason] : [],
|
|
1829
2336
|
perInstance: [],
|
|
@@ -1847,6 +2354,74 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1847
2354
|
}
|
|
1848
2355
|
}
|
|
1849
2356
|
|
|
2357
|
+
// GEN-5 label-v2 proposer rewards: baseline-relative (candidate − baseline
|
|
2358
|
+
// resolved fraction, improvement positive), one settle-time ledger line
|
|
2359
|
+
// per evaluated candidate now that the round's scores are final.
|
|
2360
|
+
if (settleCapture !== null) {
|
|
2361
|
+
const sanitizeName = (s: string): string => s.replace(/[^a-zA-Z0-9_-]/g, '_')
|
|
2362
|
+
for (const fact of proposerFacts) {
|
|
2363
|
+
try {
|
|
2364
|
+
const flatDir = join(config.outDir, 'proposer-shots')
|
|
2365
|
+
const pattern = new RegExp(`^gen${fact.generation}-cand${fact.candidateIndex}-shot\\d+\\.json$`)
|
|
2366
|
+
const receiptPaths: string[] = []
|
|
2367
|
+
for (const dir of [flatDir, join(flatDir, sanitizeName(fact.label))]) {
|
|
2368
|
+
for (const name of (await readdir(dir).catch(() => [])).sort()) {
|
|
2369
|
+
if (pattern.test(name)) receiptPaths.push(join(dir, name))
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2372
|
+
await settleCapture.captureProposer({
|
|
2373
|
+
generation: fact.generation,
|
|
2374
|
+
candidateIndex: fact.candidateIndex,
|
|
2375
|
+
proposer: fact.label,
|
|
2376
|
+
harness: config.proposers?.find((p) => p.name === fact.label)?.harness ?? null,
|
|
2377
|
+
commit: fact.commit,
|
|
2378
|
+
candResolved: fact.resolvedCount,
|
|
2379
|
+
baselineResolved: measuredBaselineCount,
|
|
2380
|
+
shotReceiptPaths: receiptPaths,
|
|
2381
|
+
diffPath: fact.diffPath,
|
|
2382
|
+
})
|
|
2383
|
+
} catch (cause) {
|
|
2384
|
+
log(`rollout-ledger: proposer capture FAILED for ${fact.label}: ${(cause as Error).message}`)
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
// GEN-5 lineage DAG: record baseline root + pareto parents + every
|
|
2390
|
+
// evaluated candidate (multi-parent for the merge seat) at the
|
|
2391
|
+
// .evolve-compatible store, and ask the governor for the continuation
|
|
2392
|
+
// decision (recorded below — never acted on inside this run).
|
|
2393
|
+
let lineageResult: Awaited<ReturnType<typeof recordLineageGeneration>> | null = null
|
|
2394
|
+
if (config.lineage === true) {
|
|
2395
|
+
try {
|
|
2396
|
+
const baselineCommit =
|
|
2397
|
+
baselineCells.find((c) => c.artifact !== null && c.artifact.kind === 'swe-arm')?.artifact?.commit ??
|
|
2398
|
+
config.loopsBaseRef
|
|
2399
|
+
lineageResult = await recordLineageGeneration({
|
|
2400
|
+
outDir: config.outDir,
|
|
2401
|
+
runId,
|
|
2402
|
+
instances: config.instances,
|
|
2403
|
+
baseline: {
|
|
2404
|
+
commit: baselineCommit,
|
|
2405
|
+
resolvedCount: measuredBaselineCount,
|
|
2406
|
+
verdicts: instanceVerdictsFromCells(baselineCells, config.instances, reps),
|
|
2407
|
+
},
|
|
2408
|
+
paretoParents: (config.paretoParents ?? []).map((p) => ({
|
|
2409
|
+
label: p.label,
|
|
2410
|
+
commit: p.commit,
|
|
2411
|
+
resolvedInstances: p.resolvedInstances,
|
|
2412
|
+
})),
|
|
2413
|
+
candidates: lineageCandidates,
|
|
2414
|
+
})
|
|
2415
|
+
log(
|
|
2416
|
+
`lineage: ${lineageResult.appended.length} node(s) appended (total ${lineageResult.nodesTotal}) → ` +
|
|
2417
|
+
`${lineageResult.path}; governor decision: ${JSON.stringify(lineageResult.governor)}` +
|
|
2418
|
+
`${lineageResult.skipped.length > 0 ? `; skipped (no commit): ${lineageResult.skipped.join(', ')}` : ''}`,
|
|
2419
|
+
)
|
|
2420
|
+
} catch (cause) {
|
|
2421
|
+
log(`lineage: recording FAILED: ${(cause as Error).message}`)
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
|
|
1850
2425
|
const winnerSurface = result.raw.winner.surface
|
|
1851
2426
|
const winnerCs =
|
|
1852
2427
|
typeof winnerSurface === 'object' && winnerSurface !== null && winnerSurface.kind === 'code'
|
|
@@ -1884,6 +2459,7 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1884
2459
|
// is worth approving.
|
|
1885
2460
|
const winnerHash = winnerCs ? surfaceHash(winnerCs) : null
|
|
1886
2461
|
const winnerCampaign = winnerHash !== null ? campaignBySurface.get(winnerHash) : undefined
|
|
2462
|
+
const winnerActivation = winnerHash !== null ? activationBySurface.get(winnerHash) : undefined
|
|
1887
2463
|
const improvementSet =
|
|
1888
2464
|
winnerCampaign !== undefined && winnerRec !== undefined
|
|
1889
2465
|
? gateEvidenceFromCells({
|
|
@@ -1893,6 +2469,7 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1893
2469
|
iids: config.instances,
|
|
1894
2470
|
reps,
|
|
1895
2471
|
costGuardRatio: config.costGuardRatio,
|
|
2472
|
+
...(winnerActivation !== undefined ? { activationFired: winnerActivation.fired } : {}),
|
|
1896
2473
|
})
|
|
1897
2474
|
: null
|
|
1898
2475
|
const wouldKeep = improvementSet !== null && improvementSet.verdict === 'accepted'
|
|
@@ -1938,6 +2515,49 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1938
2515
|
gateReasons: loop.gateResult.reasons,
|
|
1939
2516
|
// Improvement-set (search-split) evidence — NOT a held-out measurement.
|
|
1940
2517
|
improvementSet: improvementSet === null ? null : { ...improvementSet, wouldKeep },
|
|
2518
|
+
// GEN-5: the public/private split (sub-scores live per candidate in the
|
|
2519
|
+
// staircase rows; selection stays combined; private never surfaced to
|
|
2520
|
+
// proposers — the 2-of-6 private half is a direction check, not a
|
|
2521
|
+
// certification).
|
|
2522
|
+
scoreSplit:
|
|
2523
|
+
split === null
|
|
2524
|
+
? null
|
|
2525
|
+
: {
|
|
2526
|
+
seededBy: split.seededBy,
|
|
2527
|
+
publicInstances: split.publicInstances,
|
|
2528
|
+
privateInstances: split.privateInstances,
|
|
2529
|
+
},
|
|
2530
|
+
// GEN-5: activation-gate outcomes per candidate surface.
|
|
2531
|
+
activationGate:
|
|
2532
|
+
config.activationGate === true
|
|
2533
|
+
? {
|
|
2534
|
+
enabled: true,
|
|
2535
|
+
byCandidate: [...activationBySurface.entries()].map(([surface, a]) => ({
|
|
2536
|
+
surface,
|
|
2537
|
+
present: a.present,
|
|
2538
|
+
fired: a.fired,
|
|
2539
|
+
description: a.description,
|
|
2540
|
+
})),
|
|
2541
|
+
}
|
|
2542
|
+
: { enabled: false },
|
|
2543
|
+
// GEN-5: MAP+TOOLBOX briefing provenance.
|
|
2544
|
+
briefing:
|
|
2545
|
+
briefingCtx === undefined
|
|
2546
|
+
? null
|
|
2547
|
+
: { version: AUTHOR_BRIEFING_VERSION, indexPath: briefingCtx.indexPath, textSource: briefingCtx.briefingSource },
|
|
2548
|
+
// GEN-5: settle-time rollout ledger location (tangle.rollout.v1, label v2).
|
|
2549
|
+
rolloutLedger: settleCapture === null ? null : { path: settleCapture.path, capture: 'settle-time', labels: 'v2' },
|
|
2550
|
+
// GEN-5: lineage DAG + the governor's recorded continuation decision.
|
|
2551
|
+
lineage:
|
|
2552
|
+
lineageResult === null
|
|
2553
|
+
? null
|
|
2554
|
+
: {
|
|
2555
|
+
path: lineageResult.path,
|
|
2556
|
+
nodesTotal: lineageResult.nodesTotal,
|
|
2557
|
+
appended: lineageResult.appended.length,
|
|
2558
|
+
skipped: lineageResult.skipped,
|
|
2559
|
+
governor: lineageResult.governor,
|
|
2560
|
+
},
|
|
1941
2561
|
// Honest run-wide spend from the lib's CostLedger: per-channel rollups
|
|
1942
2562
|
// (agent = arm cells, judge = official-judge calls, driver = proposer
|
|
1943
2563
|
// shots), token totals, and accounting-completeness flags.
|
|
@@ -1969,6 +2589,18 @@ export async function runRound(config: OuterLoopConfig, signal?: AbortSignal): P
|
|
|
1969
2589
|
const summaryPath = join(config.roundsDir, `round${config.round}-summary-${runId}.json`)
|
|
1970
2590
|
await writeFile(summaryPath, JSON.stringify(summary, null, 2))
|
|
1971
2591
|
log(`round summary → ${summaryPath}`)
|
|
2592
|
+
|
|
2593
|
+
// Round rollup at gate time: every cell's orchestration/economics in one table,
|
|
2594
|
+
// written next to the round summary and echoed into the run log.
|
|
2595
|
+
await reportSupervisorRound(join(config.outDir, 'arm-runs'), {
|
|
2596
|
+
appendHeadlineTo: join(config.outDir, 'run.log'),
|
|
2597
|
+
reportDir: config.roundsDir,
|
|
2598
|
+
title: `Round ${config.round} rollup — ${runId}`,
|
|
2599
|
+
echo: true,
|
|
2600
|
+
}).catch((err: unknown) => {
|
|
2601
|
+
log(`round rollup failed: ${err instanceof Error ? err.message : String(err)}`)
|
|
2602
|
+
})
|
|
2603
|
+
|
|
1972
2604
|
log(`gate: ${result.decision} — ${loop.gateResult.reasons[0] ?? ''}`)
|
|
1973
2605
|
} finally {
|
|
1974
2606
|
await result.dispose()
|
|
@@ -2087,17 +2719,35 @@ if (isMain) {
|
|
|
2087
2719
|
if (argv[0] === '--write-config') {
|
|
2088
2720
|
const path = argv[1]
|
|
2089
2721
|
if (!path || path.startsWith('--')) {
|
|
2090
|
-
console.error('usage: outer-loop.mts --write-config <path> [--out-name <dirname>] [--gen3]')
|
|
2722
|
+
console.error('usage: outer-loop.mts --write-config <path> [--out-name <dirname>] [--gen3|--gen4|--gen5]')
|
|
2091
2723
|
process.exit(2)
|
|
2092
2724
|
}
|
|
2093
2725
|
const outDirName = flag('--out-name')
|
|
2094
2726
|
const gen3 = argv.includes('--gen3')
|
|
2095
|
-
const
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
)
|
|
2100
|
-
|
|
2727
|
+
const gen4 = argv.includes('--gen4')
|
|
2728
|
+
const gen5 = argv.includes('--gen5')
|
|
2729
|
+
let config: OuterLoopConfig
|
|
2730
|
+
let flavor: string
|
|
2731
|
+
if (gen4 || gen5) {
|
|
2732
|
+
// The codex seat rides only when the CLI is actually present — a config
|
|
2733
|
+
// naming a missing harness would fail the whole launch at t=0.
|
|
2734
|
+
const codexProbe = await run('codex', ['--version'])
|
|
2735
|
+
const includeCodex = codexProbe.code === 0
|
|
2736
|
+
if (!includeCodex) {
|
|
2737
|
+
console.log(
|
|
2738
|
+
`codex CLI unavailable (rc=${codexProbe.code}) — ${gen5 ? 'gen-5' : 'gen-4'} config written WITHOUT the codex-author seat`,
|
|
2739
|
+
)
|
|
2740
|
+
}
|
|
2741
|
+
const make = gen5 ? defaultGen5Config : defaultGen4Config
|
|
2742
|
+
config = make(undefined, { ...(outDirName ? { outDirName } : {}), includeCodex })
|
|
2743
|
+
flavor = gen5 ? 'gen-5' : 'gen-4'
|
|
2744
|
+
} else {
|
|
2745
|
+
const make = gen3 ? defaultGen3Config : defaultRound4Config
|
|
2746
|
+
config = make(undefined, outDirName ? { outDirName } : {})
|
|
2747
|
+
flavor = gen3 ? 'gen-3' : 'round-4'
|
|
2748
|
+
}
|
|
2749
|
+
await writeFile(path, JSON.stringify(config, null, 2) + '\n')
|
|
2750
|
+
console.log(`default ${flavor} config → ${path}`)
|
|
2101
2751
|
} else if (argv[0] === '--calibration-smoke') {
|
|
2102
2752
|
const dir = argv[1] && !argv[1].startsWith('--') ? argv[1] : undefined
|
|
2103
2753
|
const n = flag('--analysts')
|
|
@@ -2130,7 +2780,7 @@ if (isMain) {
|
|
|
2130
2780
|
} else {
|
|
2131
2781
|
console.error(
|
|
2132
2782
|
'usage: tsx src/swe-arena/outer-loop.mts <config.json> # SPENDS: arms + judges + proposer\n' +
|
|
2133
|
-
' tsx src/swe-arena/outer-loop.mts --write-config <path> [--out-name <dirname>] [--gen3]\n' +
|
|
2783
|
+
' tsx src/swe-arena/outer-loop.mts --write-config <path> [--out-name <dirname>] [--gen3|--gen4|--gen5]\n' +
|
|
2134
2784
|
' tsx src/swe-arena/outer-loop.mts --calibration-smoke [supRunDir] [--analysts N] [--model M] [--endpoint router|zai] [--retries N]',
|
|
2135
2785
|
)
|
|
2136
2786
|
process.exit(2)
|