Skip to content

feat(mlflow): load harness-snapshot from disk and MLflow - #157

Merged
astefanutti merged 6 commits into
opendatahub-io:mainfrom
HofniGartner:feat/harness-snapshot-mlflow-consumer
Aug 5, 2026
Merged

astefanutti merged 6 commits into
opendatahub-io:mainfrom
HofniGartner:feat/harness-snapshot-mlflow-consumer

Conversation

@HofniGartner

@HofniGartner HofniGartner commented Jul 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Optional join-key support for eval runs: if the agent runtime left
harness-snapshot.json under the run/case output, log_results projects
fields to MLflow tags and uploads the file as an artifact. Later readers
fetch that artifact from MLflow (same run-name join as inputs/), not by
scraping CI env.

Changes

  • Add agent_eval/ci_context.py: find/load snapshot on disk; map join fields
    to tags (commit_sha ← ref_revision, harness_fingerprint ←
    harness_content_sha); fetch_harness_snapshot(experiment_id, eval_run_id);
    CI env only as last-resort fallback
  • Wire log_results.py to collect tags from the run dir and
    mlflow.log_artifact the snapshot when present
  • Document the handoff vs MLflow-first read path in eval-yaml-template.md
  • Tests: disk find, tag mapping, mocked MLflow fetch, prefer-MLflow order,
    producer-shaped snapshot → join tags round-trip

Test plan

  • python -m pytest tests/test_ci_context.py -q
  • (Optional) Run log_results against a run dir that contains
    cases/<id>/harness-snapshot.json and confirm tags + artifact on the
    MLflow run

Notes

  • Thin consumer only — no parallel join schema in this repo
  • Does not require an agent-runtime change to merge; without the file,
    behavior is unchanged aside from optional CI-env tag fallback

Made with Cursor

Summary by CodeRabbit

  • New Features
    • Derives MLflow run tags from available harness snapshot data, using local files or MLflow retrieval.
    • Uploads harness snapshot data as an MLflow artifact when available.
    • Combines CI-derived and configured tags while preserving the run-name join key.
  • Documentation
    • Clarified snapshot-based tag discovery, overrides, and artifact retrieval in the eval configuration template.
  • Bug Fixes
    • Falls back to CI values when snapshot data is missing or corrupted.
    • Safely rejects invalid run identifiers during snapshot retrieval.
  • Tests
    • Added coverage for discovery, fetching, precedence, merging, and error handling.

HofniGartner and others added 2 commits July 22, 2026 11:50
Disk handoff at log_results; fetch_harness_snapshot for later readers
using the same run-name join as inputs/ artifacts.

Co-authored-by: Cursor <cursoragent@cursor.com>
Vertical-slice check: fullsend-shaped harness-snapshot.json projects
to Provenance/MLflow tag names, including MLflow fetch round-trip.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 9dda3b92-941e-4de0-b29a-e7331bc10cd2

📥 Commits

Reviewing files that changed from the base of the PR and between d84092b and 37fb88c.

📒 Files selected for processing (1)
  • skills/eval-mlflow/scripts/log_results.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • skills/eval-mlflow/scripts/log_results.py

📝 Walkthrough

Walkthrough

Adds CI context collection from local harness snapshots, MLflow artifacts, or CI environment variables. Maps snapshot and provenance fields into MLflow tags, supports source precedence and protected configuration merging, and logs discovered snapshots as MLflow artifacts. Updates MLflow configuration documentation and adds tests for mapping, discovery, retrieval, precedence, fallback, merging, malformed input, and unsafe run-name validation.

Estimated code review effort: 4 (Complex) | ~45 minutes

