Skip to content

feat: remove the eval's platform push and the prime-runs dependency - #3046

Merged
mikasenghaas merged 1 commit into
mainfrom
feat/remove-push
Nov 3, 2026
Merged

mikasenghaas merged 1 commit into
mainfrom
feat/remove-push

Conversation

@mikasenghaas

@mikasenghaas mikasenghaas commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

Summary

vf-eval no longer pushes runs to the Prime Intellect platform, and verifiers no longer depends on prime-runs. Platform uploads belong to prime-rl's eval. Hosted evaluations already use it: production and dev set HOSTED_EVAL_V1_RUNNER: prime-rl.

  • Config. EvalConfig.push (--push / --no-push) and RunConfig.attach (--run.attach) are removed, and so is the validator that tied them together.
  • Run id. RunConfig.id is now a local uuid4().hex, set when the config is created. Before, open_run assigned it from the prime-runs handle. It still goes on every trace (EvalRunInfo) and into $VF_RUN_ID.
  • Runner. run_eval no longer opens, streams to, finishes or aborts a platform run. Episodes still go to traces.jsonl as each one finishes.
  • Dashboard. The "Pushing traces / Traces pushed" footer line is removed.
  • Removed: verifiers/v1/utils/platform.py (PushState, open_run, log_episodes, finish_run, abort_run, and the unused build_samples re-export) and its tests.
  • Dependencies. prime-runs is removed from the dependencies and from exclude-newer-package. prime-traces is removed from exclude-newer-package, because nothing pulls it in any more. uv.lock drops both packages and changes nothing else.
  • Docs and tests. --no-push is removed from the docs, the nemo-gym-weather README and the examples integration test.

Breaking

  • --push, --no-push and push in eval configs are removed. vf-eval runs no longer show up on the platform's Evaluations tab. To upload evals, run prime-rl's uv run eval. Remove --no-push from scripts.
  • --run.attach / run.attach is removed. The platform's verifiers v1 runner (generate_v1_eval_script, used when HOSTED_EVAL_V1_RUNNER=verifiers) passes it. Production and dev both use the prime-rl runner, so nothing live calls it. Do not switch a deployment back to the verifiers runner after this ships. The platform's config.py default is still "verifiers", and public-docs verifiers/v1/evaluation.mdx still documents run.attach.
  • Saved run configs with a push key fail to load. Every run saved before this change has "push": true in configs/resolved/eval.json, so vf-eval @ <run>/configs/resolved/eval.json --resume fails with "Extra inputs are not permitted". Delete the push key from that file, then resume.

Verification

  • pytest tests/unit: 244 passed, 10 skipped (9 need PRIME_API_KEY, 1 needs harbor).
  • ruff check, ruff format and ty pass.
  • vf-eval reverse-text --env.agent.harness.id null --env.agent.runtime.type subprocess -n 2 -r 1 --no-rich: 2 episodes were written, and both traces carry the same local run.id.
  • --resume from that run's configs/resolved/eval.json loads and reports nothing to resume. The same file with "push": true added fails with "Extra inputs are not permitted".

🤖 Generated with Claude Code

Note

Remove platform push from vf-eval and drop the prime-runs dependency

  • Deletes the platform run lifecycle in platform.py: open_run, log_episodes, finish_run, abort_run, PushState, and related helpers are gone. run_eval in runner.py still writes completed episodes to the local trace store.
  • Removes the push field from EvalConfig and the attach field and assign_id method from RunConfig. Each run now gets a UUID run ID at construction, so reading id no longer waits for a platform run to open.
  • The dashboard in eval.py no longer takes push state or renders a push-progress footer.
  • Drops prime-runs from pyproject.toml and removes --no-push from docs and the example integration test. Deletes test_platform.py.
  • Behavioral Change: RunConfig.id is a locally generated UUID instead of a platform-assigned ID, and VF_RUN_ID is set from config.run.id. Any code reading EvalConfig.push, RunConfig.attach, verifiers.v1.utils.platform.build_samples, or passing --no-push will break; in-tree usages are updated.

Macroscope summarized ab63017.


Note

Medium Risk
Breaking CLI/config surface (push, attach, saved eval JSON) and run ID semantics change from platform-assigned to local UUID; core eval path remains disk-backed traces only.

