feat: make the SWE-bench-Pro baseline runnable for the vero optimizer#50
feat: make the SWE-bench-Pro baseline runnable for the vero optimizer#50shehabyasser-scale wants to merge 45 commits into
Conversation
51c152d to
ced19f9
Compare
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) <noreply@anthropic.com>
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 <noreply@anthropic.com>
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.
Across gaia/officeqa/swe-atlas-qna/tau3: 100-run budgets and 4x-pass
case budgets on both agent partitions, submit-mode selection,
baseline_floor off, 16k feedback, parameterized inner environment
(${inner_env:-modal}), and verifier_timeout = 2x timeout_seconds.
swe-atlas-qna and tau3 get explicit case/task-agent timeouts derived
from their datasets' declared agent timeouts (enforced budgets 1800s
and 900s, provisional until empirical wall_seconds data). harness_user
is explicit on gaia/officeqa; tau3 and swe-atlas-qna stay unisolated
pending off-env delivery of task-service credentials. Also fix the
vendor script's stale pre-restructure path in its usage comment.
Root cause of every swe-atlas trial dying at setup: the task images set ENTRYPOINT ["/bin/bash"], Modal prepends it to the sandbox command, so harbor's default keepalive ["sh","-c","sleep infinity"] ran as 'bash sh -c ...' - bash interprets the sh binary as a script and exits 126, killing the sandbox before the first exec. Pass bash's own args via the JSON-decoded keepalive env kwarg instead. Validated end-to-end on Modal (3 dev trials, 379-602s wall). CONFIGURATION.md records the empirical probe timings behind the provisional case timeouts.
scripts/per_trial_tokens.py reads a session's gateway request log and attributes token/latency to Harbor trials: by the gateway's stamped thread_id when present (request_log.attribution builds → full coverage incl. stateful chains), else a legacy fallback that recovers each conversation's root turn (labelable via --tasks-dir) and residualizes unrecoverable follow-ups. Reports gateway-total vs attributed vs agent-reported per evaluation. Stdlib-only; tests cover both paths.
…r at turn cap Chat Completions is the only universally-supported inference surface — the OpenAI Responses API doesn't translate cleanly to non-OpenAI models via litellm (parallel_tool_calls rejected, output_text crashes on a null message part). Rewrite AtlasAgent's loop to stateless chat messages + tool_calls, validated cross-provider (gpt-5.4-mini and fireworks_ai/gpt-oss-120b both run the multi-turn tool loop). Also: at the turn cap, force one final tool-free answer instead of raising, so a budget-exhausted trial scores best-effort rather than losing the case.
Same port as swe-atlas: stateless chat messages + tool_calls, works across providers (validated cross-provider on gpt-5.4-mini and fireworks_ai/gpt-oss-120b). officeqa drops the hosted web_search tool (closed-corpus benchmark, and chat/completions has no hosted-tool equivalent) and moves read_image feedback to chat image_url content. tau3 keeps its host-side MCP loop; the stateless history also fixes the previous_response_id reset that dropped context after plain-text turns, and the MCP session id is now charset-validated before shell interpolation (greptile injection finding).
Mirrors the swe-atlas fix: at MAX_TURNS force one tool-free completion for the best answer and submit it, so a budget-exhausted case scores best-effort rather than being lost with no answer recorded.
A fifth harness-engineering benchmark: optimize a retrieval + reasoning agent over BrowseComp-Plus's fixed corpus and canonical BM25 index, graded by a semantic answer judge (gpt-4.1). Task packages are generated from the encrypted upstream dataset by scripts/build_tasks.py and are gitignored (they contain decrypted questions/answers); the upstream repo is pinned as a submodule and the 2.2 GB index is pulled at image-build time. Wired consistently with the normalized suite: 33/66/66 stratified split, 4-pass budgets, submit-mode selection, harness_user null + task_services_use_upstream for the in-container judge. Baseline agent uses Chat Completions (works across providers) and forces a best-effort answer at the turn cap. The task image installs a full JDK with JAVA_HOME resolved from it, so pyserini's Lucene BM25 searcher works (a headless JRE with JAVA_HOME unset left jnius unable to locate the JVM).
…line Full held-out (test) pass of the seed harness, 3 independent rounds, under the new targets (deepseek-v4-flash; gpt-oss-120b on swe-atlas): swe-atlas 0.097 ±0.011 (agg_score 0.632) [gpt-oss-120b] tau3 0.611 ±0.021 [deepseek-v4-flash] officeqa 0.360 ±0.042 [deepseek-v4-flash] browsecomp 0.449 ±0.007 [deepseek-v4-flash] Each pinned into its target's baseline_reward with score_baseline: false, so finalization uses the number instead of re-scoring the seed every run. The three deepseek benchmarks logged zero exceptions over 945 trials (max_retries absorbed the shared-quota 429s); swe-atlas lost 5/150 to gpt-oss 128k overflow. CONFIGURATION.md documents the numbers, method, and the swe-atlas binary-vs- agg_score note. gaia deferred. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
It was the suite's only Family B task and the only one that bypassed the compiler: a hand-written task directory with no build.yaml, so it got none of the build-time validation the other five benchmarks get. Its optimizer was also unmetered -- no gateway container, raw upstream credentials in main, no model allow-list -- which is a fair-play hole in a benchmark whose whole point is controlled measurement. Its sidecar factory had additionally gone stale against SidecarEvaluationPolicy and would have died at startup. The nested-backend refactor now supports `evaluation_backend: command`, so a replacement Family B task can be built through the compiler and get the gateway for free. examples/harbor-circle-packing carries a worked version of exactly that shape, verified end to end. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
These tests moved here from pr2-add-vero, where they could only ever skip. They had been failing for a while against a pinned literal -- evaluation allowed_models == ["gpt-5.4-mini-2026-03-17"] -- that stopped matching when the benchmarks switched to fireworks-served targets. Rewrite the assertions so they cannot drift that way again: the evaluation scope must allow exactly [config.model], derived rather than pinned. That is the real invariant, and it now matches the build-time validator that rejects a model outside its scope's allow-list. Also drop the skip guard, so a missing harness-engineering-bench fails rather than passing vacuously, and extend coverage from three benchmarks to all five. 415 passed, 5 skipped -- the three long-standing failures are gone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ced19f9 to
20dd166
Compare
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) <noreply@anthropic.com>
The agents strip only the `openai/` prefix before calling the gateway
(`removeprefix("openai/")`), and the gateway matches the allow-list exactly
(`model not in scope.allowed_models` -> 403 model_denied). So `model:
openai/gpt-4o` puts `gpt-4o` on the wire, and an allow-list carrying the
prefixed spelling never matches. Listing both spellings papered over that
and then fails the config invariant that the evaluation scope allow exactly
the target model.
Drop the prefix on both sides, and template the producer list the way every
other benchmark does so `--model` / `--param optimizer_model` keeps working
without a config edit.
This config still cannot be swept by tests/test_v05_benchmark_configs.py:
its partitions are deliberately empty pending real task ids, so it fails to
load. It should join BENCHMARKS there once the partitions and the task
source digest are pinned.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A model that is configured but not deployed upstream is invisible until the run is over. The gateway forwards the request, the upstream 404s, the agent makes no progress, and every case is scored 0.0 and labelled `task_failure` — a run that looks honest and says the candidate failed. That is how swe-atlas-qna produced 469 zero-score cases across two runs (#51): `gpt-5.4-mini-2026-03-17` is not provisioned on the configured Azure resource, so 322/322 evaluation-scope and 79/79 finalization-scope requests returned 404 DeploymentNotFound while the producer scope ran clean. `vero harbor run` now sends one 16-token request per distinct allow-listed model before compiling the task, and aborts if any comes back 404. Only a definitive 404 is fatal. A timeout, a 429 or a 503 is inconclusive and is reported without blocking, so a transient upstream blip cannot stop a run that would have succeeded. Names are probed with the provider prefix stripped, which is the form the agents actually send. Verified against the live endpoint: gaia (which points at the undeployed model) now exits 1 in about two seconds with the DeploymentNotFound body quoted, instead of burning ~30 minutes and ~$2; a gpt-5.3-codex producer with a gpt-4o evaluation scope passes. Refs #51. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#53 stopped a dead sandbox being scored as an informative zero. The same masking survives one layer up, for a cause that is even easier to fix. In the 2026-07-25 swe-atlas-qna run, 145 of 469 cases ended on: NotFoundError: Error code: 404 - {'error': {'type': 'invalid_request_error', 'code': 'DeploymentNotFound', 'message': 'The API deployment for this resource does not exist. ...'}} The configured eval model is not provisioned on the Azure resource. The agent's every call 404s, it writes no answer, and `classify_case` — finding nothing in the signal it recognises — returns TASK_FAILURE, whose policy is `is_informative_sample=True`. So each case was recorded as a genuine score of 0.0 and the harness reported that the candidate failed the task. Add UPSTREAM_MODEL_UNAVAILABLE: never an informative sample, never retried, terminating (every remaining case fails identically, so there is nothing left to measure), and counted toward invalidity so the aggregate still comes out invalid if the terminating path is ever bypassed. It is ranked above TRANSIENT_INFRA, so a case that saw both a dead sandbox and a missing deployment reports the deterministic, operator-fixable cause. The pattern deliberately matches the provider error codes and the exact Azure sentence rather than a bare "does not exist": 102 cases in that same run failed with `FetchSpec failed: loading container: file does not exist`, which is genuine infrastructure and must stay TRANSIENT_INFRA. There is a test pinning both sides. Refs #51. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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) <noreply@anthropic.com>
The probe only spoke the Responses API and treated any 404 as proof the deployment was absent. A route-level 404 (the upstream does not implement that path) and a model-level 404 (the deployment does not exist) share a status code and mean opposite things, so the preflight would hard-block a run against a Chat-Completions-only upstream that would have succeeded. That is now a live risk in this repo: officeqa, tau3, swe-atlas-qna and browsecomp-plus were ported to Chat Completions, leaving gaia as the only agent still on Responses. Try both routes, and only call a model missing when the 404 body names the model (`DeploymentNotFound`, `model_not_found`, or "model ... does not exist") rather than the route. If every route 404s on the route itself, the result is inconclusive and the run proceeds. Same fix for the model name: the provider prefix routes on a proxy and is meaningless to a single-provider endpoint, so probe the configured spelling first and fall back to the bare one before reporting anything missing. Previously the prefix was stripped unconditionally, which is wrong for `fireworks_ai/...` names. Verified against the live Azure endpoint: `gpt-4o` 200 on both routes; `openai/gpt-5.3-codex` 404s prefixed and passes preflight via the bare fallback; `fireworks_ai/gpt-oss-120b` is still correctly blocked; and a model 404 body is distinguished from a bare route 404. Refs #51. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ccc7d07 to
ec708e9
Compare
|
Rebased onto the current Added one commit on top, fixing a real defect the new invariants exposed. The config had: model: openai/gpt-4o
producer: allowed_models: ["gpt-5.3-codex", "openai/gpt-5.3-codex"]
evaluation: allowed_models: ["gpt-4o", "openai/gpt-4o"]The dual-spelling lists were a workaround for a mismatch that should not exist. Agents strip only Two things a reviewer should know:
Full suite matches |
20dd166 to
014eb72
Compare
fix: a missing upstream deployment is not a task failure
5397fe4 to
ec0b444
Compare
feat: preflight configured models before launching an optimizer trial
fix: classify Modal sandbox / tests-dir loss as transient_infra
9a963a3 to
5723247
Compare
The scaffold could not resolve a task: `task_source` was the literal `scale-ai/swe-bench-pro@sha256:REPLACE_WITH_REAL_DIGEST`, the three partition files were empty, and the split script refused to run behind a `TOTAL_TASKS = 0` stub guard. SWE-bench-Pro is not a package dataset. It ships as `swebenchpro` in Harbor's default registry (731 instances over 11 projects), whose tasks resolve to git-backed ids under laude-institute/harbor-datasets at commit c8e8f3fac7097accaacf261d74c3d6f441de45b1, so the pin is a bare `name@version` rather than a content digest. That distinction drives the rest of the change: - `_read_tasks` reads the stratification key from `tests/config.json` (`repo`), not `[metadata].repository`: these task.toml files carry no `[task].name`, and Harbor derives the canonical name from the task directory, which is what `-i` matches. - `_fetch_registry_refs` goes through `RegistryClientFactory` instead of `PackageDatasetClient`, recording `<git_commit>:<path>` as the per-task ref, which identifies content the way a digest would. - `expose_case_resources` is false on the development partition. VeRO materializes case resources through `PackageDatasetClient`, which only accepts `<org>/<name>` refs, so a registry dataset cannot be exposed that way. - 731 splits 20/40/40 as 146.2/292.4/292.4; the leftover goes by largest remainder and the .4/.4 tie breaks toward test, matching how officeqa (246 -> 49/98/99) and swe-atlas-qna (124 -> 25/49/50) resolved it. Hence 146/292/293. - `task_agent_timeout_seconds` drops 3600 -> 3000 to mirror the task package's own `[agent] timeout_sec`, making the runner's --agent-timeout-multiplier exactly 1800/3000 = 0.6. - `requires-python` floors at 3.12 because harbor 0.20.0 requires it; ">=3.11" left the package's own `uv run pytest` unresolvable. The <3.14 cap stays (litellm/pyo3 fails to build on 3.14). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ward
Each of these silently biases the measurement rather than failing loudly,
so the optimizer would have hill-climbed against a broken baseline.
1. REPO_DIR was `/app/repo`. The swebenchpro task images set `WORKDIR
/app` and reset the checkout in place there, and the task instruction
says so verbatim ("I've uploaded a code repository in the directory
/app"). Every shell command ran in a directory that does not exist.
2. `reasoning: {effort: high}` was sent unconditionally. Non-reasoning
models reject it with a hard 400 on the very first turn, so a gpt-4o
run could not complete a single trial. Gated on capability, matching
the sibling agents.
3. `_write_file` joined a model-supplied path onto `logs_dir`. Models
routinely answer with the absolute path they just saw in shell output,
and `Path(logs_dir) / "staged" / "/app/x.py"` discards the left side
entirely, so the write landed on the HOST root and killed the trial
with `OSError [Errno 30] Read-only file system: '/app'`. Seen on 2 of
the first 12 held-out trials. Paths are now normalized repo-relative
and traversal is refused.
4. Exhausting the turn budget raised RuntimeError. Reward comes from the
task's hidden suite run against whatever the agent left in the
repository, so raising discarded real edits, errored the trial, made
harbor re-run the whole thing (9 of the first 49 held-out trials) and
scored a hard 0 for a fix that may well have been correct. It now
records the exhaustion in metadata and lets the verifier grade, which
is exactly what the "model stopped calling tools" branch already did.
5. Harbor decodes exec output as strict UTF-8. These are real
repositories, so a model that cats or greps a binary raised
UnicodeDecodeError out of `exec` and killed the trial: 5 of the first
49 held-out trials. A non-decodable stream is now a tool error the
model can react to, with a hint to re-run through `strings`/`file`.
Verified end to end: a single-case smoke on
instance_ansible__ansible-0ea40e with a gpt-4o agent completed with
reward 1.0, all 16 required tests PASSED, 0 errored trials.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The config-invariant suite enumerates benchmarks explicitly, so swe-bench-pro was silently unchecked. Now that its task_source resolves, it can join the other five. All three parametrized cases pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| ) | ||
| if result.return_code != 0: | ||
| # Retry with a looser fuzz factor before giving up. | ||
| result = await environment.exec( | ||
| f"git apply --whitespace=nowarn -C1 {remote_path}", | ||
| cwd=REPO_DIR, | ||
| timeout_sec=120, | ||
| ) | ||
| return { | ||
| "applied": result.return_code == 0, | ||
| "return_code": result.return_code, | ||
| "stderr": self._truncate(result.stderr or ""), | ||
| } |
There was a problem hiding this comment.
Original diagnostic discarded on C1 retry failure
When both git apply attempts fail the function returns the stderr from the C1 retry only. The original attempt usually gives a more informative hunk-mismatch message (exact offsets, context lines), while the -C1 output is often just "patch failed". A model trying to fix the patch only sees the less precise C1 error, making self-correction harder. Preserving the first attempt's stderr (e.g. under a separate key like "original_stderr") would give the model the full picture.
Prompt To Fix With AI
This is a comment left during a code review.
Path: harness-engineering-bench/swe-bench-pro/baseline/target/src/swebench_pro_agent/agent.py
Line: 415-427
Comment:
**Original diagnostic discarded on C1 retry failure**
When both `git apply` attempts fail the function returns the `stderr` from the C1 retry only. The original attempt usually gives a more informative hunk-mismatch message (exact offsets, context lines), while the `-C1` output is often just "patch failed". A model trying to fix the patch only sees the less precise C1 error, making self-correction harder. Preserving the first attempt's `stderr` (e.g. under a separate key like `"original_stderr"`) would give the model the full picture.
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!
| from types import SimpleNamespace | ||
|
|
||
| import pytest | ||
|
|
||
| from swebench_pro_agent import SweBenchProAgent | ||
|
|
||
|
|
||
| class FakeEnvironment: | ||
| def __init__(self): | ||
| self.commands: list[str] = [] |
There was a problem hiding this comment.
No tests for
_repo_relative path-traversal guard
_repo_relative is the sole barrier that prevents the model from writing files outside /app (defect #3 in the PR description). It handles absolute paths, .. components, and traversal via /app/../…. The existing test suite exercises the happy path (submit, retry) but does not test any of these normalisation or rejection cases. A targeted parametrised test would be cheap to add and protects against regressions if the VeRO optimizer rewrites the tool dispatch loop.
Prompt To Fix With AI
This is a comment left during a code review.
Path: harness-engineering-bench/swe-bench-pro/baseline/target/tests/test_agent.py
Line: 1-10
Comment:
**No tests for `_repo_relative` path-traversal guard**
`_repo_relative` is the sole barrier that prevents the model from writing files outside `/app` (defect #3 in the PR description). It handles absolute paths, `..` components, and traversal via `/app/../…`. The existing test suite exercises the happy path (submit, retry) but does not test any of these normalisation or rejection cases. A targeted parametrised test would be cheap to add and protects against regressions if the VeRO optimizer rewrites the tool dispatch loop.
How can I resolve this? If you propose a fix, please make it concise.
Adds a SWE-bench-Pro baseline under
harness-engineering-bench/swe-bench-pro/, mirroring the gaia baseline layout, so the vero optimizer can hill-climb a patch-style SWE agent.This is no longer a stub. The two blockers called out in the original draft (an unpinned
task_sourceand empty partitions) are resolved, and the seed agent has been fixed to the point where it actually completes a trial.Verification
A single-case smoke run against the real dataset,
instance_ansible__ansible-0ea40ewith a gpt-4o agent on Modal:pytest tests/test_v05_benchmark_configs.py -k swe-bench-propasses 3/3. The suite has 6 pre-existing failures onofficeqaandbrowsecomp-plus(registry task_source must include an explicit version) that are present on this branch's base with or without this PR; they are fixed by newer commits onpr3-harness-benchthat this branch has not absorbed yet.Pinning the task source
SWE-bench-Pro is not a package dataset. It ships as
swebenchproin Harbor's default registry (731 instances over 11 projects), so the pin is a barename@version, not an<org>/<name>@sha256:<digest>:Its tasks resolve to git-backed ids under
laude-institute/harbor-datasetsat commitc8e8f3fac7097accaacf261d74c3d6f441de45b1. Grading is fully offline (the task's ownrun_script.sh+parser.pywritereward.txt), so no judge model and no verifier credentials are needed.Consequences that shaped the config:
expose_case_resources: falseon the development partition. VeRO materializes case resources throughPackageDatasetClient, which only accepts<org>/<name>refs, so a registry dataset cannot be exposed that way.scripts/partition_swe_bench_pro.pynow reads the stratification key (repo) from each task'stests/config.jsonrather than[metadata].repository, because thesetask.tomlfiles carry no[task].nameand Harbor derives the canonical name from the task directory.task_agent_timeout_seconds3600 to 3000, mirroring the task package's own[agent] timeout_sec, which makes the runner's--agent-timeout-multiplierexactly1800/3000 = 0.6.Partitions
Regenerated and stratified by repo: 146 / 292 / 293 (development / validation / test), replacing three empty files and a
TOTAL_TASKS = 0stub guard. 731 splits 20/40/40 as 146.2/292.4/292.4; the leftover goes by largest remainder and the .4/.4 tie breaks toward test, matching how officeqa (246 to 49/98/99) and swe-atlas-qna (124 to 25/49/50) resolved the same tie.Five seed-agent defects
Each of these silently biases the measurement rather than failing loudly, so the optimizer would have hill-climbed against a broken baseline.
REPO_DIRwas/app/repoWORKDIR /appand reset the checkout in place there. Every shell command ran in a directory that does not exist.reasoning.effortsent unconditionally_write_filePath(logs_dir) / "staged" / "/app/x.py"discards the left side, so the write landed on the host root and killed the trial withOSError [Errno 30] Read-only file system: '/app'. Seen on 2 of the first 12 held-out trials. Paths are normalized repo-relative; traversal is refused.raise RuntimeErroron turn-budget exhaustionUnicodeDecodeErrorNote on the base
This branch is behind
pr3-harness-benchand GitHub currently reports it as conflicting. That predates this PR and is not addressed here; the branch needs a merge from its base before it can land.How to run
--environment modalneeds a Modal-reachable model endpoint (e.g. the Azure…openai.azure.com/openai/v1endpoint), not a VPN-internal one.🤖 Generated with Claude Code
Greptile Summary
This PR scaffolds a fully functional SWE-bench-Pro baseline under
harness-engineering-bench/swe-bench-pro/, fixes five agent defects that silently biased measurements in the held-out run, and introduces a shared error taxonomy module (error_taxonomy.py) that gives all pipeline layers a single vocabulary for classifying failures.REPO_DIR, unconditionalreasoning.effortcrashing gpt-4o, absolute-path staging landing on the host root,raise RuntimeErroron turn-budget exhaustion discarding edits, and unhandledUnicodeDecodeErroron binary output.task_source: swebenchpro@1.0correctly pins the registry dataset;expose_case_resources: falsejustified byPackageDatasetClientlimitation.error_taxonomy.pyconsolidates error classification withUPSTREAM_MODEL_UNAVAILABLEspecifically added to prevent misclassifying Azure 404s as informative task failures;harbor/cli.pyadds pre-flight model probing and a_redact_trace_textpath for session export.Confidence Score: 4/5
Safe to merge with two minor quality issues that do not affect correctness or reward integrity.
The agent's path-traversal guard and error taxonomy precedence table are both sound. The two findings are: full response.output_text written verbatim to the trace on every turn, and when both git apply passes fail the model only sees the C1 retry error. Neither breaks the reward pipeline or introduces data loss.
Files Needing Attention: swebench_pro_agent/agent.py for trace logging volume and apply-patch error-message retention; test_agent.py would benefit from parametrised tests for _repo_relative boundary conditions.
Important Files Changed
Sequence Diagram
sequenceDiagram participant VeRO as VeRO Optimizer participant CLI as harbor CLI participant GW as Inference Gateway participant Agent as SweBenchProAgent participant Env as Harbor Environment (Modal) participant Verifier as Task Verifier VeRO->>CLI: harbor run --config build.yaml CLI->>CLI: _preflight_models() CLI->>GW: POST /responses (1 token probe) GW-->>CLI: 200 OK CLI->>Env: uvx harbor run compiled task loop Each turn (max 50) Agent->>GW: responses.create(model, tools, input) GW->>GW: enforce producer scope budget GW-->>Agent: response (function_calls) alt tool call Agent->>Env: "environment.exec(command, cwd=/app)" Env-->>Agent: ExecResult Agent->>Agent: _trace(turn, tool, result) else submit Agent->>Agent: record metadata, break end end Agent->>Verifier: repo state in /app Verifier->>Verifier: run hidden test suite Verifier-->>VeRO: reward.txt (0.0-1.0)Prompt To Fix All With AI
Reviews (1): Last reviewed commit: "test: cover swe-bench-pro in the benchma..." | Re-trigger Greptile
Context used: