docs: add benchmark harness spec, ADRs, and task breakdown
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:
26
.claude/adr/0014-bench-cost-equivalent-token-metric.md
Normal file
26
.claude/adr/0014-bench-cost-equivalent-token-metric.md
Normal 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.
|
||||
22
.claude/adr/0015-bench-single-user-seed.md
Normal file
22
.claude/adr/0015-bench-single-user-seed.md
Normal 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.
|
||||
21
.claude/adr/0016-bench-guard-based-tool-isolation.md
Normal file
21
.claude/adr/0016-bench-guard-based-tool-isolation.md
Normal 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.
|
||||
Reference in New Issue
Block a user