Skip to content

Fix SkippyBench eval reproducibility - #992

Merged
i386 merged 3 commits into
mainfrom
jd/fix-skippy-eval-review
Jul 14, 2026
Merged

Fix SkippyBench eval reproducibility#992
i386 merged 3 commits into
mainfrom
jd/fix-skippy-eval-review

Conversation

@i386

@i386 i386 commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

What changed

  • update existing external-eval clones to the fetched upstream ref instead of leaving stale local branches checked out
  • record the resolved upstream harness SHA as harness_commit in every run.json
  • forward --api-key to SPEED-Bench requests through a small bearer-auth launcher while keeping the upstream harness unchanged and redacting the token from recorded commands
  • split the former 2,154-line evals.rs into registry, sync, doctor, run, and per-adapter modules
  • document the synchronization and reproducibility behavior

Why

This follows up on the four findings in the post-merge review of #865. Floating upstream refs were not auditable, cached clones could remain stale after eval sync, SPEED-Bench ignored endpoint credentials, and the new eval implementation exceeded the repository's source-file size policy.

Validation

  • cargo fmt --all --check
  • cargo check -p skippy-bench
  • cargo clippy -p skippy-bench --all-targets -- -D warnings
  • cargo test -p skippy-bench --bins (55 passed)
  • git diff --check
  • SPEED-Bench dry-run smoke confirming harness_commit output and API-key redaction

Summary by CodeRabbit

  • New Features
    • Added evaluation commands for listing packs, viewing eval info, syncing harnesses, preflight “doctor” checks, and running evaluations.
    • Introduced new adapters for MCP Atlas, SWE-bench Pro, Terminal-Bench, and Speed Bench.
    • Run reports now include normalized metrics, duration, artifact locations, and the resolved harness revision (harness_commit).
    • Added dry-run support and enhanced harness synchronization/step execution.
  • Documentation
    • Expanded guidance on harness synchronization and reproducible evidence recording, plus telemetry/authentication behavior.
  • Security
    • Secret environment variables are redacted in displayed commands while still being used during execution.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

SkippyBench evaluation handling is reorganized into registry, synchronization, diagnostics, adapter, and run modules. Supported benchmarks now generate dedicated commands, collect evaluation-specific metrics and artifacts, redact secret environment values, and record the resolved harness commit in run.json.

Changes

SkippyBench evaluation workflow

