Skip to content

Harden benchmark integrity: mispriced tokens, false-certainty stat, COI + parity disclosure - #23

Closed
macanderson wants to merge 18 commits into
mainfrom
launch-hardening
Closed

Harden benchmark integrity: mispriced tokens, false-certainty stat, COI + parity disclosure#23
macanderson wants to merge 18 commits into
mainfrom
launch-hardening

Conversation

@macanderson

@macanderson macanderson commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Pre-launch adversarial audit of the benchmark's fairness and methodology. A benchmark that ranks the author's own agents against competitors gets the harshest scrutiny in software — these are the things a hostile expert would lead with. All fixes verified: tsc clean, 53/53 vitest, biome clean.

📉 Statistics

  • wilsonInterval(0, n=0) returned [0,0] — false certainty of 0% from zero data. A run where every trial is excluded as agent-error (scoredTrials = 0) would make arena gate --require-significant certify a "100% resolve-rate drop" — the exact case the agent-error category exists to prevent. Now returns [0,1].
  • Paired-bootstrap CI used asymmetric percentile indices (floor(0.025N) / ceil(0.975N) — trims 2.5% below but 2.45% above). Switched to the type-1 empirical quantile ceil(q·N)-1 on both bounds.

💵 Pricing (pricing.json)

  • Opus 4.8 was priced at $15/$75 — 3× the real $5/$25; Haiku 4.5 at $0.8/$4 vs $1/$5. Every computedUsd involving those models was fiction, and any unmatched run against a cheaper competitor inflated the competitor's cost gap ~3×. Corrected to published rates, and added source + asOf + a cache-write-TTL note to each Anthropic entry (the third-party entries already carried "verify before publishing" notes; the wrong ones didn't).

🏷️ Claims vs. reality (README + web)

  • COI disclosure added. METHODOLOGY.md demands publishers disclose "we build Agent A" — but neither README nor the site said Arena's authors build Oxagen and Stella, two of the four agents. Now stated prominently in both.
  • "held-out tests the agent can never see or author" was false for local runs (the verify suites are on disk and public in this repo). Reworded to "copied in only after the agent exits / not in the workspace," with a not-network-sandboxed caveat pointing at Harbor.
  • "Autonomy levels are matched as closely as each CLI allows" was contradicted by the adapters: claude-code/gemini are capped at edits-only while oxagen/stella run one-shot ungated (shell included) — a real edge for the author's agents on test-graded tasks. Disclosed, with the matched-autonomy flags and the full-env-passthrough caveat.

🧭 Deliberately left for an owner decision (documented in the audit report, not silently changed here)

These change measured behavior or need a judgment call:

  • Pin every adapter to a matched autonomy level (edits-only for all, or --dangerously-skip-permissions/--approval-mode yolo for all).
  • Null out tokens/cost on envelope-parse failure instead of recording a real 0 tokens / $0.00 (today one CLI JSON-shape drift silently hands that vendor the cost column).
  • Decouple the agent-error classifier from parsed token counts (currently vendor-asymmetric).
  • Env-allowlist spawned agents (strip PWD, don't hand every CLI every vendor's keys).

Part of a two-repo launch audit (Arena + Stella); the companion report ranks the top 25 pitfalls across both.

macanderson and others added 17 commits July 12, 2026 13:13
Adapters for Claude Code, Gemini CLI, Oxagen, Stella (+ mock for CI);
held-out verification the agent can never author; normalized token and
uniform cost accounting; matched-config enforcement with unmatched-model
warnings; agent-error quarantine; Wilson/McNemar/seeded-bootstrap stats;
per-run manifests, transcripts, diffs, and reproduce commands.
Repo moved to github.com/oxageninc/arena. Updates the package name,
repository URL, README title + clone command, harness self-name in the run
manifest and CLI banner, and the Stella link (now oxageninc/stella).
Adds harbor/ — a Python Harbor adapter (BaseInstalledAgent) that runs your
coding agent through Harbor's containerized SWE-bench / Terminal-Bench verifier
head-to-head against the agents Harbor already ships (Claude Code, Gemini,
Codex, Cursor, Aider, ...), all scored by the same repo-native test suite.