Overview
vf-eval is local-only for traces: it no longer opens, streams to, finishes, or aborts a Prime Intellect platform run. Episodes still append to traces.jsonl as before; platform uploads are expected via prime-rl's eval.

Removed verifiers/v1/utils/platform.py (including PushState, open_run, log_episodes, finish_run, abort_run) and its unit tests. prime-runs is dropped from pyproject.toml and uv.lock; prime-traces is removed from exclude-newer-package only.

Config breaking changes: EvalConfig.push (--push / --no-push), RunConfig.attach, and assign_id are gone. run.id is a uuid4().hex at config construction (still on traces and $VF_RUN_ID). Saved resolved configs that still contain "push": true will fail validation on resume/replay until that key is removed.

Runner and dashboard: run_eval no longer calls platform helpers or shielded close-out; the live dashboard no longer shows push progress URLs. Docs and integration tests drop --no-push from example commands.

Reviewed by Cursor Bugbot for commit ab63017. Bugbot is set up for automated code reviews on this repo. Configure here.

vf-eval no longer opens a run on the platform or streams episodes to
it. Hosted evaluations run prime-rl's eval, which owns platform
uploads, so verifiers drops prime-runs (and with it prime-traces).
The run id is minted locally.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mikasenghaas
mikasenghaas marked this pull request as ready for review November 3, 2026 00:16
@macroscopeapp

macroscopeapp Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — Evaluations become local-only, and existing push/attach flags and saved configs lose compatibility. Human judgment is needed on the migration and release plan, including preventing hosted deployments from selecting the removed attachment path.

You can add or adjust custom eligibility rules. Learn more.

