LodestarSWE

API Endpoint
Leaderboard
Loading leaderboard...
README

env-lodestar-harbor

938 execution-validated, real-world Issue -> PR SWE tasks in Harbor format, for an
OpenReward harbor environment (isHarbor, subdirectory = tasks).

Produced by Lodestar (~/lodestar, quality-curation layer for SWE RL envs): mined GitHub
issue->PR pairs -> per-repo environment build (cached image) -> gold-patch differential
(test_patch only = before, test_patch + gold = after) -> FAIL_TO_PASS / PASS_TO_PASS.
Grading reuses RepoLaunchGym's verifier (grade.py / _gradelib.py, verbatim).

Contents

Tasks938: the 1,001-task harbor_gold set minus 51 that failed the oracle sweep; the 20 Ruby/Java re-validated with real parsers, 8 Ruby kept
Repos281
Languagespython 467, go 342, typescript 85, rust 16, javascript 14, ruby 8, mdx (python repo) 6
Task classbug_fix 793, feature_addition 141, other 4
FAIL_TO_PASS65,926 total; median 4 per task, mean 70.3, max 4,592
PASS_TO_PASS121,527 total; median 13 per task, mean 129.6, max 10,390
Empty PASS_TO_PASS307 tasks (33%): python 122, go 119, ts 56, js 6, rust 4
Lodestar qualitylodestar_q in task.toml; Q>=0.8: 115 tasks, Q>=0.7: 328
Splitstrain 172, pool 766 (see Measured solvability)

train holds the tasks with measured training signal for rl-r3-step170: step170 fails them at
least once and a model solves them at least once. pool holds the rest. Splits are set from
data/solvability.csv by tools/set_split.py. Re-run it after regenerating tasks/, because
harborize_validated.py writes split = "train" for every task.

Task layout (tasks/<instance_id>/)

task.toml metadata (repo, language, task_class, lodestar_q/d/l, lodestar_base_image), agent 1800s / verifier 3600s, cpus=2, memory=8G (-> machine size 2:8) instruction.md the issue (agent-facing) environment/Dockerfile FROM the cached per-repo image; checks out THIS task's base_commit, strips all refs/objects not reachable from it (no future commits / gold fix in `git log --all`) and cuts history at base (no ancestors either, see Git history); runs the same reinstall validation ran tests/spec.json base_commit, rebuild_cmds, test_cmds, log_parser (embedded python), FAIL_TO_PASS, PASS_TO_PASS tests/test_patch.diff hidden gold tests (injected at grade time) tests/gold_patch.diff gold code fix (used only for the rot recheck) tests/grade.py, tests/_gradelib.py RepoLaunchGym verifier, unchanged tests/test.sh verifier entrypoint (RLG's + PATH pin, see below) solution/solve.sh oracle: applies the gold patch

No task sets [environment].docker_image: OpenReward builds each environment/Dockerfile with
Cloud Build into openreward/sandbox-images/<envId>:<task> (the only *.pkg.dev path the
sandbox proxy accepts).

Git history

The agent sees only the base commit. Each Dockerfile writes .git/shallow = HEAD before
git gc --prune=now, so ancestors are dropped along with later commits, and the build fails if any
history survives (git rev-list --count HEAD must be 1 and the parent commit object must be gone).