- ByoAgent: wire up your own agent from a TOML/JSON spec — no Python.
- OxagenAgent / StellaAgent: specs for agents Harbor lacks; worked examples.
- Spec-driven install (binary upload or script) + one-shot run + best-effort
  token/cost parsing with the same cache-aware normalization as the TS side.
- A non-zero agent exit never aborts scoring — the verifier decides pass/fail.
- Pure logic (spec/metrics/command) is Harbor-free and unit-tested; agent tests
  run against real Harbor 0.6.1 (39 tests green) and verify Harbor's factory
  loads each agent by import path.
- Docs + run.sh + a CI job (pip install -e .; pytest).

Main README + METHODOLOGY now point at this adapter as the scale-up path.
Harbor requires Python >=3.12, so the CI job used 3.11 and could not resolve
harbor. Bump CI to 3.12, set requires-python accordingly, and pin the dep to
the tested 0.6.x line.
Snapshot a run's per-agent metrics as a committed baseline, then fail CI when
a later run regresses:

- arena baseline save <runDir> [--agent A] -> arena-baseline.json
- arena baseline show
- arena gate <runDir> [--require-significant] [--allow-task-mismatch] [...]
  exits non-zero on regression.

Checks per agent: resolve-rate drop (strict, or only when it clears 95% CI
noise with --require-significant), median token/cost increase past thresholds,
wall-clock (reported; enforced with --speed-increase). Refuses to compare
across different task sets unless --allow-task-mismatch. Thresholds via flags
or arena-gate.json.

src/summary.ts factors the per-agent aggregation into one source of truth
shared by report + baseline + gate. 14 new unit tests (51 total); example CI
workflow + gate config under examples/. README + METHODOLOGY document it.
…, dependency review

Quality:
- Add Biome (lint + format), pinned devDep, as a CI gate (pnpm lint).
  Normalized formatting across src/test; removed dead code Biome caught
  (unused pricing local in orchestrator; unused test locals).

Supply chain / security (standard for popular OSS repos):
- .github/dependabot.yml — weekly npm + pip + github-actions updates.
- dependency-review workflow — blocks PRs adding high-severity vulns.
- OpenSSF Scorecard workflow — security-posture scoring to the Security tab.
- SECURITY.md — private vulnerability reporting policy.
- CODEOWNERS — routes review to the maintainer.
- Least-privilege 'permissions: contents: read' on CI.

typecheck + 51 tests + biome ci all green.
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.9.5 to 26.1.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 26.1.1
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Updates the requirements on [harbor](https://github.com/harbor-framework/harbor-cookbook) to permit the latest version.
- [Commits](https://github.com/harbor-framework/harbor-cookbook/commits)

---
updated-dependencies:
- dependency-name: harbor
  dependency-version: 0.19.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mac Anderson <mac@oxagen.sh>
Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.9.3 to 7.0.2.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Commits](https://github.com/microsoft/TypeScript/commits)

---
updated-dependencies:
- dependency-name: typescript
  dependency-version: 7.0.2
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mac Anderson <mac@oxagen.sh>
Bumps the actions group with 7 updates:

| Package | From | To |
| --- | --- | --- |
| [actions/checkout](https://github.com/actions/checkout) | `4` | `7` |
| [pnpm/action-setup](https://github.com/pnpm/action-setup) | `4` | `6` |
| [actions/setup-node](https://github.com/actions/setup-node) | `4` | `6` |
| [actions/setup-python](https://github.com/actions/setup-python) | `5` | `6` |
| [actions/dependency-review-action](https://github.com/actions/dependency-review-action) | `4` | `5` |
| [ossf/scorecard-action](https://github.com/ossf/scorecard-action) | `2.4.0` | `2.4.3` |
| [github/codeql-action](https://github.com/github/codeql-action) | `3` | `4` |


Updates `actions/checkout` from 4 to 7
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@v4...v7)

Updates `pnpm/action-setup` from 4 to 6
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](pnpm/action-setup@v4...v6)

Updates `actions/setup-node` from 4 to 6
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](actions/setup-node@v4...v6)

Updates `actions/setup-python` from 5 to 6
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](actions/setup-python@v5...v6)

Updates `actions/dependency-review-action` from 4 to 5
- [Release notes](https://github.com/actions/dependency-review-action/releases)
- [Commits](actions/dependency-review-action@v4...v5)

Updates `ossf/scorecard-action` from 2.4.0 to 2.4.3
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](ossf/scorecard-action@v2.4.0...v2.4.3)

Updates `github/codeql-action` from 3 to 4
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](github/codeql-action@v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: pnpm/action-setup
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/setup-python
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: actions/dependency-review-action
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
- dependency-name: ossf/scorecard-action
  dependency-version: 2.4.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions
- dependency-name: github/codeql-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mac Anderson <mac@oxagen.sh>
* chore(deps-dev): Bump vitest from 2.1.9 to 3.2.6

Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 2.1.9 to 3.2.6.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v3.2.6/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 3.2.6
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix

* fix

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mac Anderson <mac@oxagen.sh>
Replaces #18 — the Dependabot branch accumulated lockfile conflicts after
the vitest-3.x and typescript-7 merges landed on main. This reapplies the
same two patch bumps (biome 2.5.2->2.5.4, tsx 4.19.2->4.23.1) on a clean
base with a freshly-regenerated lockfile.
…end (#20)

Harness (TypeScript):
- parse: brace-matched envelope scan so pretty-printed JSON (gemini-cli)
  parses; line-based JSONL scan kept as the first pass
- adapters/base: kill the whole process group on timeout (agents spawn
  subprocesses that held the stdio pipes open past the cap); settle on
  "exit" with a drain grace; cache version (was two spawns per trial)
- orchestrator: drop dead loadPricing call and module-level pricing
  cache (load once, pass down); timeout now takes precedence over a
  post-kill test pass; pass taskDir through AdapterRunArgs instead of
  the MockAdapter.currentTaskDir mutable static
- workspace: async fs/child_process APIs (no event-loop blocking inside
  the async run loop); disable commit.gpgsign in seeded repos
- report: aggregate via perAgentSummary (was duplicated inline math that
  contradicted summary.ts's single-source-of-truth contract); no more
  NaN cells when an agent has zero scored trials
- cli: validate numeric flags instead of silently running with NaN
- METHODOLOGY: document timeout precedence

Harbor adapter (Python):
- remove dead tomli fallback (package requires Python >= 3.12)
- frozen dataclasses for specs and parsed metrics; validate metrics.kind
- collections.abc.Mapping; class-level _agent_output/_spec defaults;
  tolerate float ARENA_TIMEOUT values
- add ruff (lint config in pyproject, run in CI); fix all findings

Branding + site:
- black & white stadium mark (nested geometric stadium shapes), IBM Plex
  type, all-neutral palette; static site under web/ for arena.oxagen.sh
- logo assets in assets/, logo in README
The arena and stella repositories moved from the oxageninc org to the
macanderson account; point all badges, links, and package metadata at
the new home.
…ch paper (#22)

* fix: verification integrity, metric honesty, and CLI hardening

Highest-severity first:
- Timeouts kill the agent's whole process tree (POSIX process groups);
  trials can no longer hang on pipes held by orphaned grandchildren,
  and survivors can no longer tamper with held-out verification.
- Zero-token (unparseable-envelope) trials are excluded from token/cost
  medians and deltas instead of dragging them toward zero past the gate.
- claude-code preserves full model ids (no floating "sonnet" alias), so
  version pinning, matchedModels, and pricing lookups hold.
- Gemini normalization counts thoughts (reasoning) and tool tokens.
- Pretty-printed JSON envelopes parse (TS + Harbor Python mirror).
- Per-trial error containment + incremental results.json; wall clock
  measures spawn-to-exit only; git-diff failure is "unknown", never
  "empty"; report table shares perAgentSummary with the gate (no NaN).
- CLI: -o short flag (as documented), strict numeric flags, unknown
  verify ids error, duplicate agent specs rejected, typo'd gate
  thresholds error instead of silently disabling the check.
- Cost with unpriced cache writes is null, never guessed.
- Harbor: float-tolerant ARENA_TIMEOUT (never silently unbounded),
  loud empty-{budget} failure, metrics.kind validated at load.


* feat(site): arena.oxagen.sh landing page + Agent Benchmark Protocol draft

Static site (site/) for arena.oxagen.sh: landing page with the
matched-model scoreboard, and the ABP design spec. Spec source lives at
docs/agent-benchmark-protocol.md: four interchange schemas (task, run,
trace, verdict), the live GitHub-issue task pipeline with golden traces,
smallest-normalized-diff scoring, conformance levels, and roadmap.


* docs: The State of Agent Benchmarking (paper) + site rendering

Research paper surveying the July 2026 agent-benchmark landscape through
the engine-vs-model lens: 28 cited references, gap analysis of four
capabilities (matched-model isolation, efficiency grading, statistical
CI gating, live tasks with golden traces), COI disclosed. Markdown
source in docs/, rendered at arena.oxagen.sh/paper/. README links the
site, paper, and spec.


* docs: architecture map (module graph, trial data flow, contracts)
…t, disclose COI + parity gaps

Pre-launch fairness/methodology audit fixes for the benchmark.

Statistics
- wilsonInterval(0, n=0) returned [0,0] — false certainty of 0% from zero data.
  A run with zero scored trials (e.g. every trial excluded as agent-error) would
  make `arena gate --require-significant` certify a "100% resolve-rate drop". Now
  returns [0,1] (maximal uncertainty); test updated.
- Paired-bootstrap CI used floor(0.025N)/ceil(0.975N) — asymmetric tails
  (trims 2.5% below, 2.45% above). Switched to the type-1 empirical quantile
  (ceil(q·N)-1) on both bounds.

Pricing
- pricing.json priced Anthropic Opus 4.8 at $15/$75 — 3x the real $5/$25 — and
  Haiku 4.5 at $0.8/$4 vs $1/$5. Every computed cost involving those models (and
  any unmatched run against a cheaper competitor) was fiction. Corrected to
  published rates; added source URL + asOf date + a cache-write-TTL note to each
  Anthropic entry, matching the "verify before publishing" discipline the
  third-party entries already carried.

Claims (README + web) — disclose what the code actually does
- Added a prominent conflict-of-interest note: Arena is built by the team behind
  Oxagen and Stella, two of the agents it benchmarks. METHODOLOGY already
  required this of publishers; the project now meets its own bar.
- "held-out tests the agent can never see or author" was false for local runs
  (the verify suites sit on disk and are public in this repo). Reworded to
  "copied in only after the agent exits / not in the workspace", with an explicit
  not-network-sandboxed caveat pointing at Harbor.
- "Autonomy levels are matched as closely as each CLI allows" was contradicted by
  the adapters: claude-code/gemini are capped at edits-only while oxagen/stella
  run one-shot ungated (shell included) — an advantage for the author's agents on
  test-graded tasks. Disclosed the asymmetry and the matched-autonomy flags, and
  noted the full-env-passthrough (every CLI sees every vendor's keys).

Not changed here (needs an owner decision, see the audit report): pinning the
adapters to a matched autonomy level, nulling tokens/cost on envelope-parse
failure, decoupling the agent-error classifier from parsed token counts, and
env-allowlisting spawned agents.

@sourcery-ai sourcery-ai 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.

Sorry @macanderson, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@macanderson
macanderson marked this pull request as ready for review July 30, 2026 04:08
@macanderson
macanderson enabled auto-merge (squash) July 30, 2026 04:08
@macanderson
macanderson disabled auto-merge July 30, 2026 04:08
@macanderson
macanderson enabled auto-merge (squash) July 30, 2026 04:09
auto-merge was automatically disabled July 30, 2026 21:58

Pull request was closed

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