🚥 Pre-merge checks | ✅ 9 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
No Sensitive Data In Logs ⚠️ Warning New warnings interpolate raw MLflow exceptions and run identifiers, which may include credentials or response data (CWE-532, CWE-209). Log fixed messages with sanitized exception types/status only; do not print exception text or raw identifiers, and apply secret redaction before artifact/tag logging.
✅ Passed checks (9 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: loading harness-snapshot data from disk and MLflow for MLflow evaluation runs.
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.
Contribution Quality And Spam Detection ✅ Passed The PR adds a focused four-file feature, 11 tests, and iterative implementation fixes; no two cross-category spam signals are evidenced, and the filter validation has direct coverage.
No Hardcoded Secrets ✅ Passed PR-added files contain no hardcoded credentials, private-key blocks, embedded URL credentials, or decodable base64 strings over 32 characters; token hits are environment-variable documentation exam...
No Weak Cryptography ✅ Passed No banned primitive or custom crypto appears in the PR code; the only “sha1” use is a git ref fixture, which is non-security use. No secret comparison exists.
No Injection Vectors ✅ Passed No exploitable CWE-78/89/94/502/79 sink found; the MLflow filter rejects quotes and backslashes before interpolation, and no shell, eval, unsafe YAML/pickle, or HTML sink exists.
No Privileged Containers ✅ Passed PR diff adds no manifest or container-file privilege settings; existing images use root only for build steps and end with USER 1001, while generated pods drop ALL capabilities and disable escalatio...

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 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 `@agent_eval/ci_context.py`:
- Around line 130-139: Make harness snapshot loading best-effort by catching
invalid or truncated JSON errors at each caller: collect_from_snapshot_dir, the
HARNESS_SNAPSHOT_PATH branch in from_disk, and the load_harness_snapshot(path)
call in fetch_harness_snapshot. On failure, preserve the existing fallback/None
behavior so collect_ci_context continues logging tags, artifacts, traces, and
feedback instead of propagating the snapshot parsing exception.
- Around line 174-192: Replace the broad silent exception handlers in the MLflow
run lookup and artifact-download loop with targeted exception handling that logs
the failure details through the existing logging mechanism, while preserving the
current None/continue fallback behavior. Also ensure load_harness_snapshot
failures are handled consistently with the companion error-handling path rather
than remaining unguarded.
- Around line 169-173: Sanitize eval_run_id before constructing the
filter_string passed to search_runs: escape or reject quote and backslash
characters so caller-controlled values cannot alter the MLflow tag-filter
expression. Keep the existing run-name lookup behavior unchanged for valid
identifiers.

In `@skills/eval-mlflow/scripts/log_results.py`:
- Around line 287-301: Update the collect_ci_context call in the MLflow tag
setup to forward the already-computed experiment_id, enabling the documented
MLflow-artifact fallback. Wrap this context collection and tag-application block
in the same appropriate exception-handling pattern used by nearby trace-search,
link, and feedback calls, so malformed harness snapshots do not abort artifact
logging or later run processing.
🪄 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: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: c0b8744c-cb93-407c-8975-43099071f12c

📥 Commits

Reviewing files that changed from the base of the PR and between 4b540c6 and 1aa34a2.

📒 Files selected for processing (4)
  • agent_eval/ci_context.py
  • skills/eval-analyze/references/eval-yaml-template.md
  • skills/eval-mlflow/scripts/log_results.py
  • tests/test_ci_context.py

Comment thread agent_eval/ci_context.py Outdated
Comment thread agent_eval/ci_context.py
Comment thread agent_eval/ci_context.py Outdated
Comment thread skills/eval-mlflow/scripts/log_results.py Outdated
Best-effort JSON load so corrupt snapshots do not abort log_results;
forward experiment_id for artifact fallback; reject unsafe run-name
filter chars; warn on MLflow search/download failures.

Co-authored-by: Cursor <cursoragent@cursor.com>
@HofniGartner

Copy link
Copy Markdown
Contributor Author

Addressed CodeRabbit review:

  • Best-effort snapshot load (try_load_harness_snapshot) so corrupt/truncated JSON falls through to MLflow/CI instead of aborting log_results
  • Pass experiment_id into collect_ci_context so the documented MLflow-artifact fallback is live
  • Reject eval_run_id values containing ' / \ before building filter_string
  • Warn (stderr) on MLflow search/download failures; wrap tag + snapshot artifact logging in try/except

On the CWE-532 note about repository_url / pipeline_run_url: those are intentional join-key tags from the snapshot contract. URLs with embedded credentials would be a producer/env bug; we are not stripping forge pointers from tags.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@skills/eval-mlflow/scripts/log_results.py`:
- Around line 290-300: Ensure the tag-merging logic around merge_mlflow_tags and
the mlflow.set_tag loop always preserves the mlflow.runName value established by
mlflow.start_run() from args.run_id, ignoring any
config.mlflow.tags["mlflow.runName"] override. Add coverage for this override
case and document that mlflow.runName is immutable because provenance consumers
depend on it.

In `@tests/test_ci_context.py`:
- Around line 203-214: Update test_fetch_rejects_unsafe_eval_run_id to provide a
mock search_runs callable, retain its reference, and assert it was never called
after fetch_harness_snapshot receives the unsafe run ID. Keep the existing None
result and client.download_artifacts assertion.
🪄 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: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: f3f6182b-5804-44f8-b1e4-95d6860abfc0

📥 Commits

Reviewing files that changed from the base of the PR and between 1aa34a2 and 06d07fe.

📒 Files selected for processing (3)
  • agent_eval/ci_context.py
  • skills/eval-mlflow/scripts/log_results.py
  • tests/test_ci_context.py

Comment thread skills/eval-mlflow/scripts/log_results.py
Comment thread tests/test_ci_context.py
Join consumers look up runs by start_run's name; ignore config overrides
and assert unsafe eval_run_id never hits search_runs.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/test_ci_context.py (1)

185-194: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert preservation of an existing mlflow.runName.

This test only verifies that configuration cannot add the key. It would still pass if merge_mlflow_tags accidentally discarded an existing mlflow.runName, despite the artifact lookup contract requiring preservation.

Proposed test adjustment
    merged = merge_mlflow_tags(
-       {"eval_run_id": "r1"},
+       {"eval_run_id": "r1", "mlflow.runName": "original"},
        {"mlflow.runName": "hijacked", "team": "ml"},
    )
-   assert "mlflow.runName" not in merged
+   assert merged["mlflow.runName"] == "original"
    assert merged["team"] == "ml"
🤖 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 `@tests/test_ci_context.py` around lines 185 - 194, Update
test_merge_mlflow_tags_preserves_run_name to include an existing mlflow.runName
in the base tags, then assert the merged result retains that original value
while still rejecting the configuration override and preserving unrelated tags.
🤖 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.

Nitpick comments:
In `@tests/test_ci_context.py`:
- Around line 185-194: Update test_merge_mlflow_tags_preserves_run_name to
include an existing mlflow.runName in the base tags, then assert the merged
result retains that original value while still rejecting the configuration
override and preserving unrelated tags.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: e54bedb7-1c9a-46da-af51-89cb38a752fa

📥 Commits

Reviewing files that changed from the base of the PR and between 06d07fe and 0573923.

📒 Files selected for processing (4)
  • agent_eval/ci_context.py
  • skills/eval-analyze/references/eval-yaml-template.md
  • skills/eval-mlflow/scripts/log_results.py
  • tests/test_ci_context.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • skills/eval-analyze/references/eval-yaml-template.md
  • skills/eval-mlflow/scripts/log_results.py
  • agent_eval/ci_context.py

Co-authored-by: Cursor <cursoragent@cursor.com>
@HofniGartner

Copy link
Copy Markdown
Contributor Author

Refreshed onto current main (2026-08-02). Prior CodeRabbit notes were addressed; no unresolved review threads on my side. Looking for a maintainer review/merge when convenient.

@astefanutti astefanutti 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.

Thanks @HofniGartner!

@astefanutti
astefanutti merged commit 930eadd into opendatahub-io:main Aug 5, 2026
3 checks passed
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