Ancestors used to be kept, and that leaked one task. In sooperset__mcp-atlassian-1076, upstream
landed the fix (#1072), reverted it, and re-landed it in the task's PR, so the gold fix sat two
commits below base with the gold patch's exact post-image blob. RL rollouts found it with
git log/git show. A scan of all 938 tasks found no other case: it checked revert commits in the
100 commits below each base for a reverted commit that wrote a gold post-image blob. 46 near-misses
touched a gold file, but with at most 8% of its added lines (changelogs, setup.py). Cutting history
for every task also covers leaks that scan can't see, at the cost of git log/git blame for the
agent. The solvability measurements below were taken with history present.

Grading

Binary reward (SWE-bench resolved). grade.py injects the gold tests, rebuilds, runs
test_cmds, parses with the task's parser, and requires every FAIL_TO_PASS to pass and no
PASS_TO_PASS to break. Failures are re-run twice (flaky filter), then checked against a fresh
gold run: a test gold also fails today counts as rotted and is ignored. A task where gold
passes no FAIL_TO_PASS is ungradable (reward 0.0, gradable:false in reward.json).

test_cmds / log_parser are exactly what produced the labels (tools/build_validate.py:
targeted_cmd = only the test_patch's files, parser_for = per-language parser, embedded as a
def parser(log) script so _gradelib does not fall back to the pytest parser).

tests/test.sh pins the image PATH into /etc/profile.d: _gradelib runs commands with
bash -lc, and Debian's /etc/profile resets root's PATH, which drops /usr/local/go/bin and
/usr/local/cargo/bin, so every Go and Rust task would otherwise grade 0.

Specification check (tools/hidden_interface.py)

Some tasks can only be passed by guessing a name. The hidden tests call something the gold fix
introduces (a function, class, method or CLI command), and the issue never names it, so a correct
fix with a different name fails. A test file that imports the missing name fails every
FAIL_TO_PASS test in it. Example: PyThaiNLP-1058's tests import
pythainlp.tokenize.display_cell_tokenize, while the issue only says "Thai character splitter
to display cell".

python tools/hidden_interface.py --tasks tasks [--out hidden_interface.jsonl] [--broad]
Flagged (narrow check)284 of 938: easy 84/577, medium 92/197, hard 108/164 (lodestar_d buckets)
By languagepython 139/467, go 110/342, typescript 29/85, javascript 5/14, mdx 1/6, rust 0/16, ruby 0/8
Effect (Oct 2026 runs, rl-r3-step170 + GLM-5.3-Flash)where both models ran 3 seeds on every task (200 tasks), flagged tasks were solved by either model on 2 of 62 (3%), unflagged on 60 of 138 (43%). Over all 938 it is 13/284 (5%) vs 286/654 (44%), but GLM covered flagged tasks less there

The narrow check only covers names the fix defines: def/class/func/method/CLI command, used by
the tests, absent from instruction.md. It misses parameter and field names. --broad adds every
new identifier the tests use, which catches mcp-atlassian-252's content_type, but it is noisy:
it flags a quarter of easy tasks that were solved. Names that already existed before the fix are
never flagged; the agent can see them. The fix for a flagged task is to state the interface in the
issue text, not to drop the task.

Measured solvability (rl-r3-step170 vs GLM-5.3-Flash, 16 Oct 2026)

Both models ran in the agentorg harness at budget 0, with the per-task network policy enforced.
step170 ran every task 3 times. GLM-5.3-Flash ran only the tasks step170 never solved, because only
there does a GLM pass add information. It covered all of those in the first 200-task batch and the
easy, no-hidden-interface ones after that. Failures count only if graded, and passes only if the
agent did not fetch its own project upstream. 158 trials that ran the wrong task during a
mid-run task-list change are excluded (data/excluded_sessions.txt). Per task:
data/solvability.csv (tools/solvability_export.py); this section is generated by
tools/solvability_summary.py.

Difficulty (lodestar_d)Tasksstep170 solved (any seed)step170 per-seed passGLM ranGLM certifiedCandidates
easy577194 (34%)28%38084160 (28%)
medium1975 (3%)2%10556 (3%)
hard1646 (4%)3%9336 (4%)
all938205 (22%)18%57892172 (18%)
Candidates (keep rule)172: step170 mixed 80, GLM-certified 92 (plus 2 held: GLM passed, step170's failures never graded)
Keep rulestep170 fails at least once (graded) and someone passes at least once (step170 on another seed, or GLM)
Solved by either modelhidden interface 13/284 (5%), none 286/654 (44%)
Status countsneither 442, glm_not_run 169, step170_always 125, candidate_glm 92, candidate_mixed 80, ungradable 28, held 2

GLM's per-task coverage differs by group, so compare GLM-certified counts within a difficulty
bucket, not across buckets. glm_not_run tasks (medium/hard, or with a hidden interface, outside
the first batch) may still hold a few candidates.

Oracle sweep (every task: gold must score 1, empty submission must score 0)

All tasks went through tools/oracle_sweep/ (build the Dockerfile, run solve.sh or nothing,
bash /tests/test.sh, the same flow OpenReward runs). Every task in tasks/ passed it.
Dropped 51 of the original 981: the empty patch already scored 1 on 31 (no signal), gold did not
score 1 on the rest. The cause was a validation bug: F2P was "passes after gold − passes before",
so tests that merely didn't run before (crashed or cold run) became F2P. Fixed in
tools/build_validate.py (a warm recheck run without gold; F2P must fail there). 9 tasks were
re-validated with the fix, re-harborized and passed the sweep; they replace their old versions
(new F2P lists). Grade time on passing tasks: p50 20 s, p90 88 s, p99 474 s.

Smoke test (oracle must be 1, empty submission must be 0)

Emulated the OpenReward flow on a dev VM (build Dockerfile, run solve.sh or nothing, upload tests/,
bash /tests/test.sh). Oracle=1 / empty=0 on python x3, go x2, rust x1, ts x1 (subliminal-1201, marimo-7770, haystack-10421, casbin-1632, templ-484, maturin-2165, virtual-967). Not yet run on OpenReward itself.

Known caveats

  1. 33% of tasks have empty PASS_TO_PASS. Validation ran only the test_patch's own files, so
    regression guarding is weak on those tasks; they grade on FAIL_TO_PASS only.
    (~/lodestar/scripts/backfill_p2p.py widens scope to the test directory; not applied here.)
  2. Validation ran once per task (no N-run flakiness gate at label time). The grader's
    flaky re-runs and gold recheck absorb some of this, not all of it.
  3. JS/TS labels are per test file, e.g. foo.test.ts (3 tests) (vitest summary lines),
    not per test name. The raw labels carried run durations (... 28ms) in 95 tasks; these are
    stripped from both the labels and the grade-time parse.
  4. Large label sets. Some tasks have thousands of F2P, where the before-run failed wholesale
    (for example a new test file that cannot import before the fix). These are valid
    differentials, but they behave as "make the suite pass".
  5. Ruby/Java: 8 of 20 kept. The original 20 (19 ruby, 1 java) were dropped before the sweep. Their labels came from parse_generic,
    which matches "ok"/"PASS" anywhere in the output, so their "tests" were strings such as
    1.81 seconds to load) from rspec's timing line. They could not be graded. Re-validated with rspec/minitest/surefire parsers and the fixed F2P
    rule: 8 validated, 7 pass the oracle sweep (the Java one fails: its image has no python3 for
    the grader). Per-repo setup recipes (REPO_RECIPES in tools/build_validate.py: Postgres for
    theodinproject, generated test app for activeadmin, gemfile shim for sorcery) recovered
    theodinproject-4507. The rest stay out: gumroad (MySQL/Mongo/Redis stack), sorcery-371/379
    (gold removes a test / only edits CHANGELOG), activeadmin-8411 (F2P needs the test app
    regenerated after gold), view_component-2015 and theodinproject-4349 (new test file only
    loads with gold, so there is no clean failing "before").
  6. Base images live in us-central1-docker.pkg.dev/dev-ran-gr-inc/lodestar-envs. That
    repo's IAM policy is empty. OpenReward's Cloud Build identity needs read access before the
    Dockerfiles can build.
  7. JS/TS test commands use npx --yes jest|vitest, which may download at grade time, so the
    sandbox needs npm registry egress.

Regenerating

python tools/harborize_validated.py --labels-from <old harbor dir> \ --manifest build_manifest_full.jsonl --out tasks \ --templates ~/RepoLaunchGym/pipeline/templates

(tools/ holds snapshots of the generating scripts. The canonical copies are in ~/lodestar/scripts.)

GeneralReasoning/LodestarSWE | OpenReward