@mikasenghaas
mikasenghaas merged commit 278fd63 into main Nov 3, 2026
37 checks passed
@mikasenghaas
mikasenghaas deleted the feat/remove-push branch November 3, 2026 00:20
mikasenghaas added a commit to PrimeIntellect-ai/prime-rl that referenced this pull request Nov 3, 2026
…ime (#4366)

## Summary

Companion to PrimeIntellect-ai/verifiers#3042 and
PrimeIntellect-ai/prime#1140 (released in `prime-runs` 0.1.6). The file
monitor and the Prime monitor encode each episode in short steps, so a
large episode no longer stalls the orchestrator's event loop for as long
as encoding it takes.

- **Pins.**
- The verifiers submodule moves to verifiers main, which includes
verifiers#3042: `to_json` encodes one node at a time and releases the
GIL every millisecond, and `record_run` records the run on every trace.
- `prime-runs` 0.1.6, already on main, contains prime#1140: the SDK
uploads `episode.to_json()` as it is when the episode and its traces
name the upload's run. The dispatcher's `record_run` makes that true for
RL episodes.
- Verifiers main also includes PrimeIntellect-ai/verifiers#3046, which
removes `vf-eval`'s platform push and verifiers' `prime-runs`
dependency. In `uv.lock` (uv 0.12.0), only the verifiers metadata
changes.
- **The file monitor writes `episode.to_json()`.**
- The stream line is byte for byte what
`orjson.dumps(episode.to_record())` gave before.
- The index row comes from `index_record(episode)`. It dumps everything
but the nodes' payloads, one trace at a time, and gives the same row.
- `ChunkedJsonl.append` takes a line in parts, so the newline is written
without copying a long line.
- **The load test's lag limits drop** from p99 100 ms and max 250 ms to
25 ms and 100 ms, so a regression shows. Across runs at production
sizes, the highest values were a p99 of 12.5 ms and a max of 22 ms.
- **A hosted orchestrator stamps the platform's run id.** A hosted
launch sets only `$RUN_ID`, not `$PRL_RUN_ID`, so the orchestrator
stamped episodes with a random id, and the SDK re-stamped every upload.
It now falls back to `$RUN_ID`, the Prime run id.

## Verification

**Headline: event-loop lag at 1,000 production-sized episodes (~8 GB of
JSON)**, monitor load test, dev box:

| | Main (before) | This PR |
|---|---|---|
| prime: lag p99 / max | 14 / 17 ms | **3.1 / 3.5 ms** |
| file: lag p99 / max | 47 / 93 ms | **4.8 / 15 ms** |
| file: `log()` max | 177 ms | 195 ms |

- **A second run:** inside the full unit suite, with more load on the
box, it measured prime 11 / 18 ms, file 5.2 / 22 ms, and file `log()`
max 224 ms.
- **Why the GIL release matters:** encoding node by node without it left
the file monitor at 15–18 / 31–66 ms, varying from run to run. A busy
encoder thread keeps the GIL until CPython's 5 ms switch interval forces
a handoff, and the event loop waits that out several times per wakeup.

**The stall no longer grows with the episode.** One thread encodes
episodes of 10 to 10,000 turns (1,000 tokens per turn) while a 5 ms
ticker on the event loop records the worst stall. Medians of 5 runs,
under the orchestrator's GC policy:

| Turns | Episode | Encode CPU, before / after | Worst stall, before |
Worst stall, after |
|---|---|---|---|---|
| 10 | 0.2 MB | 0.4 / 0.5 ms | 5.5 ms | 5.2 ms |
| 100 | 2.2 MB | 4.0 / 4.5 ms | 8.0 ms | 1.6 ms |
| 1,000 | 22 MB | 50 / 51 ms | 40 ms | 3.1 ms |
| 3,000 | 65 MB | 152 / 167 ms | 100 ms | 5.2 ms |
| 10,000 | 217 MB | 508 / 571 ms | 326 ms | 15 ms |

- **Before:** the stall grows linearly with the episode.
- **After:** it stays around 2–5 ms up to 3,000 turns, about the GIL
switch interval. The 10-turn case is that interval alone, since each
episode encodes in under a millisecond.
- **The rest at 10,000 turns:** the trace header's pydantic dump, which
holds every model call (one per turn). Alone it stalls 4.4 / 8.4 / 15 ms
at 1,000 / 3,000 / 10,000 turns. Agentic episodes in production have a
few hundred turns, so this part stays small. Encoding the calls one at a
time, like the nodes, would remove it.
- **CPU:** encoding costs up to ~12% more, from the extra calls and GIL
releases.

**Encoding:** `test_received_episode_encodes_as_its_record_did` sends a
two-trace episode over the real delta wire into a `WireEpisode`. Then:
- the file monitor's stream line equals `orjson.dumps(to_record())`,
byte for byte;
- its index row equals the row from the full record;
- after `record_run`, the SDK takes the episode's own `to_json()`, which
carries the same record as the old stamped line.

**Tests:** `pytest tests/unit -m "not gpu"`: 1,077 passed, 7 failed. The
same 7 fail on main on this dev box: an attention kernel without sm_120
support, and no ninja for the CPU Adam extension.

**CI:** on the CI runner, the file monitor at 1,000 production-sized
episodes measured event-loop lag p99 6.0 ms and max 12 ms, against 63 /
152 ms on main. Its slowest `log()` was 382 ms, under the 1 s limit.


🤖 Generated with [Claude Code](https://claude.com/claude-code)


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes affect how every episode is persisted and indexed and how run
identity is chosen on hosted launches; behavior is contract-tested but
touches high-volume I/O on the training path.
> 
> **Overview**
> Large episodes no longer block the orchestrator event loop during
trace logging. The **file monitor** writes stream lines with
**`episode.to_json()`** (incremental, GIL-friendly encoding from
verifiers) instead of a single **`orjson.dumps(to_record())`**, and
builds index rows via new **`index_record()`** so summarization skips
heavy node payloads without materializing the full record first.
**`ChunkedJsonl.append`** accepts **byte parts** so the newline is
appended without copying megabyte-scale lines.
> 
> The orchestrator **`run_id`** now falls back to **`$RUN_ID`** when
**`$PRL_RUN_ID`** is unset, so hosted runs align with the platform id
and Prime uploads are not re-stamped with a random id.
> 
> Monitor load tests use **stricter event-loop lag thresholds** to catch
regressions. A new unit test asserts on-disk bytes and SDK upload JSON
still match the legacy **`to_record()`** encoding.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f83e849. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
earakely-scale added a commit to scaleapi/agentenv-framework that referenced this pull request Nov 3, 2026
verifiers main removed the eval's platform push (PrimeIntellect-ai/verifiers#3046), and with it the
--no-push flag, which its config now rejects as an extra input. 0.4.0 still pushes by default, so
the taskset test passes --no-push only when vf-eval --help lists it: both the pinned and the main
jobs run the same test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants