docs: add benchmark harness spec, ADRs, and task breakdown
All checks were successful
CI / test (pull_request) Successful in 50s
CI / test (push) Successful in 49s

Add the benchmark-harness spec, three supporting ADRs (cost-equivalent
token metric, single-user seed, guard-based tool isolation), and the
0022-0030 task breakdown that slices the harness into foundational
seams, an integrating single-cell runner, and the reporting layer.
This commit was merged in pull request #22.
This commit is contained in:
2026-07-15 10:04:28 -04:00
parent b5955cd7b8
commit d445b2bd2b
13 changed files with 377 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
# Cost-equivalent tokens as the benchmark's headline metric
The benchmark compares how much each arm costs to drive.
The maintainer runs on a Claude subscription with a fixed weekly token allowance, so the scarce resource is token consumption against that allowance, not dollars.
The question is how to reduce each run's four token components — fresh input, cache-creation, cache-read, and output — into a single headline number that reflects weekly-budget burn.
Research into Anthropic's documentation established that the exact unit and per-component weighting of the subscription weekly limit are not publicly documented.
The one anchoring signal is that overage past the included allowance is billed at standard API rates, which points toward cost-weighted accounting rather than a flat token count.
## Considered Options
**Raw summed tokens as headline** (rejected) — Summing all four components at 1× is transparent and assumption-free, but cache-read routinely dominates the total, and Anthropic's API prices cache-reads at roughly a tenth of fresh input.
A raw sum therefore overstates the burn of arms whose context is largely cached (notably the eager-schema MCP arm) by up to an order of magnitude, which would misrank the arms on the very axis the benchmark exists to measure.
**Imputed dollars as headline** (rejected) — The runtime already reports an imputed cost that folds in every component at the correct weights.
It is an accurate comparative number, but it is expressed in a unit the maintainer does not spend; on a subscription no dollars leave the account, and the mental model is weekly tokens.
**Cost-equivalent tokens as headline** (chosen) — Weight the four components by Anthropic's published API pricing ratios (fresh input 1×, cache-write 1.25× or 2× by TTL, cache-read 0.1×, output 5×) and express the result as a token count.
This is tokens — the maintainer's unit — weighted the way their budget most plausibly burns, and it is the same ranking as the imputed dollar figure.
## Consequences
- The headline is cost-equivalent tokens; the raw summed tokens and the full four-component breakdown are recorded alongside every run, so the data can be re-weighted without re-running if the subscription's real accounting is ever documented.
- Imputed dollars are retained as a de-emphasized secondary column, portable for readers who are on the API rather than a subscription.
- The weighting is an explicit, documented assumption grounded in the overage-pricing signal, not a measured fact; an optional later validation could pin the real weekly weighting empirically by burning a known token mix.
- The auxiliary small model invoked by the runtime is counted rather than suppressed, since it is real consumption against the same allowance.

View File

@@ -0,0 +1,22 @@
# Single-user seed and its constraints on the task surface
The benchmark seeds a throwaway repository to a known state before each trial and scores tasks against that ground truth.
Seeding realistic author and assignee variety would require several Gitea accounts.
The maintainer prefers to run the benchmark under their single existing account rather than provision additional accounts.
## Considered Options
**Provision throwaway collaborator accounts** (rejected) — Multiple accounts would restore the author and assignee dimensions and enable non-self pull-request approvals, but they add account lifecycle and credential handling that the maintainer explicitly declined for this benchmark.
**Keep multi-user tasks and let arms fail** (rejected) — Retaining tasks that need distinct authors or a non-self reviewer would make those tasks impossible under one account for every arm uniformly, producing no comparative signal while consuming budget.
**Single-user seed with a redesigned surface** (chosen) — All seed content is authored by the one account, and the discriminating dimensions become label, state, assignee presence (assigned-to-self versus unassigned), and title keyword instead of author.
Tasks that assumed author or assignee variety are recast onto these axes: reassignment becomes assign-to-self or unassign, and author-filtered bulk mutation becomes a filter on assignee presence.
## Consequences
- Author filtering leaves the scored suite; it carries little signal with one author anyway.
- Review tasks in the scored suite use comment-type reviews, which a user may leave on their own pull request.
Whether the host permits self-approval and self-request-changes is verified during implementation; if permitted, those two tasks are promoted from comment reviews to approve and request-changes, otherwise approve and request-changes move to the bonus table as two-account scenarios.
- Non-self approval, distinct-author filtering, and distinct-assignee tasks are out of scope for the scored suite and belong to the multi-account bonus scenarios.
- The seed stays small and fully deterministic, which keeps the full-state diff used for collateral-damage checking cheap to compute and reason about.

View File

@@ -0,0 +1,21 @@
# Guard-based tool isolation instead of containers
The benchmark's validity depends on each arm's agent reaching exactly one tool.
If the tea-arm agent could quietly call `curl` or `gitea-axi`, the comparison would be meaningless.
The benchmark machine has no container runtime available, so per-arm operating-system sandboxing is not an option.
## Considered Options
**Container per arm** (rejected) — A container image carrying only the arm's binary would give hard, kernel-level isolation, but it requires installing and depending on a container runtime the maintainer does not have and declined to add for this benchmark.
**Curated PATH alone** (rejected) — Prepending a directory that exposes only the allowed binary is convenient but leaky: an agent can invoke another tool by absolute path, or reach the API through a language interpreter's fetch, bypassing PATH entirely.
**Guard callback as the authority** (chosen) — A callback inspects every proposed shell command and permits only the one binary allow-listed for the active arm plus harmless utilities, denying foreign binaries, absolute-path evasions, and interpreter-based fetch attempts.
A curated per-arm PATH backs it as a convenience layer, and the gitea-mcp arm disables the shell tool entirely and attaches only the MCP tools, giving that arm no leakage surface at all.
## Consequences
- The guard, not the PATH, is authoritative; the PATH is defense in depth.
- A blocked attempt is left in the transcript and counts as realistic wasted effort, reflecting an agent fumbling with a tool that cannot do the job; blocked calls are never silently retried or discarded.
- Every command is logged, and a post-run audit asserts no foreign tool was reached; a detected leak flags the trial invalid rather than letting it be scored.
- Isolation strength rests on the completeness of the guard's deny rules, so the guard is one of the harness's primary unit-tested seams, covering absolute-path and interpreter-fetch evasions explicitly.