evals: merge-readiness fixes for the external-harness stack - #2649
Conversation
- Verifiability gate: verifier-failed rows now count as ungraded (self-reported) runs on their arm; a configured gate fails when any appear, and the per-arm report line shows them. A gated batch can no longer publish self-reported rows silently. - GAIA: complete the removal — dataset, suite builder, fan-out, category overrides, legacy-only sets, help text. b:gaia now says 'Unknown benchmark' instead of pointing at a broken --legacy path. - Planner: a stagehand-harness selection that reduces to nothing runnable errors with harness guidance instead of planning zero cases; broad targets still omit suites and plan the rest. - Codex: cap tool steps (EVAL_CODEX_MAX_STEPS, falling back to AGENT_EVAL_MAX_STEPS, default 50) by aborting the stream at budget — runs get a citable action budget instead of an unbounded one. - Prompts: restore the per-dataset constraints from the retired suite modules (OnlineMind2Web's stay-on-site rule; navigate guidance for WebTailBench/Odysseys) in both harness prompt builders. - Tags: strip stagehand agent-mode tags (dom/hybrid/cua) from external- harness testcases so Braintrust tag filters don't pool them with historical Stagehand agent runs. - stagehand_code: normalize screenshot bytes to Buffer (v4 SDK returns Uint8Array; Buffer.isBuffer consumers silently dropped screenshots) — ported from the facade worktree.
|
There was a problem hiding this comment.
All reported issues were addressed across 19 files
Architecture diagram
sequenceDiagram
participant TUI as TUI / CLI (run)
participant Plan as Bench Planner
participant Suite as Suite Builders
participant Prom as Prompt Builder
participant Codex as Codex Runner
participant SDK as Codex SDK / Thread
participant Shot as stagehand_code
participant Verif as Verifier Adapter
participant Gate as Verifier Gate (run.ts)
Note over TUI,Gate: External-harness eval run (webvoyager / onlineMind2Web / webtailbench / odysseys)
Note over TUI: GAIA removed - b:gaia shorthand now reports "Unknown benchmark"
TUI->>Plan: generateBenchTestcases(harness=stagehand)
alt Selection reduces to nothing runnable (suite-only)
Plan-->>TUI: CHANGED: EvalsError - re-run with --harness claude_code or codex
else Broad target
Plan->>Plan: omit agent suites from stagehand plan, keep rest
end
TUI->>Suite: build<Dataset>Testcases(models)
Suite->>Suite: CHANGED: strip dom/hybrid/cua tags from testcases
Suite-->>TUI: rows tagged harness/<harness>
TUI->>Codex: runCodexAgent(plan)
Codex->>Codex: NEW: read EVAL_CODEX_MAX_STEPS fallback AGENT_EVAL_MAX_STEPS, default 50
Codex->>SDK: runStreamed(prompt, signal: budgetController)
loop Agent tool loop
SDK-->>Codex: event item.completed
alt command_execution or mcp_tool_call
Codex->>Codex: toolStepCount += 1
opt toolStepCount >= maxToolSteps
Codex->>SDK: abort stream (stop reason: tool step budget exhausted)
end
end
end
Note over Prom,Codex: NEW: dataset guidance added to prompt (codex + claude_code runners)
Codex->>Prom: datasetPromptGuidance(dataset)
Prom-->>Codex: stay-on-site (onlineMind2Web) / navigation hint (webtailbench, odysseys)
Note over Shot,Verif: CHANGED: v4 SDK screenshot bytes normalized to Buffer
Codex->>Shot: page.screenshot() / captureStagehandEvidence()
Shot-->>Codex: Buffer.from(bytes)
Codex->>Verif: gradeExternalTrajectory(trajectory)
alt Verifier fails (verifierError set)
Verif-->>Codex: self-reported _success only (ungraded)
else Verifier grades
Verif-->>Codex: criterionCount + evidenceInsufficient
end
Codex-->>TUI: TaskResult
TUI->>Gate: summarizeArmVerifiability(results)
Gate-->>TUI: per-arm gradedRuns + ungradedRuns
Note over TUI,Gate: Verifiability line reports ungraded (self-reported) count
alt EVAL_MAX_UNVERIFIABLE_CRITERIA set and any arm has ungraded runs
TUI->>TUI: NEW: fail batch (exit 1) - self-reported rows never published
end
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
The --legacy escape hatch could no longer run anything on this branch: bench a/e/o tasks need the v4 harness context the legacy runner never builds, the individual agent modules are gone, and the suite fan-outs resolve task modules that no longer exist. Dead escape hatches are worse than none — they route users to a path that exits. - Delete cli-legacy.ts, index.eval.ts, args.ts, and tui/commands/legacy.ts (and the evals:old script). - Drop the --legacy flag, LEGACY_ONLY_BENCHMARKS (osworld now reports 'Unknown benchmark'), the legacy-only target/split machinery in the run command, and the skipped-tasks plumbing in the dry-run payload and preview that existed only to report legacy-skipped suites.
There was a problem hiding this comment.
All reported issues were addressed across 11 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
- ARCHITECTURE.mmd: drop the legacy CLI nodes and skippedTasks from the dry-run payload shape; README: drop the removed --agent-mode(s) row - run.test: assert the exact planned matrix instead of a vacuous every() - codexRunner: detach the abort forwarder after each run so long batches don't accumulate listeners on the shared signal
The matrix carries one row per default model; the exact-array assertion tripped on multiplicity. The unique set still fails on an empty matrix and on a suite leaking into the plan.
There was a problem hiding this comment.
All reported issues were addressed across 4 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
--provider filtered the default model list down to bare model ids (gpt-4o-mini, claude-...), which the v4 initStagehand cannot key-resolve — provider-filtered runs died before browser startup. The flag is redundant: --model overrides a single run, and per-harness model lists (EVAL_CLAUDE_CODE_MODELS / EVAL_CODEX_MODELS) cover multi-model selection with fully-qualified ids. Braintrust metadata keeps its provider field — now derived from the model id's provider/ prefix instead of a separate selector.
- Both external-harness adapters now apply the normal-teardown timeout (EVAL_AGENT_MOUNT_CLEANUP_TIMEOUT_MS) on the setup-failure cleanup path too — a hung cleanup can no longer wedge the row. - ARCHITECTURE.mmd's dry-run node lists the actual payload fields.
There was a problem hiding this comment.
All reported issues were addressed across 14 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
The agent-facing half of the stagehand_code code-mode surface: prepareLLMExposure initializes a v4 Stagehand client via initStagehand and declares a code_handles agent mount — stagehand/page/z in the snippet scope, surface-owned prompt instructions and run-tool copy, final-state evidence capture (screenshot + URL + aria tree), and cleanup that closes the browser as well as the client (stagehand.close() alone leaves the browser running). Nothing consumes the mount here; the claude_code adapter does in #2596 and codex in #2609. Bottom of the nondeterministic-evals stack (#2591 → #2611, with the merge-readiness fixes in #2649 and the MCP tool surfaces in #2650 stacked on top).⚠️ **Base housekeeping before merge**: this PR still targets `evals-v4-root`, which has since merged (via #2570 → #2494) into `v4-spike`. Rebase onto current `v4-spike` and retarget. One known reconciliation: v4-spike removed the `EVAL_VERIFIER_MODEL` override from `verifierAdapter` (2af557b) as redundant with V3Evaluator's own constructor options; this stack's later PRs still carry it — drop it during the rebase rather than reintroducing it. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Adds the `stagehand_code` code-mode tool and registers it in the core tool registry, wiring a v4 `@browserbasehq/stagehand` client with scoped handles, run-tool execution, artifact capture, and full teardown. Enables the v4 code-mode surface for STG-2671 with a fixed SDK model and local/Browserbase startup profiles. - New Features - New `StagehandCodeTool` (`id: stagehand_code`) with session, navigation, evaluation, screenshot, viewport, wait, click, hover, scroll, type, press, tabs, and representation. - Targets: `selector`, `coords`, `focused`. - Agent mount via handles: `stagehand`, `page`, and `z`; scoped prompt instructions; run-tool description, code param description, and deny message. Snippets also get `startUrl`, `task`, and `console` in scope. - Captures screenshot, URL, and ARIA tree; cleanup closes both the Stagehand client and the browser. - Profiles: `tool_launch_local` and `tool_create_browserbase`; connection mode derived; model fixed to `openai/gpt-4.1-mini`. - Registered in `listCoreTools`/`getCoreTool`; tests assert `stagehand_code` is retrievable and that prompt guidance includes awaited locator actions. <sup>Written for commit e579140. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/2591?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
## Summary Codex joins claude_code as an external harness across all three code tool surfaces (`stagehand_code`, `playwright_code`, `cdp_code`) — recreating #2397 on the LLMExposure architecture. codex-sdk has no in-process MCP mounting (unlike claude-agent-sdk), and an external MCP process could not share this process's live surface handles. So the codex mount for a `code_handles` exposure is a loopback HTTP bridge: this process executes snippets against the in-memory handles; the codex workspace gets a tiny `browser_run.mjs` client that posts a snippet file to the bridge and prints the result. Scope semantics are identical to the claude_code run tool. - `codexCodeBridge.ts` (new): the bridge server + generated workspace client - `codexToolAdapter.ts`: code-surface mounting (exposure selection, bridge lifecycle, tmpdir cwd, prompt rewrite from run-tool to `browser_run.mjs` invocation) - `codexRunner.ts` / `harnesses/codexAdapter.ts`: harness-observed terminal artifact anchors the verifier's final observation, mirroring the claude_code runner - Tests: bridge round-trip + widened surface resolution Part of the nondeterministic-evals stack; stacks on the exposure-adapter PR. Follow-up on top of the stack: #2650 adds the MCP tool surfaces (playwright_mcp / chrome_devtools_mcp) to both external harnesses; MCP tool calls there count against the codex tool-step budget introduced in #2649. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Enable Codex on `stagehand_code`, `playwright_code`, and `cdp_code` via a loopback HTTP bridge that runs snippets against in-memory handles, with terminal artifact capture in the runner for grounded grading. `browse_cli` remains supported with sane startup defaults, and code surfaces now have clear `browser_run.mjs` guidance. - **New Features** - Bridge server/client in `codexCodeBridge.ts`: `browser_run.mjs` posts snippet code to `/run`; executes with `handles`, `startUrl`, `task`, and `console`; timeout via `EVAL_CODEX_RUN_TOOL_TIMEOUT_MS`; non-zero exit on failure. - Tool adapter and runner: `codexToolAdapter.ts` mounts `browse_cli`, `stagehand_code`, `playwright_code`, `cdp_code`; defaults to tool-owned browsers for `browse_cli`/`stagehand_code` and runner-provided CDP for `playwright_code`/`cdp_code`; writes `browser_run.mjs` and rewrites `AGENT_RUN_TOOL_NAME`; captures evidence via `captureEvidence` and passes it to `codexAdapter.ts`; robust cleanup. - **Bug Fixes** - Final observation is only anchored when a screenshot is present; URL-only artifacts no longer qualify. - Redacts credential fragments (e.g., `signingKey`, `sk-*`) from snippet error messages before crossing the bridge or hitting logs. <sup>Written for commit a710ed6. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/2609?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> Co-authored-by: miguel <miguelg71921@gmail.com>
…ection (#2610) ## Summary STG-2752: external-harness runs now carry per-step observations and a final observation grounded in harness-captured evidence, and unverifiable-criteria counts are reported per arm and can gate the batch. - `ToolStartResult.captureEvidence` (optional hook): each code surface captures current page state (url + screenshot + aria tree) through its own handles — one shared capture per surface, resolved through `session.activePage()` at capture time - `observationRecorder.ts` (new): run-indexed probe buffer; a failed capture leaves a gap instead of shifting later observations onto the wrong step; `EVAL_HARNESS_OBSERVATIONS=none` excludes a run from evidence collection - Probes record after each run-tool execution in `claude_code` and each bridge run in `codex`; the trajectory adapters attach them to code steps only, and refuse attachment when counts mismatch (misattribution is worse than a gap) - `tui run` prints per-arm verifiability and enforces the `EVAL_MAX_UNVERIFIABLE_CRITERIA` gate Verified live: in webvoyager runs the verifier now rejects agent claims that the collected step evidence does not support (e.g. asserted ingredients absent from the extracted list). Stacked follow-ups: #2649 extends the gate to count verifier-failed (ungraded, self-reported) rows per arm and fail gated batches containing any; #2650 extends per-step observation to the MCP tool surfaces via the runner event streams. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Wires verifier-backed evidence capture into `claude_code` and `codex` so runs include per-step URL/screenshot probes and a harness-observed final artifact. Adds per-arm verifiability reporting and an optional gate for STG-2752. - **New Features** - Added `ObservationRecorder` for per-step probes; opt out with `EVAL_HARNESS_OBSERVATIONS=none`, timeout via `EVAL_OBSERVATION_TIMEOUT_MS`. - Probes record after each `run_tool` in `claude_code` and each bridge run in `codex`; adapters attach only to code steps (`LLM_RUN_TOOL_NAME`, `browser_run.mjs`) as `probeEvidence`. Final observation prefers the harness-captured artifact, else the last agent screenshot. - `tui run` prints per-arm verifiability and enforces the `EVAL_MAX_UNVERIFIABLE_CRITERIA` gate. - **Bug Fixes** - Bridge probe callbacks are non-blocking; failed captures leave indexed gaps instead of shifting evidence. - `codex` only attaches observations when recorded bridge runs match filtered steps; `claude_code` captures a terminal artifact before cleanup; final observation requires a screenshot. - Strict integer parsing for `EVAL_MAX_UNVERIFIABLE_CRITERIA`; the gate fails loudly when set but no arms were graded. <sup>Written for commit 88d32fd. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/2610?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
…2611) ## Summary Agent suites (webvoyager, onlineMind2Web, webtailbench, odysseysbench) run exclusively through the external harnesses (claude_code / codex); the v3 agent path is removed from the bench framework. Net −5,028 lines. ## Why now The agent tier's history on this lineage: | Date | Change | Event | |---|---|---| | 2026-05-01 | #2011 Evals v2 | agent bench tasks created | | 2026-07-23 | v4-spike v3 purge | deleted | | 2026-07-27 | #2401 Restore v3 evals | restored against the published stagehand-v3 npm package | #2401 restored the v3 agent tier as a stopgap because v4 had no agent story. The nondeterministic-evals stack under this PR — the LLMExposure contract, the external harnesses, per-step evidence collection — is that story, so the stopgap retires. Suites are now planner-level constructs (virtual registry entries over the dataset builders in `suites/`), not task files. ## What changes - stagehand bench harness is act/extract/observe-only on the Stagehand SDK; both `initV3` branches, the `--api` path, and the v3 context fields are gone - An explicit suite target on the stagehand harness errors with harness guidance; broad targets omit suites; dry-runs surface planner errors in the payload instead of crashing - Deleted as dead once the path is gone: the 47 v3-context agent tasks, `runWithVerifier`, `TrajectoryRecorder` (its external-harness successors — `gradeExternalTrajectory`, `observationRecorder` — live on the stack below), the agent-mode/CUA matrix machinery, and the `--agent-mode`/`--agent-modes` flags - Plus three run fixes found during live benchmarking: extract-schema steering in the stagehand_code prompt, `@browserbasehq/sdk`/`ws` resolved from the evals package (the old resolver pointed at `packages/core`, which does not exist on this lineage), and a CLI stderr filter for the stale-frame CDP log flood ## Scope boundaries - Deterministic evals untouched: zero changes to `defineTask.ts` / `types.ts` / `context.ts` / framework barrel (the #2494 / #2587 stack); a/e/o task-file v4 typing remains that stack's deliverable - ~~The legacy runner (`--legacy`) keeps its own v3 wiring and is scheduled for a separate removal~~ — done: #2649 (stacked on this PR) removes the legacy runner outright, along with GAIA - Zero changes under `packages/server` / `packages/extension` ## Stacked on top - #2649 — merge-readiness fixes: gate counts verifier-failed rows as ungraded and fails gated batches; GAIA removed entirely; legacy runner removed; codex tool-step budget; per-dataset prompt constraints restored (Mind2Web stay-on-site); agent-mode tag hygiene; stagehand_code screenshot Buffer fix - #2650 — playwright_mcp / chrome_devtools_mcp enabled on both external harnesses <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Routes all agent benchmark suites (`webvoyager`, `onlineMind2Web`, `webtailbench`, `odysseysbench`) through external harnesses (`claude_code`, `codex`) and removes the v3 agent path. The `stagehand` harness is now act/extract/observe-only; suites are discovered as virtual entries; and the `stagehand_code` prompt now requires single-word, all-required extract schema keys. - **Bug Fixes** - Filtered Stagehand stale-frame CDP ERROR lines from CLI stderr; other errors still print. - Fixed Browserbase target prep by resolving `@browserbasehq/sdk` and `ws` from `packages/evals` dependencies. - **Migration** - Run suites with `--harness claude_code` or `--harness codex`; the `stagehand` harness no longer runs agent suites and will error on explicit suite targets (dry-run payloads include planner errors). - Remove usage of `--agent-mode`, `--agent-modes`, and the `agentModes` config key. The legacy runner (`--legacy`) keeps its own v3 wiring. <sup>Written for commit 600adf1. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/2611?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
…esses (#2650) ## Summary Stacked on #2649. `--tool playwright_mcp` and `--tool chrome_devtools_mcp` now execute on `--harness claude_code` and `--harness codex` — the first wiring of the MCP surfaces into the agent harnesses (previously core-tier only). **Design**: the generic `agentMount { via: "mcp", mcpServers }` contract variant, produced by the tools and delivered by the adapters — no surface-specific adapter code. The agent spawns its own MCP server instance against the runner-provided CDP browser; the harness keeps its own session on the same browser for evidence capture. - **Tools**: export the mount (via new `buildPlaywrightMcpLaunchSpec` / `buildChromeDevtoolsMcpLaunchSpec` helpers — named for the facade branch to rebase onto) + `captureEvidence`. Mount requires a `providedEndpoint`, so a tool-launched isolated browser can never split agent and observer. - **claude_code**: `mcpServers` passthrough to the SDK, `mcp__<server>` tool allowlisting, per-step observation triggered from the runner's `tool_result` stream keyed by `tool_use` id. - **codex**: `mcp_servers` via SDK config overrides; observation on `mcp_tool_call` completion events; MCP calls count against the #2649 tool-step budget. - **Trajectory adapters**: `observedToolName` matcher generalizes observation attachment to MCP steps; the strict `===` count guard is kept (the facade's `>=` relaxation is deliberately not adopted — it reintroduces positional misattribution; the trailing-capture undercount wants an attempted-run count instead, follow-up). Deliberately out (punted with the facade): `stagehand_playwright_code`, callback batching, the facade's codex-only `prepareCodexPlaywrightMcpAdapter` (superseded by the generic path). ## Verification - typecheck / oxfmt clean, **420/420** unit tests (4 new: surface resolution both harnesses, MCP observation attachment both adapters) - Live smoke (claude_code × playwright_mcp, WebVoyager, LOCAL): agent drove `mcp__playwright__*` tools for 50 steps, per-step url/aria probe evidence attached to MCP steps only, verifier graded a 5-criterion rubric (0 unverifiable) - codex × chrome_devtools_mcp: config injection + server spawn validated on Browserbase (run failed on an unrelated model-pairing error; `mcp_servers` reached Codex and servers started) Known rough edge: probe screenshots through the harness-side `playwright_mcp` session are flaky under the 10s observation timeout (url/aria reliable; ~1/40 screenshots in the smoke). Follow-up: bump timeout for MCP surfaces or capture via raw CDP. <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Enable MCP browser tool surfaces on the `claude_code` and `codex` harnesses. `--tool playwright_mcp` and `--tool chrome_devtools_mcp` now run end-to-end with per-step evidence attached to MCP steps; plus reliability fixes for capture and tab syncing. - **New Features** - Tools export an MCP agent mount (`via: "mcp"`) with `buildPlaywrightMcpLaunchSpec` / `buildChromeDevtoolsMcpLaunchSpec`, plus `captureEvidence`. - Claude Code: passes `mcpServers` to the SDK, allows `mcp__<server>` tools, and attaches observations from the `tool_result` stream (tracks `tool_use` id → name). - Codex: injects `mcp_servers` via SDK config overrides; records observations on `mcp_tool_call` completion; MCP calls count toward the tool-step budget. - Trajectory adapters: add an `observedToolName` matcher so observations attach to MCP steps; strict count guard remains to avoid misattribution. - Startup: MCP surfaces use runner-provided CDP endpoints (local or Browserbase) so agent and harness share the same browser. - **Bug Fixes** - Evidence capture re-points the harness session to the browser’s visible tab via CDP before probing (best-effort fallback if unavailable). - Observation recorder settles in-flight captures before drain; `drainStepObservations` is async on both harnesses to avoid missing last-step evidence. - Codex `captureEvidence` is bounded by `EVAL_CAPTURE_EVIDENCE_TIMEOUT_MS` (default 15s) to prevent stalls. <sup>Written for commit 544b54a. Summary will update on new commits.</sup> <a href="https://cubic.dev/pr/browserbase/stagehand/pull/2650?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
Summary
The remaining merge blockers for the #2591→#2611 stack, implemented per the review conclusions (verifier fallback accepted on empirical evidence; GAIA removal decided; Odysseys rubric item dropped as irrelevant).
verifierErrorset,_successself-reported) now count as ungraded runs on their arm. The per-arm verifiability line reports them, and whenEVAL_MAX_UNVERIFIABLE_CRITERIAis configured, any ungraded run fails the batch. This changes no grading behavior — it converts "the fallback hasn't fired in hundreds of runs" into "if it ever fires, the batch fails loudly instead of publishing self-graded rows."index.eval.tsfan-out, category overrides, legacy-only sets, help text, README).b:gaia→ "Unknown benchmark", instead of a half-present suite pointing at a broken--legacypath.EVAL_CODEX_MAX_STEPS, falling back to the pre-migrationAGENT_EVAL_MAX_STEPS, default 50. Runs get a citable, reproducible action budget.dom/hybrid/cuastripped from external-harness testcases so Braintrust tag filters don't pool them with historical Stagehand agent rows.Uint8Array;Buffer.isBufferconsumers silently dropped screenshots. Now normalized toBuffer.Deliberately not here
startUrl: pending an explicit protocol decision (self-navigation as the documented norm vs. pre-goto for cross-era comparability).>=relaxation of the codex observation guard: kept strict===— the relaxation reintroduces positional misattribution; the underlying trailing-capture undercount needs an attempted-run count in the recorder (follow-up with the facade work).Verification
typecheck clean · 416/416 unit tests (3 GAIA-era tests updated to the new behavior, 1 new gate test) · oxfmt clean
Summary by cubic
Hardens external-harness evals for merge: enforces strict verifier gating, removes GAIA and the legacy runner/flag, adds a Codex step budget, restores dataset prompt guidance, fixes screenshot handling, and bounds setup-failure cleanup timeouts. Also cleans up docs/payloads, fixes a Codex abort-listener leak in long batches, tightens a dry-run test assertion, and removes the
--providerflag (provider now derived from the model id).New Features
stagehandharness that leaves nothing runnable now errors with guidance instead of planning zero cases.Refactors
b:gaianow reports “Unknown benchmark.”b:osworldalso reports “Unknown benchmark.”--legacyflag; deleted legacy files and commands. Dry-run payload drops skippedTasks; preview/help text,ARCHITECTURE.mmd, and README updated.--providerand provider-based model filtering; provider metadata is inferred fromprovider/model. Dropped EVAL_PROVIDER env, config/help surfaces, and related tests.dom,hybrid,cuafrom external-harness testcases to keep Braintrust filters separated from legacy Stagehand runs.stagehand_codescreenshot bytes normalized toBufferto fix dropped screenshots with the v4 SDK.Written for commit 66bc69d. Summary will update on new commits.
Update (second commit): the legacy runner is removed outright.
--legacycould no longer run anything on this branch (a/e/o need the v4 harness context it never builds; the agent modules and suite targets it resolves are gone), so the escape hatch was routing users to a guaranteed failure. Deleted:cli-legacy.ts,index.eval.ts,args.ts,tui/commands/legacy.ts, theevals:oldscript, the--legacyflag,LEGACY_ONLY_BENCHMARKS(b:osworldnow reports "Unknown benchmark"), and the legacy-skip plumbing in the run command, dry-run payload, and preview. Net −1,885 lines. Gates re-run green (typecheck, 416/416, oxfmt).