Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
bddda59
Keep verifier outcomes, uncertainty, and execution failures auditable
miguelg719 Sep 7, 2026
d33f457
fix(evals): share offline verifier policy and preserve ungraded uncer…
miguelg719 Sep 8, 2026
dcbb62b
Merge branch 'evals/consolidation-10-usage-provenance' into evals/con…
miguelg719 Sep 8, 2026
ceeb01f
fix(evals): leave uncertain verifier spans ungraded
miguelg719 Sep 8, 2026
8bea6e1
Merge branch 'evals/consolidation-10-usage-provenance' into evals/con…
miguelg719 Sep 8, 2026
5364fc8
Merge branch 'evals/consolidation-10-usage-provenance' into evals/con…
miguelg719 Sep 8, 2026
3a18643
Merge branch 'evals/consolidation-10-usage-provenance' into evals/con…
miguelg719 Sep 8, 2026
8f6b5b5
fix(evals): retain ungraded verifier failures and trusted evidence
miguelg719 Sep 8, 2026
b025849
Merge branch 'evals/consolidation-10-usage-provenance' into evals/con…
miguelg719 Sep 8, 2026
bd6fe77
Merge branch 'evals/consolidation-10-usage-provenance' into evals/con…
miguelg719 Sep 8, 2026
94080eb
Merge commit '8bdd0bb57190181a435b0b17d29a11ff66c41b72' into HEAD
miguelg719 Sep 10, 2026
a08cec7
Merge commit '08611ac78125e724e3eba933ad3652998e7c2774' into HEAD
miguelg719 Sep 10, 2026
2136ac4
Merge commit 'feffa57127a675b950583c81c008a25dfe372bb6' into HEAD
miguelg719 Sep 10, 2026
739d6db
Merge commit '02cb9a25ac48874093d2129d7335b718be44bad3' into HEAD
miguelg719 Sep 14, 2026
b571c00
Merge commit 'f3a56be7cb822a9823335d81a1848b41979317b3' into HEAD
miguelg719 Sep 14, 2026
15865b2
Merge commit '11c2bd1804dc83987a4f1c640a173731e1821cb9' into HEAD
miguelg719 Sep 14, 2026
5aa2d83
Merge commit 'cdfda080cebf023baa70c2ad14bbd316172ad9c8' into HEAD
miguelg719 Sep 14, 2026
b3faa9a
Merge commit 'becd7bb896ef05090432f60ca94c8a899def3a84' into HEAD
miguelg719 Sep 14, 2026
949c8a3
Merge commit 'f32ba920b3c1c783992be7ac803734d90bcb9119' into HEAD
miguelg719 Sep 14, 2026
59bcebb
Merge commit '5d700206454c05b76a7ed887bb5f7cd1b6ea7f0c' into HEAD
miguelg719 Sep 14, 2026
798b651
Merge commit 'f744d0df40e2bdd2093256a1c04a375706909210' into HEAD
miguelg719 Sep 14, 2026
32391e5
Merge commit 'da395ebf5db7cd81c6bfe2d93f62f8b073115fd7' into HEAD
miguelg719 Sep 15, 2026
e9cf972
Merge commit '3d6a19e9088638785627ee61ea043109c34711f6' into HEAD
miguelg719 Sep 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions packages/evals/docs/verifier-gates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Verifier evidence gates

External harnesses use the existing V3 verifier with the task's precomputed rubric when available. A requested verification that errors or returns a verifier-uncertainty sentinel fails closed: `_success` is false, `verifierError` explains the failure, and `agentReportedSuccess` preserves the original self-report. Such rows are ungraded and must not be presented as verified benchmark outcomes.

For completed grades, the raw judge verdict is retained under `judge` in `scores/result.json`. The top-level result, `task_data.json`, and the run row carry the same adjusted outcome. Failed or uncertain verification instead persists `{ graded: false, verifierError, judge? }`, without top-level outcome or process scores; `judge` is present only if the verifier returned a response. `scores/gates.json` records diagnostics for completed grades when trajectory persistence is enabled.

## Outcome

A judge pass is rejected when the final answer is empty or, if a mounted-tool matcher is available, the trajectory has no browser tool calls. Grounding checks are advisory by default. `EVAL_REQUIRE_GROUNDING=1` additionally rejects an answer whose checked numeric findings all lack matching observations from a known non-search page. Captured step and terminal accessibility trees are included; unknown-page text cannot establish grounding. A terminal match is recorded as `groundedAtFinalObservation`, while untrusted matches can be recorded as `seenOnUnknownPage`. The check is a text heuristic: images, paraphrases and valid snippet sources can escape its matching, so it is not a replacement for rubric verification.

Execution state remains separate. When populated by the runner or adapter, `harnessStatus`, `harnessStopReason` and `terminationReason` describe completion, budget exhaustion, abort, SDK error and browser loss. The verifier does not synthesize missing lifecycle metadata; its absence means unavailable. A supported task completion can still pass after a disconnect; execution error alone does not erase earlier evidence. An unfinished task must fail its rubric.

## Process