Layer / File(s) Summary
Registry and command dispatch
crates/skippy-bench/src/evals.rs, crates/skippy-bench/src/evals/registry.rs, crates/skippy-bench/src/evals/adapters/mod.rs
Evaluation definitions, metadata views, command routing, and submodule wiring are added for listing and inspecting evals.
Harness synchronization and diagnostics
crates/skippy-bench/src/evals/sync.rs, crates/skippy-bench/src/evals/doctor.rs
Existing harnesses fetch and check out FETCH_HEAD; eval-specific setup, prerequisite checks, Docker probes, and MCP Atlas port checks are implemented.
Evaluation command adapters
crates/skippy-bench/src/evals.rs, crates/skippy-bench/src/evals/adapters/*, crates/skippy-bench/src/evals/adapters/templates/*
Dedicated adapters generate commands and scripts for MCP Atlas, Speed Bench, SWE-bench-Pro, and Terminal Bench; secret environment variables are injected into processes and redacted in displayed commands.
Evaluation execution and reporting
crates/skippy-bench/src/evals/run.rs, crates/skippy-bench/src/evals.rs
Runs validate and execute evaluations, resolve harness commits, enumerate artifacts, collect benchmark-specific metrics and telemetry, and write run.json.
Reproducibility documentation
.agents/skills/skippy-bench/SKILL.md, crates/skippy-bench/README.md
Documentation records fetched-ref checkout, harness commit reporting, run metadata, Speed Bench authentication, and telemetry failure behavior.

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

Sequence Diagram(s)

sequenceDiagram
  participant EvalCLI
  participant run_eval
  participant Adapter
  participant Harness
  participant RunReport
  EvalCLI->>run_eval: submit evaluation arguments
  run_eval->>Adapter: build benchmark command
  Adapter->>Harness: execute evaluation harness
  Harness-->>run_eval: return artifacts and status
  run_eval->>RunReport: resolve commit and collect metrics
  RunReport-->>EvalCLI: write run.json
Loading

Suggested reviewers: ndizazzo

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: fixing SkippyBench eval reproducibility.
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 jd/fix-skippy-eval-review

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.

@github-actions

Copy link
Copy Markdown
Contributor

This pull request is currently a draft. Reviews will not take place until the PR is marked as ready for review.

@i386
i386 marked this pull request as ready for review July 14, 2026 20:22
@github-actions
github-actions Bot requested a review from ndizazzo July 14, 2026 20:22

@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: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/skippy-bench/src/evals.rs (1)

138-221: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Redact OPENAI_API_KEY in crates/skippy-bench/src/evals/adapters/terminal_bench.rs

OPENAI_API_KEY still goes through .env(...), so it will be included in command.display() and persisted in run.json. Switch it to .secret_env(...).

  • mcp_atlas_command and swe_bench_pro_command also write the raw key into run_dir/raw/*.sh, so those artifacts retain secrets on disk too.
🤖 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 `@crates/skippy-bench/src/evals.rs` around lines 138 - 221, Update the command
construction in terminal_bench.rs so OPENAI_API_KEY is passed through secret_env
rather than env, ensuring CommandSpec::display redacts it. Apply the same secret
handling in mcp_atlas_command and swe_bench_pro_command, and prevent those
commands from writing the raw key into run_dir/raw/*.sh while preserving their
existing execution behavior.
🧹 Nitpick comments (2)
crates/skippy-bench/src/evals/run.rs (2)

3-102: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

run_eval is close to the function-size guideline; consider phase-splitting.

At ~100 lines this sits right at clippy's default too_many_lines threshold: too-many-lines-threshold = 100 # default: 100 (make explicit). The function mixes validation, dry-run branching, command execution, and report assembly. Splitting into e.g. build_initial_report(...) and execute_and_finalize(...) helpers would keep it comfortably under the limit and match the guideline's "split before it reaches the threshold" intent.

🤖 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 `@crates/skippy-bench/src/evals/run.rs` around lines 3 - 102, Split run_eval
before the 100-line threshold by extracting initial RunReport construction into
a build_initial_report helper and non-dry-run execution, metrics, telemetry, and
report updates into an execute_and_finalize helper. Keep run_eval responsible
for validation, setup, command creation, helper orchestration, report
serialization, and final success handling.

Source: Coding guidelines


183-193: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Metrics-parsing failures are silently swallowed.

collect_metrics (Line 185-188) defaults to an empty EvalMetrics via .unwrap_or_default() on any parse error, and mcp_atlas_metrics (Line 345) drops malformed CSV rows via .filter(|record| record.is_ok()) — both without any diagnostic. A harness output-format regression would silently produce all-empty/undercounted metrics with no signal in stdout or run.json explaining why.

Also applies to: 343-350

🤖 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 `@crates/skippy-bench/src/evals/run.rs` around lines 183 - 193, Update
collect_metrics to report errors from each evaluator-specific metrics parser
instead of silently replacing failures with EvalMetrics::default(), while
preserving duration and client-rate population. In mcp_atlas_metrics, stop
filtering malformed CSV records without diagnostics; surface or explicitly log
each parse failure so undercounted metrics are observable.
🤖 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 `@crates/skippy-bench/src/evals/adapters/speed_bench.rs`:
- Line 34: Update the cache_root construction in the Speed-Bench adapter to
derive its path from the configured root parameter instead of env::temp_dir().
Keep the existing cache subdirectory name and ensure the --cache-root value
controls the adapter’s cache location consistently with the other adapters.
- Around line 3-21: Update AUTH_LAUNCHER’s authorized_request to inject the
Authorization header only when the request URL targets the benchmark --url host;
leave headers unchanged for all other hosts. Avoid applying credentials through
the globally patched request hook beyond that endpoint, while preserving
existing caller-provided Authorization headers.

In `@crates/skippy-bench/src/evals/adapters/swe_bench_pro.rs`:
- Around line 14-289: Extract the large shell script template from
write_swe_bench_pro_run_script into a separate template file and load it with
include_str!, leaving this function responsible only for setup, value
preparation, formatting, and writing. Apply the same extraction to the
corresponding oversized script template in write_mcp_atlas_run_script in
crates/skippy-bench/src/evals/adapters/mcp_atlas.rs (lines 18-187), preserving
all placeholders and generated script behavior.

In `@crates/skippy-bench/src/evals/adapters/terminal_bench.rs`:
- Around line 25-26: Standardize API-key handling across the eval adapters: in
crates/skippy-bench/src/evals/adapters/terminal_bench.rs:25-26, replace the
recorded OPENAI_API_KEY env assignment with CommandSpec::secret_env; in
crates/skippy-bench/src/evals/adapters/mcp_atlas.rs:34-52, remove direct
args.api_key interpolation from the generated script and its
LLM_API_KEY/OPENAI_API_KEY exports, instead registering it via secret_env and
reading the process environment; in
crates/skippy-bench/src/evals/adapters/swe_bench_pro.rs:54-77, apply the same
secret_env and environment lookup pattern, avoiding plaintext embedding and CLI
propagation at the referenced model-API-key sites.

In `@crates/skippy-bench/src/evals/run.rs`:
- Around line 82-88: Update the collect_telemetry error branch in the eval run
flow so it only records telemetry_report::unavailable and does not set
report.success to false. Preserve report.success as determined by
outcome.success, while continuing to represent telemetry collection failures
separately.

---

Outside diff comments:
In `@crates/skippy-bench/src/evals.rs`:
- Around line 138-221: Update the command construction in terminal_bench.rs so
OPENAI_API_KEY is passed through secret_env rather than env, ensuring
CommandSpec::display redacts it. Apply the same secret handling in
mcp_atlas_command and swe_bench_pro_command, and prevent those commands from
writing the raw key into run_dir/raw/*.sh while preserving their existing
execution behavior.

---

Nitpick comments:
In `@crates/skippy-bench/src/evals/run.rs`:
- Around line 3-102: Split run_eval before the 100-line threshold by extracting
initial RunReport construction into a build_initial_report helper and
non-dry-run execution, metrics, telemetry, and report updates into an
execute_and_finalize helper. Keep run_eval responsible for validation, setup,
command creation, helper orchestration, report serialization, and final success
handling.
- Around line 183-193: Update collect_metrics to report errors from each
evaluator-specific metrics parser instead of silently replacing failures with
EvalMetrics::default(), while preserving duration and client-rate population. In
mcp_atlas_metrics, stop filtering malformed CSV records without diagnostics;
surface or explicitly log each parse failure so undercounted metrics are
observable.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e0c7f538-7cb5-4405-b22a-15d86021b6a7

📥 Commits

Reviewing files that changed from the base of the PR and between 4f25060 and 18ec9e8.

📒 Files selected for processing (12)
  • .agents/skills/skippy-bench/SKILL.md
  • crates/skippy-bench/README.md
  • crates/skippy-bench/src/evals.rs
  • crates/skippy-bench/src/evals/adapters/mcp_atlas.rs
  • crates/skippy-bench/src/evals/adapters/mod.rs
  • crates/skippy-bench/src/evals/adapters/speed_bench.rs
  • crates/skippy-bench/src/evals/adapters/swe_bench_pro.rs
  • crates/skippy-bench/src/evals/adapters/terminal_bench.rs
  • crates/skippy-bench/src/evals/doctor.rs
  • crates/skippy-bench/src/evals/registry.rs
  • crates/skippy-bench/src/evals/run.rs
  • crates/skippy-bench/src/evals/sync.rs

Comment thread crates/skippy-bench/src/evals/adapters/speed_bench.rs
Comment thread crates/skippy-bench/src/evals/adapters/speed_bench.rs Outdated
Comment thread crates/skippy-bench/src/evals/adapters/swe_bench_pro.rs
Comment thread crates/skippy-bench/src/evals/adapters/terminal_bench.rs Outdated
Comment thread crates/skippy-bench/src/evals/run.rs Outdated

@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: 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 `@crates/skippy-bench/src/evals/adapters/templates/mcp_atlas_run.sh`:
- Around line 85-113: Update the service startup logic around port_ready, the
Docker agent environment, and mcp_completion.main so an open port is not treated
as sufficient evidence that the expected service is reusable. Track ownership of
processes started by this script and fail when ports 1984 or 3000 are occupied
by unowned services, or add identity/configuration checks that verify the
running services use this evaluation’s harness, base URL, and API key before
reuse.

In `@crates/skippy-bench/src/evals/adapters/templates/swe_bench_pro_run.sh`:
- Around line 87-104: Update the Docker patching logic around
SWEREX_PIP_INDEX_URL and the generated pip install command so the URL is safely
quoted and credentials are not embedded in the Docker RUN command or generated
source/image history. Pass authenticated index credentials through the supported
Docker build-secret mechanism, while retaining only the non-secret index URL in
the command; update the docker module replacement strings accordingly.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: cbcf9c38-1698-4556-bf69-02f5b5c68a0a

📥 Commits

Reviewing files that changed from the base of the PR and between 18ec9e8 and 896b960.

📒 Files selected for processing (10)
  • .agents/skills/skippy-bench/SKILL.md
  • crates/skippy-bench/README.md
  • crates/skippy-bench/src/evals.rs
  • crates/skippy-bench/src/evals/adapters/mcp_atlas.rs
  • crates/skippy-bench/src/evals/adapters/speed_bench.rs
  • crates/skippy-bench/src/evals/adapters/swe_bench_pro.rs
  • crates/skippy-bench/src/evals/adapters/templates/mcp_atlas_run.sh
  • crates/skippy-bench/src/evals/adapters/templates/swe_bench_pro_run.sh
  • crates/skippy-bench/src/evals/adapters/terminal_bench.rs
  • crates/skippy-bench/src/evals/run.rs
🚧 Files skipped from review as they are similar to previous changes (6)
  • .agents/skills/skippy-bench/SKILL.md
  • crates/skippy-bench/src/evals/adapters/terminal_bench.rs
  • crates/skippy-bench/README.md
  • crates/skippy-bench/src/evals/adapters/speed_bench.rs
  • crates/skippy-bench/src/evals/run.rs
  • crates/skippy-bench/src/evals.rs

Comment on lines +85 to +113
if ! port_ready 1984; then
docker rm -f skippy-bench-mcp-atlas-agent-env >/dev/null 2>&1 || true
docker run --rm \
--name skippy-bench-mcp-atlas-agent-env \
-p 1984:1984 \
--env-file .env \
agent-environment:latest \
> "$RAW_DIR/mcp-agent-env.log" 2>&1 &
agent_started=1
fi
wait_url "MCP-Atlas agent environment" \
"http://localhost:1984/enabled-servers" \
"$RAW_DIR/mcp-agent-env.log"

if ! port_ready 3000; then
(
cd "$COMPLETION_DIR"
LLM_BASE_URL="$BASE_URL" \
LLM_API_KEY="$API_KEY" \
OPENAI_BASE_URL="$BASE_URL" \
OPENAI_API_KEY="$API_KEY" \
uv run python -m mcp_completion.main
) > "$RAW_DIR/mcp-completion.log" 2>&1 &
completion_pid="$!"
completion_started=1
fi
wait_url "MCP-Atlas completion service" \
"http://localhost:3000/docs" \
"$RAW_DIR/mcp-completion.log"

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not silently reuse services merely because their ports are open.

An old or concurrent service can pass these probes while using a different harness, base URL, or API key. Fail when an unowned port is occupied, or verify service identity and configuration before reuse; otherwise evaluation results are not reproducible.

🤖 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 `@crates/skippy-bench/src/evals/adapters/templates/mcp_atlas_run.sh` around
lines 85 - 113, Update the service startup logic around port_ready, the Docker
agent environment, and mcp_completion.main so an open port is not treated as
sufficient evidence that the expected service is reusable. Track ownership of
processes started by this script and fail when ports 1984 or 3000 are occupied
by unowned services, or add identity/configuration checks that verify the
running services use this evaluation’s harness, base URL, and API key before
reuse.

Comment on lines +87 to +104
if [[ "$DEPLOYMENT_TYPE" == "docker" && -n "$SWEREX_PIP_INDEX_URL" ]]; then
.venv/bin/python - "$SWEREX_PIP_INDEX_URL" <<'PY'
import sys
from pathlib import Path

import swerex.deployment.docker as docker

path = Path(docker.__file__)
text = path.read_text()
old = 'f"RUN /root/python3.11/bin/pip3 install --no-cache-dir {{PACKAGE_NAME}}\\n\\n"'
new = (
f'f"RUN /root/python3.11/bin/pip3 install --index-url {{sys.argv[1]}} '
'--no-cache-dir {{PACKAGE_NAME}}\\n\\n"'
)
if old in text:
path.write_text(text.replace(old, new))
elif new not in text:
raise RuntimeError(f"could not patch SWE-ReX Docker pip index in {{path}}")

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.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Do not embed the package-index URL directly into a Docker RUN command.

SWEREX_PIP_INDEX_URL is inserted unquoted, allowing shell metacharacters to alter the build command. Authenticated URLs may also persist credentials in generated source or image history. Pass index credentials through a build secret and safely quote the non-secret URL.

🤖 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 `@crates/skippy-bench/src/evals/adapters/templates/swe_bench_pro_run.sh` around
lines 87 - 104, Update the Docker patching logic around SWEREX_PIP_INDEX_URL and
the generated pip install command so the URL is safely quoted and credentials
are not embedded in the Docker RUN command or generated source/image history.
Pass authenticated index credentials through the supported Docker build-secret
mechanism, while retaining only the non-secret index URL in the command; update
the docker module replacement strings accordingly.

@i386
i386 merged commit bb0b0f7 into main Jul 14, 2026
22 checks passed
@i386
i386 deleted the jd/fix-skippy-eval-review branch July 14, 2026 23:02
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.

1 participant