Skip to content

feat(evaluator-sdk): add read_trials bundle loader + self-contained bundle refs - #808

Merged
SandyChapman merged 1 commit into
mainfrom
read-trials-bundle-loader/schapman
Jul 28, 2026
Merged

feat(evaluator-sdk): add read_trials bundle loader + self-contained bundle refs#808
SandyChapman merged 1 commit into
mainfrom
read-trials-bundle-loader/schapman

Conversation

@SandyChapman

@SandyChapman SandyChapman commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

What

Adds the inverse of persist_run, so a persisted agent-eval run bundle can be loaded back and re-scored with a different metric/judge without re-running the agent:

  • read_trials(run_dir) — hydrates trials.jsonl into AgentEvalTrial objects with their evidence, resolving each evidence ref against the bundle dir. Feed the result to AgentEvaluator().run(tasks=…, trials=…) to re-score.
  • persist_run now writes bundle-relative evidence refs (_write_trials) — a trial's evidence lives under the bundle, so storing the ref relative to the bundle (not the launch CWD) makes a moved or copied bundle re-score with no path fixups. Refs pointing outside the bundle are left verbatim.

Why

persist_run had no loader, so re-scoring a stored run (e.g. with a cheaper/faster or corrected judge) meant re-running the agent — expensive and often impossible after the fact. This makes "run once, re-grade later / elsewhere" a first-class, generic capability (any runner's bundle, not tied to a specific benchmark).

Compatibility

read_trials is backward-compatible: it resolves bundle-relative refs (new), still-valid absolute refs, and legacy/moved bundles (rebuilt under run_dir from the evidence/ tail). Existing bundles keep working.

Tests

test_persistence.py: hydrate + valid ref, moved-bundle ref rebuild, and a persist_run → assert-relative-ref → copytreeread_trials round-trip proving self-containment. pytest green; existing evaluator persist/imported-trials tests unaffected. Includes the re-vendored SDK mirror.

Summary by CodeRabbit

  • New Features
    • Added end-to-end persistence and retrieval of evaluation trials via trials.jsonl within run bundles.
    • Evidence references are written in a portable way so they continue to resolve after bundle copy/move; external absolute evidence refs are preserved.
  • Bug Fixes
    • Improved hydration by rebuilding evidence refs when a bundle is relocated and workspace paths must be re-associated.
  • Tests
    • Expanded coverage for moved-bundle behavior, external absolute refs, and a security check preventing evidence refs from escaping the bundle via path traversal.

@SandyChapman
SandyChapman requested review from a team as code owners July 21, 2026 14:25
@github-actions github-actions Bot added the feat label Jul 21, 2026
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 5b0689c4-fc80-4be4-915e-a6694d83fc27

📥 Commits

Reviewing files that changed from the base of the PR and between b9a75e1 and 6806214.

⛔ Files ignored due to path filters (1)
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/persistence.py is excluded by !sdk/**
📒 Files selected for processing (2)
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_persistence.py

📝 Walkthrough

Walkthrough

Changes

Portable trial persistence

Layer / File(s) Summary
Bundle writing and trial hydration
packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py
persist_run writes bundle-relative evidence references, while read_trials streams trials.jsonl and safely resolves current, moved, external, and legacy references.
Persistence behavior validation
packages/nemo_evaluator_sdk/tests/agent_eval/test_persistence.py
Tests cover trial hydration, stale workspace reference rebuilding, copied bundles, path traversal rejection, and preservation of external absolute references.

Sequence Diagram(s)

sequenceDiagram
  participant AgentEvalResult
  participant persist_run
  participant trials.jsonl
  participant read_trials
  participant run_dir
  AgentEvalResult->>persist_run: provide trials
  persist_run->>trials.jsonl: write bundle-relative evidence refs
  read_trials->>trials.jsonl: stream persisted trial records
  read_trials->>run_dir: resolve evidence refs
  read_trials-->>AgentEvalResult: return hydrated trials
Loading

Suggested labels: feat

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding read_trials and bundle-relative evidence references.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch read-trials-bundle-loader/schapman

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py`:
- Around line 110-131: Update _resolve_evidence_ref so both rebuilt paths are
resolved and accepted only when they remain contained within run_dir; reject
traversal or legacy-tail results that escape the bundle even if the target
exists. Preserve valid in-bundle relative and legacy evidence resolution, and
add a regression test covering a crafted .. reference targeting an existing
out-of-bundle file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a89b569b-a015-452b-9870-365110d4ba5c

📥 Commits

Reviewing files that changed from the base of the PR and between 848ea33 and d254173.

⛔ Files ignored due to path filters (1)
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/persistence.py is excluded by !sdk/**
📒 Files selected for processing (2)
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_persistence.py

@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor
Suite Lines Covered Line Rate Branch Rate
Unit Tests 26438/34088 77.6% 61.9%
Integration Tests 15183/32713 46.4% 18.6%

@SandyChapman
SandyChapman force-pushed the read-trials-bundle-loader/schapman branch from d254173 to b9a75e1 Compare July 21, 2026 14:47

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py (1)

93-145: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Containment check is fixed, but returned ref still uses the unresolved path — reopens a TOCTOU gap.

_resolves_within validates path.resolve() stays under base, but _resolve_evidence_ref returns str(rebuilt)/the unresolved joined path, not the canonical resolved one. Any symlink component in rebuilt is re-followed whenever the returned ref is later opened for re-scoring — potentially much later, per read_trials' own docstring — so a symlink swapped after this check still escapes the bundle despite passing containment.

Return the resolved canonical path so the validated location is what actually gets used later.

🔒 Suggested fix
-    if not candidate.is_absolute():
-        rebuilt = run_dir / candidate
-        if _resolves_within(base, rebuilt):
-            return str(rebuilt)
+    if not candidate.is_absolute():
+        resolved = _resolve_within(base, run_dir / candidate)
+        if resolved is not None:
+            return str(resolved)
     elif candidate.exists():
         return ref
     parts = candidate.parts
     if "evidence" in parts:
-        rebuilt = run_dir / Path(*parts[parts.index("evidence") :])
-        if _resolves_within(base, rebuilt):
-            return str(rebuilt)
+        resolved = _resolve_within(base, run_dir / Path(*parts[parts.index("evidence") :]))
+        if resolved is not None:
+            return str(resolved)
     return ref


-def _resolves_within(base: Path, path: Path) -> bool:
+def _resolve_within(base: Path, path: Path) -> Path | None:
     resolved = path.resolve()
     if not resolved.exists():
-        return False
-    return resolved == base or base in resolved.parents
+        return None
+    if resolved == base or base in resolved.parents:
+        return resolved
+    return None
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py`
around lines 93 - 145, Update _resolve_evidence_ref to return the canonical
resolved path produced after containment validation, rather than str(rebuilt),
for both relative refs and rebuilt evidence refs. Reuse the resolved path from
_resolves_within (or adjust that helper to expose it) so read_trials stores the
exact validated location and later rescoring cannot reopen the unresolved
symlink path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/nemo_evaluator_sdk/tests/agent_eval/test_persistence.py`:
- Around line 59-84: Extend
test_persist_run_writes_bundle_relative_refs_that_survive_a_move with a
workspace located outside the bundle, then verify persist_run writes its
absolute evidence reference unchanged and read_trials returns that same absolute
reference. Keep the existing in-bundle relative-reference and moved-bundle
assertions intact.

---

Duplicate comments:
In
`@packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py`:
- Around line 93-145: Update _resolve_evidence_ref to return the canonical
resolved path produced after containment validation, rather than str(rebuilt),
for both relative refs and rebuilt evidence refs. Reuse the resolved path from
_resolves_within (or adjust that helper to expose it) so read_trials stores the
exact validated location and later rescoring cannot reopen the unresolved
symlink path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: dcc259bf-e2ba-4765-ad63-f7af65a41e1f

📥 Commits

Reviewing files that changed from the base of the PR and between d254173 and b9a75e1.

⛔ Files ignored due to path filters (1)
  • sdk/python/nemo-platform/src/nemo_platform/beta/evaluator/agent_eval/persistence.py is excluded by !sdk/**
📒 Files selected for processing (2)
  • packages/nemo_evaluator_sdk/src/nemo_evaluator_sdk/agent_eval/persistence.py
  • packages/nemo_evaluator_sdk/tests/agent_eval/test_persistence.py

Comment thread packages/nemo_evaluator_sdk/tests/agent_eval/test_persistence.py
…undle refs

persist_run had no inverse — a persisted run bundle could not be loaded back to
re-score its stored trials with a different metric/judge without re-running the
agent. Add read_trials(run_dir) to hydrate persisted trials with their evidence,
and make persist_run write bundle-relative evidence refs so a moved or copied
bundle re-scores with no path fixups. read_trials stays backward-compatible with
legacy absolute refs (and rebuilds moved-bundle paths from the evidence/ tail).
Covered by round-trip tests.

Signed-off-by: Sandy Chapman <schapman@nvidia.com>
@SandyChapman
SandyChapman force-pushed the read-trials-bundle-loader/schapman branch from b9a75e1 to 6806214 Compare July 21, 2026 14:58
@SandyChapman
SandyChapman added this pull request to the merge queue Jul 28, 2026
Merged via the queue into main with commit 22dfc8a Jul 28, 2026
60 checks passed
@SandyChapman
SandyChapman deleted the read-trials-bundle-loader/schapman branch July 28, 2026 13:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants