/** * S1 value-verdict harness β€” the FAIRNESS ROOT (SPEC-S1-value-harness.md Β§2). ONE place constructs the shared * Runner ingredients (config / brain / pricing), the SAME budget for every arm, and the injected deterministic * clock that makes C2 (human-review wall-time) reproducible. * * πŸ”΄ THE Β§3.2 RED LINE ([ref]'s #1 confound): every leaf TaskSpec across all 3 arms carries the SAME * `limits.{ maxTokens, maxCostUsd, maxTurns }` (core β‰₯5.8: budget keys live ONLY in `limits` β€” a top-level * `maxTokens`/`maxCostUsd` is a silently-unread dead key), and TEAM's per-worker budgets sum to ≀ the solo budget β€” so no * arm can win on a bigger pie. `assertBudgetMatch` (below) is the build-time guard the shape test runs. * * πŸ”΄ BUDGET-MATCH for TEAM is NEW WIRING no leader live test does: the (now-deleted, 7.83.0 / [ref] β‘£) conflict * live test set NO budget on `SubtaskSpec.spec` and NO `now` on any Runner. The harness STAMPS both (arms.ts) β€” * copying a live test verbatim would yield an unbounded TEAM (the confound) and an empty `humanReview` (C2 = undefined). * * The real-infra construction (E2B worker/grader envs + a live brain) is deferred to the live make-real proof * (`test/s1-value-live.test.ts`, gated on E2B+DEEPSEEK). This module only fixes the SHAPE + the budget invariant * + the clock; a deterministic shape test exercises it with a MOCK runner (no real agents, no keys). */ import type { ExecutionEnv } from "@sema-agent/core"; /** η”± bench ε…₯口(`run-firm.ts` ηš„ `--debug-git`)ηΏ»εΌ€;不调 = 关。 */ export declare function setS1DebugGit(on: boolean): void; /** tar/import/oracle/leader 四族 stderr θΏ½θΈͺεΌ€η€ζ²‘ζœ‰(读侧单点)。 */ export declare function s1DebugGit(): boolean; /** * The budget block the budget-match guard compares. NOT a s1.v1 RawRow field (the contract carries no budget) β€” * it is a PRODUCER-side fairness descriptor (one per emitted cell). `teamWorkerBudgetSumUsd` is the bigger-pie * guard input (TEAM only): Ξ£ per-worker maxCostUsd, asserted ≀ maxCostUsd. */ export interface RowBudget { modelId: string; maxTokens: number; maxCostUsd: number; maxTurns: number; maxRounds: number; supAutoBudget?: number; /** TEAM only: Ξ£ per-worker maxCostUsd β€” asserted ≀ maxCostUsd (anti-bigger-pie confound). */ teamWorkerBudgetSumUsd?: number; } /** Project the producer's shared budget (+ an optional TEAM worker-sum) into a `RowBudget` for the fairness guard. */ export declare function budgetDescriptor(budget: BenchBudget, arm: string, teamWorkerBudgetSumUsd?: number): RowBudget; /** The single budget every arm shares (the Β§3.2 red line). All scalars are the SAME across SOLO/SUP/TEAM. */ export interface BenchBudget { /** SAME base model all arms ([ref] Β§3.2 β€” decorrelation is a separate axis, not the value axis). */ modelId: string; /** `TaskSpec.limits.maxTokens` β€” SAME all arms. */ maxTokens: number; /** `TaskSpec.limits.maxCostUsd` β€” SAME all arms (also the per-run spend cap). For TEAM, Ξ£worker ≀ this. */ maxCostUsd: number; /** `TaskSpec.limits.maxTurns` β€” SAME all arms. */ maxTurns: number; /** `VerifyConfig.maxRounds` (verify-fix rounds) β€” SAME for SOLO & SUP. */ maxRounds: number; /** `createDurableAskPolicy.autoBudget` β€” the SUP per-leg auto-approve circuit-breaker count, constant across SUP cells. */ supAutoBudget: number; } /** * An injectable deterministic clock (SPEC Β§2). EVERY Runner in EVERY arm is built with `now: ctx.now`, and the * reviewer's modeled think-time advances `advanceClock(ms)` β€” so `stats.humanReview.totalWaitMs` is reproducible * and NEVER consumes real wall-time (`RunnerDeps.now`, core types.d.ts / [ref] Β§4.3 flaky-guard). * * πŸ”΄ CLOCK-ADVANCE OWNERSHIP (review #10 β€” HARNESS-OWNS-CLOCK, the single fold point per arm): the modeled review * wait is folded into ctx.clock by the HARNESS exactly once per arm β€” SUP in driveSupSuspendResume (per leg), TEAM * in runArm after captureTeamStats. The live TEAM leader's workers therefore MUST NOT advance ctx.clock themselves * (give them a child/frozen clock); if a worker shared ctx.now and hit a modeled review gate it would advance the * clock, and runArm's `advanceClock(stats.humanReview.totalWaitMs)` would DOUBLE-COUNT the same wait into C3 * (wallTimeSec), making TEAM look slower than it is β€” a value-verdict confound in a fair-comparison harness. */ export interface BenchClock { now: () => number; advanceClock: (ms: number) => void; } /** Construct the deterministic clock used to model C2 review seconds (no real wall-time advance). */ export declare function makeBenchClock(startEpochMs?: number): BenchClock; /** * The shared context every arm runs in. Construction of `config/brain/pricing/newWorkerEnv/newGraderEnv` is the * live make-real proof's job (it needs real keys + a real adapter). The SHAPE is fixed here so the arm runner + * the shape test type-check against it. * * πŸ”΄ `newGraderEnv` MUST return a DISTINCT env object from `newWorkerEnv` (decorrelation + the repair-loop Β§5.1 * anti-reward-hack identity check β€” `repair-loop.d.ts`: `graderEnv === workerEnv β†’ oracle.unprotected`). The * oracle (oracle.ts) ALWAYS grades in a grader env; the repair leg ALWAYS passes `workerEnv` so the identity * check is LIVE (it is SKIPPED when `workerEnv` is undefined β†’ a silently reward-hackable oracle). */ export interface RunnerCtx { budget: BenchBudget; clock: BenchClock; /** A stable id for the whole batch (rows carry it for resume-by-(taskId,repeatIdx,arm) + orphan reap). */ runId: string; /** The git SHA the harness ran at (provenance for search). */ gitSha: string; } /** * Apply the shared budget to a leaf TaskSpec-like object (SOLO impl, SUP impl, each TEAM `SubtaskSpec.spec`). * Returns the budget fields to spread onto the spec β€” kept as a helper so EVERY leaf is stamped identically * (the live tests forget this for TEAM workers β€” the confound). `maxCostUsd` is overridable for the TEAM * per-worker split (Ξ£ ≀ solo, enforced by `assertBudgetMatch`). * * πŸ”΄ ALL THREE keys live under `limits` β€” core β‰₯5.8 reads `maxTokens`/`maxCostUsd` ONLY from `TaskSpec.limits`; * a top-level key is DEAD (silently unread β€” the cost/token gates never bind). */ export declare function leafBudgetFields(budget: BenchBudget, overrideMaxCostUsd?: number): { limits: { maxTokens: number; maxCostUsd: number; maxTurns: number; }; }; /** * BUDGET-MATCH build-time guard (the Β§3.2 red line β€” run by the shape test). FAILS if, within a task class: * (a) any arm's `{ modelId, maxTokens, maxCostUsd, maxTurns, maxRounds }` differs, OR * (b) a TEAM row's `teamWorkerBudgetSumUsd` exceeds `maxCostUsd` (the bigger-pie confound). * * Pure over the rows' `budget` blocks (so it works on emitted RawRows AND on a pre-flight check). Returns the * list of violations (empty = OK) so the caller can assert it. */ export declare function assertBudgetMatch(rows: Array<{ arm: string; taskId: string; budget: RowBudget; }>): string[]; /** Assert two execution envs are DISTINCT objects (the Β§5.1 anti-reward-hack precondition). Throws if same. */ export declare function assertDistinctEnvs(workerEnv: ExecutionEnv, graderEnv: ExecutionEnv): void; //# sourceMappingURL=runner-ctx.d.ts.map