`detail.prompt_tokens`; its reading: "Cost fell 17% (62% of prompt tokens were cache hits)").
### Measured costs
| Measurement | Spend | Record |
| --- | --- | --- |
| Plane increment 2: verify a, b and the tie-break on the 46-candidate validation set | $0.0205 per candidate over the 46 including the recorded triage, against the $0.022 reference (`gate.cost_per_candidate_with_recorded_triage_usd`); totals: plane $0.8567, recorded triage $0.0872, with triage $0.9439, reference $1.0123 (`detail.usd`); the tie-break asked 10 disputed candidates and flipped 5 to agreed | `benchmarks/independent/plane-increment-2.json` |
| Plane increment 1: verify a and b alone | 357 calls, 54 hunts at 5.37 turns per hunt, $0.7471 plus $0.0872 recorded triage (`detail`) | `benchmarks/independent/plane-increment-1.json` |
| Decision engine, injection slice: evaluation at k = 5 | $0.003215 per candidate (`spend.cost_per_candidate_evaluate_usd`); metered at list price: canary $0.010158, compile $0.429194, a first compile attempt that failed with HTTP 400 $0.049047, evaluate $0.353626, smoke $0.070812, in all $0.912838, plus $0.003976 of embeddings; 8,601,840 of 9,936,337 prompt tokens were cache hits (`spend`) | `benchmarks/measurements/2026-10-01-decision-engine-injection-slice/record.json` |
| Decision engine, slice 2 (six families): compile, canary and evaluation per family | $2.8832 metered at list price for DeepSeek under an $8 ceiling (`spend.metered_usd_deepseek_total`), $0.000868 of embeddings; $0.0027 to $0.0032 per evaluated candidate (`families.<family>.spend.cost_per_candidate_usd`); 25,633,349 of 29,779,297 prompt tokens were cache hits (`spend.deepseek_tokens`); balance $17.73 to $16.73 | `benchmarks/measurements/2026-10-02-decision-engine-slice-2/record.json` |
| Decision engine harvest: `verify` part | $2.5373 over 1,961 calls, 474 tasks done, 10,921,167 prompt tokens of which 6,275,060 cache hits, 306,941 output tokens, task budgets summing to $8.624 under a $10 ceiling (`verify`) | `benchmarks/measurements/2026-10-01-decision-engine-harvest/record.json` |
| Decision engine harvest: `roles` part | $1.4036 over 1,034 calls, 151 tasks done, 2,398,669 prompt tokens of which 329,600 cache hits, 370,155 output tokens, task budgets summing to $4.917 under a $10 ceiling (`roles`) | same record |
The increment-2 record's note on the two denominators: "the reference divides by the 46
candidates before triage; on that basis the plane is 7% cheaper, on the 43 after triage it is
0.2% under".
!!! note "The meter prices at list; the account moved less"
The attribution table prices every call at the Model's list price
(`plane/models/deepseek-flash.yaml`). The harvest record: "Spend is the plane's attribution
table (`ousast plane status`, task meters priced at plane/models/deepseek-flash.yaml); the
DeepSeek account moved less (balance below)", with the balance at $19.63 before, $18.75
after `verify` and $18.23 after `roles`. The injection-slice record names the ratio: "the
provider charged ~1/3 of the list-price meter (balance moved $0.30 for $0.91 metered):
DeepSeek's off-peak discount window, presumably; the meter prices at list"
(`spend.balance_note`, balance $18.2 to $17.9). Budgets and gates are set against the
meter, never against the balance.
### Not done yet
- **No model-side token budget in ax itself.** The plane's requirements state what ax does
not yet carry: "task dependencies, artifacts, token budgets (on ax's roadmap), a DeepSeek
provider"; the thin `Run` layer carries them and dissolves into ax as ax gains them. Until
then the ceiling lives in the metered client, not in the executor.
- **Triage is applied, not run.** The plane has no triage task; it filters by the recorded
triage and adds that recording's cost as its own line. A triage task is planned as a later
specification.
- **`k` and the contrast examples are not knobs.** `k` is a compiled setting in {1, 3, 5}
(`learn/compile.toml`, "k and lam remain A/B variants"), changed only through the decision
engine's A/B experiments, its requirement that "changes to prompts, models, pass counts, rule
sets and features [are] compared by controlled experiments, so that nothing is adopted on one
run's number" (Requirement 4 of its specification). The retrieval cap of at most two
contrast examples from other families is a module constant (`learn/retrieve.py`,
`CONTRAST = 2`), a maintainer decision, not an experiment variant yet.
## B. Development: the maintainers' own sessions
```mermaid
flowchart LR
session["agentic coding session"] --> read["Read of a whole file"]
read --> guard{"read_guard: over 350 lines?"}
guard -- "no" --> allow["read proceeds"]
guard -- "yes" --> deny["denied: read a range or ask the bulk reader"]
deny --> bulk["bulk_read.py: cheap model answers with path:line under --max-usd"]
session --> worktree["subagent in a worktree: its tool output never enters the main context"]
session --> files["scripts in files, terse output"]
transcript["session transcript .jsonl"] --> report["token_report.py: share per content kind"]
report --> record["counts-only dev_token_report in the measurement record"]
```
### The measurement: tool I/O dominates
`benchmarks/dev/token_report.py` reads a Claude Code session transcript (`.jsonl`; without an
argument, the newest under `~/.claude/projects/`) and reports, per content kind, characters and
share: `tool_use_input` (the tool call's input as JSON), `tool_result`, `thinking`,
`assistant:text`, `user:text`, plus the tool-call count and the top five tools. Tokens are
approximated at four characters each. It prints to stdout and writes nothing; what gets
committed is the counts-only summary. The one in `benchmarks/independent/plane-increment-1.json`
(`dev_token_report`, for "the whole development session (c09e30b2), not the increment alone"):