Skip to content

fix(harbor): numeric verifier metrics, lenient + strict judge rubrics, and interception correctness - #324

Open
rgarcia wants to merge 5 commits into
TIGER-AI-Lab:mainfrom
kernel:hypeship/upstream-harbor-correctness
Open

fix(harbor): numeric verifier metrics, lenient + strict judge rubrics, and interception correctness#324
rgarcia wants to merge 5 commits into
TIGER-AI-Lab:mainfrom
kernel:hypeship/upstream-harbor-correctness

Conversation

@rgarcia

@rgarcia rgarcia commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Summary

The Harbor verifier now reports the same scoring rubrics as the native runner, with machine-safe outputs:

  • reward.json carries only numeric metrics (reward, intercepted, judge_match, judge_match_lenient, judge_match_strict, reward_lenient, reward_strict). Full metadata — including both verdict reasons — stays in clawbench-result.json, so Harbor's reward aggregation never sees booleans, strings, or nulls.
  • Each intercepted request is judged concurrently under two rubrics: the lenient no-explicit-contradiction rubric (the public leaderboard's primary signal) and a conservative strict rubric. The primary reward remains the lenient verdict; strict is reported separately as reward_strict. Both verdicts and reasons are retained.
  • Interception evidence is timestamped: the runtime server records intercepted_at when it captures the request.
  • The Red Cross chapter-finder task now intercepts the actual ZIP lookup API call instead of blocking the chapter-finder landing page.
  • Stock Harbor agents (Claude Code and Codex) are wrapped at install time so ClawBench's existing stop signal ends them cleanly after the final request is recorded, persisting stop timing to /data/agent-stop.json.
  • Verifier step timeout is raised from 180s to 300s to fit two judge calls.

Why

  • Harbor 0.21.0 expects numeric reward metrics; the old reward.json mixed booleans, strings, and nested metadata into one blob.
  • Non-intercepted tasks and judge-call failures previously emitted sparse or non-numeric payloads; both paths now produce well-formed numeric metrics, with failure reasons preserved in clawbench-result.json.
  • Stopping stock agents after interception prevents them from continuing to act or hanging the trial after the scored request has been captured.

Relation to #319

#319 collapses runner/judge_llm.py onto judge.py's transport in the native runner. This PR is independent of that refactor but shares its goal for the Harbor path: the verifier's lenient rubric text mirrors judge_llm.JUDGE_SYSTEM.

The Harbor verifier runs standalone inside each task container via the runtime-server venv where the clawbench package is not installed, so it cannot import the shared prompt today. If a suitable shared home for rubric strings lands, we're happy to follow up and deduplicate.

Tests

  • uv run pytest -q — 208 passed
  • uv run ruff check src/clawbench tests — clean
  • uv run ruff format --check src/clawbench tests — clean
  • uv run --frozen pyright src/clawbench tests — 0 errors
  • Coverage includes numeric metric output, dual-rubric wiring, unknown verdicts, stop-wrapper behavior, and the Red Cross interception regression.

Reproduction (Harbor 0.21.0)

Prerequisites: Docker, uv, agent-provider credentials, judge credentials, and the PurelyMail variables required by ClawBench.

git clone https://github.com/kernel/ClawBench
cd ClawBench
git checkout hypeship/upstream-harbor-correctness
uv sync --frozen

uv run clawbench-harbor-adapt \
  --output-dir ./harbor-datasets/clawbench-v2-smoke \
  --task-ids v2-1134-chapter-finder-redcross \
  --overwrite

cat > .harbor-smoke.env <<EOF
PURELY_MAIL_API_KEY=$PURELY_MAIL_API_KEY
PURELY_MAIL_DOMAIN=$PURELY_MAIL_DOMAIN
OPENROUTER_API_KEY=$OPENROUTER_API_KEY
CLAWBENCH_JUDGE_BASE_URL=https://openrouter.ai/api/v1
CLAWBENCH_JUDGE_API_KEY=$OPENROUTER_API_KEY
CLAWBENCH_JUDGE_MODEL=deepseek/deepseek-v4-pro
CLAWBENCH_JUDGE_API_TYPE=openai-completions
EOF
chmod 600 .harbor-smoke.env

uvx --from harbor==0.21.0 harbor run \
  --path ./harbor-datasets/clawbench-v2-smoke \
  --agent hermes \
  --model deepseek/deepseek-v4-flash \
  --env-file .harbor-smoke.env \
  --jobs-dir ./harbor-jobs \
  --max-retries 0 \
  --delete \
  --yes

trial=$(find ./harbor-jobs -path '*/steps/run/verifier/reward.json' -print -quit)
verifier_dir=$(dirname "$trial")

cat "$verifier_dir/reward.txt"
cat "$verifier_dir/reward.json"
cat "$verifier_dir/clawbench-result.json"

rm -f .harbor-smoke.env

Expected: reward.txt equals reward_lenient; reward.json contains numeric intercepted, reward_lenient, and reward_strict metrics; clawbench-result.json retains both rubric reasons.

Harbor installs Claude Code and Codex before step setup with no hook to
honor ClawBench's /data/.stop-requested signal, so agents kept running
until their own time limit. Wrap the agent executable during setup with a
watcher that forwards SIGINT when the stop file appears, exits cleanly,
and records the stop detection time for evidence.
The chapter-finder task matched the landing-page navigation, so an agent
that only opened find-your-local-chapter.html scored as intercepted
without performing the lookup. Match the region-mappings API call for
the requested ZIP instead.
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