fix: bundle harness eval flat-zero fixes (taxonomy + reasoning.effort + tau3 retries)#56
Conversation
Bring the benchmark harness with each benchmark as a top-level sibling of gaia/ (ale-bench, officeqa, swe-atlas-qna, tau3), flattening the former candidates/ grouping.
The floor gates a ship on a validation comparison while gaia's reward is on the test partition (different distributions), so keep it opt-in / off. Now that the harbor default is false this is explicit-for-clarity.
Now that the sidecar image pre-warms the harness uv cache, the inner eval runs as the unprivileged harness user again, so the candidate harness cannot read the held-out records, budgets, or admin token.
Move each benchmark to harbor 0.20.0 in lockstep so the eval resolves: build.yaml harbor_requirement (the evaluator's --with harbor[modal]) and target/pyproject.toml (the candidate's own harbor dep) must match, else `uv run --project <target> --with harbor[modal]==0.20.0` is unsatisfiable. uv.lock regenerated with `uv lock` (not hand-edited). Covers gaia, officeqa, swe-atlas-qna, tau3. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Follow-up to the pr2 rename: instructions, READMEs, and the ale-bench reference solution now teach `evals run/status/result/submit` and the .evals/tasks + .evals/results paths; baseline gitignores cover .evals/. Compiled trees are build outputs (not committed) and pick this up on rebuild. Co-Authored-By: Claude Fable 5 <[email protected]>
All four vero-compiled benchmarks pass --ek app_name=harness-engineering-bench so their Modal sandboxes are grouped under one app instead of __harbor__. Docker inner environments ignore the kwarg.
The task's verifier runs inside the Modal task container and templates EVAL_BASE_URL from OPENAI_API_BASE, unreachable-from-Modal gateway URLs aside. Enable task_services_use_upstream so the judge gets the real upstream on OPENAI_*, and point the baseline agent at the metered gateway via VERO_AGENT_INFERENCE_* (falling back to OPENAI_* locally).
The Modal app-name commit added a second extra_harbor_args key; YAML last-key-wins silently dropped --no-force-build, which would have force-built the guard Dockerfile instead of pulling the prebuilt corpus image.
Killing the outer harbor process leaves the compose topology and any in-flight Modal sandboxes running (each layer's cleanup lives in the layer above). Cap sandbox idle lifetime at 1h via --ek, and add scripts/cleanup_orphans.sh to tear down task__* containers and terminate sandboxes in the dedicated Modal app.
WIP scaffold: a working agent + build/config skeleton for a SWE-bench-Pro optimization target, mirroring the gaia baseline layout. Two things are stubbed and must be completed before it runs: (1) the task_source digest in baseline/build.yaml is a clearly-marked placeholder that must be pinned to the real SWE-bench-Pro Harbor task package, and (2) the partitions/ files are empty placeholders that must be regenerated from the real task list via scripts/partition_swe_bench_pro.py. The agent wraps responses.create in a retry-with-backoff helper from the start (the unguarded call is what scored the gaia baseline 0.0). See harness-engineering-bench/swe-bench-pro/README.md. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
The harbor backend's error taxonomy records any unrecognized case failure as TASK_FAILURE: an informative, scoreable sample at the failure value with status SUCCESS. That is right for a candidate that crashes on its own, but Modal sandbox lifecycle failures and a missing held-out tests fixture are infrastructure the candidate did not cause. Seen on a swe-atlas-qna run (2026-07-24): all 396 cases returned status=success, error_category=task_failure, score=0.0. Terminal exceptions were AddTestsDirError x144, Modal sandbox NotFound x125, RuntimeError x67, BadRequestError x60. Classified as task failures, the aggregate reported error_rate 0.0 and objective feasible at 0.0, so a fully broken environment looked like a real, shippable zero and the optimizer ran with no gradient (baseline and every candidate 0.0). Add the harness/Modal environment-loss signals (sandbox lifecycle, AddTestsDirError / "failed to add tests directory", container fetch failures, StreamTerminatedError) to the TRANSIENT_INFRA patterns. Those cases are now excluded from the aggregate and counted toward invalidity, so a collapsed environment surfaces as an invalid run instead of a silent zero. A candidate's own bug (ValueError, KeyError, no answer) is still a task failure, unchanged. Covered by two new tests; existing behavior asserted unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Each harness-engineering-bench target agent builds its Responses API request
with a hard-coded "reasoning": {"effort": ...} on every call, regardless of the
configured model. Reasoning models (gpt-5.x, o-series, *-codex) accept it, but
gpt-4o and other non-reasoning models reject the whole request with HTTP 400:
"Unsupported parameter: 'reasoning.effort' is not supported with this model".
On a swe-atlas-qna run pointed at a gpt-4o agent model this produced a wall of
400s (60 cases died with BadRequestError). The gaia and tau3 configs point their
agent model at gpt-4o in the same setup, so they share the latent bug.
Gate reasoning.effort on the model family: send it only when the resolved model
is a reasoning model (gpt-5.x / o1 / o3 / o4 / *-codex), otherwise omit it. Each
agent keeps its own effort level (high for atlas and swe-bench-pro, medium for
gaia, officeqa and tau3). No behavior change for reasoning models; gpt-4o stops
400ing. Applied uniformly to all five bench agents.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
…l drops A tau3 optimizer run (2026-07-24) died about 25 minutes in when the Modal command-router gRPC stream dropped mid-optimization (grpclib StreamTerminatedError: Connection lost). With max_retries: 1 the whole trial errored and nothing was scored, even though the drop was transient infrastructure and the run had already committed candidates. Raise max_retries from 1 to 3 so a transient stream drop retries the trial instead of failing the run. This matches infrastructure_max_attempts: 3 already set for per-case infra. A deeper fix (running the eval under the Modal VM runtime to remove the single host-networking gRPC stream SPOF) is noted for follow-up but not applied here, since it needs validation against harbor 0.20.0. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
| r"sandbox|streamterminated|" | ||
| r"failed.?to.?add.?tests.?directory|addtestsdirerror|" | ||
| r"loading.?container|fetchspec", | ||
| re.IGNORECASE, | ||
| ), | ||
| ErrorCategory.TRANSIENT_INFRA, | ||
| ), |
There was a problem hiding this comment.
Bare
sandbox term is over-broad in a global taxonomy
sandbox alone will match any exception message or type name that contains the word across all harnesses, not just Modal-specific ones. If a task in gaia or officeqa involves agent code that raises an error from a library with "sandbox" in its name or message (e.g., a Python security sandbox, a custom execution environment, any tool named *Sandbox*), the case would silently be reclassified from TASK_FAILURE to TRANSIENT_INFRA — excluded from the aggregate and counted toward invalidity instead of being scored. The other terms in this entry (streamterminated, addtestsdirerror, loading.?container, fetchspec) are Modal-specific enough to be safe. Consider anchoring the bare sandbox match more tightly, e.g. modal.*sandbox|sandbox.*unavailable|sandbox.*not.?found, to reduce false-positive risk for harnesses that don't use Modal sandboxes.
Prompt To Fix With AI
This is a comment left during a code review.
Path: vero/src/vero/evaluation/error_taxonomy.py
Line: 170-176
Comment:
**Bare `sandbox` term is over-broad in a global taxonomy**
`sandbox` alone will match any exception message or type name that contains the word across all harnesses, not just Modal-specific ones. If a task in gaia or officeqa involves agent code that raises an error from a library with "sandbox" in its name or message (e.g., a Python security sandbox, a custom execution environment, any tool named `*Sandbox*`), the case would silently be reclassified from `TASK_FAILURE` to `TRANSIENT_INFRA` — excluded from the aggregate and counted toward invalidity instead of being scored. The other terms in this entry (`streamterminated`, `addtestsdirerror`, `loading.?container`, `fetchspec`) are Modal-specific enough to be safe. Consider anchoring the bare `sandbox` match more tightly, e.g. `modal.*sandbox|sandbox.*unavailable|sandbox.*not.?found`, to reduce false-positive risk for harnesses that don't use Modal sandboxes.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
|
This bundle is now stale — superseded by the PR set below. Recommend closing it once the individual PRs are reviewed. It carries #53 + #54 + the original #55, and that third one has since been proven wrong ( Current state, all based on
The two things this bundle was built without knowing:
Neither was visible from a diff, and both were cheap to find once the exported |
ccc7d07 to
ec708e9
Compare
|
Closing as superseded. This was a rollup of #53 + #54 + a tau3 max_retries bump. #53 is restacked and open on its own; #54 is restacked and narrowed to the two agents that still lack a reasoning-effort gate; the max_retries bump was the wrong layer and was reverted out of #55. Nothing here is left unrepresented. |
What
A single branch stacking the three harness eval fixes so both benchmarks can be re-run with all of them applied at once:
transient_infra(unmask the flat-zero)reasoning.effortto models that support it (kill the gpt-4o 400s)max_retries1 -> 3 (survive transient Modal stream drops)Commits are cherry-picked from those PRs (disjoint files, no conflicts), based on
feat/swe-bench-pro-baseline-scaffold.Purpose
One branch to re-run tau3 and swe-atlas-qna end to end with the full fix set. The individual PRs (#53, #54, #55) remain open for granular review.
Caveats for the rerun
0.0, until swe-atlas-qna: eval cases fail on Modal sandbox / tests-dir provisioning (flat-zero) #51 is resolved.gpt-5.4-mini-2026-03-17. If the run targetsgpt-4o, fix: only send reasoning.effort to models that support it #54 is what keeps it from 400ing.🤖 Generated with Claude Code
Greptile Summary
This PR stacks three harness eval fixes from PRs #53, #54, and #55 to enable a clean combined re-run of tau3 and swe-atlas-qna. The individual changes are well-scoped and address real problems (a flat-zero masking bug, HTTP 400s from unconditional
reasoning.effort, and transient Modal stream drops)._SIGNAL_PATTERNSentry to classify Modal sandbox/container/tests-dir failures asTRANSIENT_INFRA, with clear tests covering the known failure messages.reasoning.effortfield from all five agent request builders and gates it on model-name prefix detection, preventing HTTP 400s from non-reasoning models likegpt-4o.max_retriesfrom 1 to 3 intau3/baseline/build.yamlto survive transient Modal stream drops.Confidence Score: 4/5
Safe to merge for the re-run; the three fixes are independently correct and the taxonomy change ships with good test coverage.
The taxonomy addition resolves the flat-zero masking problem with clear tests, the reasoning guard correctly prevents HTTP 400s on non-reasoning models, and the retry bump is a straightforward config change. Two minor concerns exist: the bare
sandboxkeyword in the new regex is the only term in the entry not anchored to Modal-specific context, risking occasional misclassification of task failures in non-Modal harnesses; and the model-detection block is copied verbatim into five agent files, making future model-list updates error-prone. Neither concern blocks the intended re-run.Files Needing Attention: vero/src/vero/evaluation/error_taxonomy.py — review the
sandboxkeyword breadth before this taxonomy is used with harnesses that don't run in Modal.Important Files Changed
sandboxkeyword is the broadest term and could match non-infrastructure errors in other harnesses, but the risk is low in practice.reasoning.effortand adds a model-name prefix guard. Same pattern duplicated across all five agent files; logic is correct for the listed prefixes.effort: high(versusmediumin the others); correct per the original value for this agent.effort: high; no additional issues.max_retriesraised from 1 to 3; straightforward configuration change to survive transient Modal stream drops.Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Agent receives model name] --> B{Reasoning-capable model?\ngpt-5 / o1 / o3 / o4 / codex} B -- Yes --> C[Add reasoning.effort to request] B -- No --> D[Omit reasoning.effort\ne.g. gpt-4o avoids HTTP 400] C --> E[client.responses.create] D --> E F[Exception signal from harness run] --> G[classify_signal] G --> H{Budget pattern?} H -- Yes --> I[INFERENCE_BUDGET_EXHAUSTED\nTerminating] H -- No --> J{Auth pattern?} J -- Yes --> K[AUTH_FAILURE\nTerminating] J -- No --> L{Transient pattern?\nrate-limit OR sandbox/streamterminated\naddtestsdirerror/fetchspec added PR53} L -- Yes --> M[TRANSIENT_INFRA\nRetryable - excluded from aggregate] L -- No --> N[TASK_FAILURE\nInformative sample - scored at 0]Prompt To Fix All With AI
Reviews (1): Last reviewed commit: "fix: raise tau3 optimizer trial max_retr..." | Re-trigger Greptile