`processScoreStrict` recomputes the weighted process score with explicit `evidenceInsufficient` criteria earning zero while retaining their maximum points in the denominator. `processScore` uses this score; `processScoreLenient` preserves the judge's aggregate. Not-applicable criteria are excluded. Without a criterion breakdown, the judge's aggregate is retained and `scoringIncomplete` flags a short result against the rubric.

Blocker wording is recorded as `blockerMentioned` on criterion diagnostics. It never changes points by itself: permitted fallback and stop-boundary explanations can correctly mention a blocker. The rubric and observed evidence determine whether the requirement was satisfied. This replaces the campaign's overbroad blocker substring heuristic.

## Reporting

These fields depend on the producing runner; this verifier layer forwards them but does not make every harness emit them:

- Where supplied, `facade_tool_calls`, `facade_tool_call_failures` and `facade_tool_calls_after_session_lost` distinguish attempted browser work from repeated terminal failures. Missing counters are unknown, not measured zero. A graded pass with an explicit zero browser-call count is shown in the batch summary; with `EVAL_MAX_UNVERIFIABLE_CRITERIA` enabled, it fails the batch gate.
- Separate agent, evidence-capture and verifier wall times are available only when recorded by the producer.
- Usage must be interpreted with the producer's presence marker and cache convention. Legacy runners may supply zero placeholders; without an explicit presence marker, zero does not establish measured usage. Historical Cursor CLI usage remains unreported.
- Costs reported by the harness can be retained. A `cost_source` field, when supplied by a producer, distinguishes reported dollars from a catalog estimate (`computed`). This verifier layer does not compute estimates. Without provenance, cost origin is unavailable; unknown or subscription costs must not be inferred as zero.
- `harnessImplementation` records adapter and SDK versions when supplied. Its absence means unknown implementation; historical labels are preserved.

Use `VERIFIER_PERSIST_TRAJECTORIES=1` for reviewable evidence. HardBench's compatibility gate rejects verifier errors, uncertainty sentinels, missing criteria and self-report fallbacks before accepting a result. Offline transport checks establish integration compatibility; live rubric accuracy still requires the separately recorded live fixtures.
21 changes: 17 additions & 4 deletions packages/evals/framework/harnesses/persistTrajectory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import {
resolveTrajectoryRoot,
writeTrajectoryMetadata,
} from "../trajectoryGroup.js";
import type { EvaluationResult, TaskSpec, Trajectory } from "stagehand-v3";
import type { EvaluationResult, TaskSpec } from "stagehand-v3";
import type { HarnessTrajectory } from "./trajectoryAdapter.js";
import type { UngradedVerifierResult } from "../verifierAdapter.js";

export interface PersistAdapterTrajectoryOptions {
trajectory: Trajectory;
trajectory: HarnessTrajectory;
taskSpec: TaskSpec;
/** EvaluationResult from V3Evaluator.verify(). Written to scores/result.json. */
evaluationResult?: EvaluationResult;
/** Accepted grade or explicit ungraded audit record. Written to scores/result.json. */
evaluationResult?: EvaluationResult | UngradedVerifierResult;
/**
* Output directory root. Final layout lives at
* `<outputRoot>/<group>/<task.id>/<runId>/`. Entrypoints normally generate
Expand Down Expand Up @@ -73,6 +75,16 @@ export async function persistAdapterTrajectory(
runDir: path.basename(directory),
attempt,
status: opts.trajectory.status,
...(opts.trajectory.cost_pricing && { cost_pricing: opts.trajectory.cost_pricing }),
...(opts.trajectory.terminationReason && {
terminationReason: opts.trajectory.terminationReason,
}),
...(opts.trajectory.harnessImplementation && {
harnessImplementation: opts.trajectory.harnessImplementation,
}),
...(opts.trajectory.harnessConfiguration && {
harnessConfiguration: opts.trajectory.harnessConfiguration,
}),
});

if (opts.evaluationResult) {
Expand All @@ -86,6 +98,7 @@ export async function persistAdapterTrajectory(
{
task: opts.trajectory.task,
status: opts.trajectory.status,
...(opts.trajectory.cost_pricing && { cost_pricing: opts.trajectory.cost_pricing }),
finalAnswer: opts.trajectory.finalAnswer ?? null,
result: opts.evaluationResult,
},
Expand Down
20 changes: 20 additions & 0 deletions packages/evals/framework/harnesses/trajectoryAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ import type {
TrajectoryStep,
} from "stagehand-v3";

/**
* Why a run stopped. `status` on the Trajectory only says whether it ended
* cleanly; this says what ended it, so a budget-exhausted run can be told
* apart from a crash offline.
*/
export type TerminationReason =
| "completed"
| "step_budget"
| "browser_session_lost"
| "sdk_error"
| "aborted";

/** A Trajectory as external harnesses persist it. */
export type HarnessTrajectory = Trajectory & {
terminationReason?: TerminationReason;
harnessImplementation?: { name: string; version: number; sdkVersion?: string };
harnessConfiguration?: Record<string, unknown>;
cost_pricing?: { as_of: string; model: string; source: string };
};

/**
* Pure converter from a harness-specific result to a verifier Trajectory.
* Implementations must be deterministic (no I/O, no mutation of input).
Expand Down
Loading
Loading