Skip to content

Feat/lever protocol and ledger - #26

Open
contactacefleetdev wants to merge 8 commits into
mainfrom
feat/lever-protocol-and-ledger
Open

Feat/lever protocol and ledger#26
contactacefleetdev wants to merge 8 commits into
mainfrom
feat/lever-protocol-and-ledger

Conversation

@contactacefleetdev

@contactacefleetdev contactacefleetdev commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Description

Turns the lever rail from a simulation into something that measures, then makes the
dashboard say where every number came from.

Stacked on the two commits already on this branch (9caa5e0, aa6b79f), which
defined the lever protocol, the priced ledger, and the rail wiring.

What this adds

Levers now run for real on proxied turns. levers/shadow.py adapts a
/v1/messages body into the same typed model transcripts produce, builds the
counterfactual copy-on-write, and prices the delta against the turn's own billed
buckets. It never sees the relayed bytes — only the throwaway parsed copy the
route already makes — and runs after the response on a worker thread, so it costs
the developer's turn nothing.

An exact counter, built from the credential in flight. Under no_key: true
the OAuth token the proxy relays is the only credential that can reach
/v1/messages/count_tokens. There is no preflight probe: the first count settles
whether the endpoint accepts a subscription token, a 401/403 latches and keeps the
reason so the rail can say why rather than going blank, and a 429 deliberately
does not latch.

Results persist. lever_turns is a sibling table to turns — a counterfactual
and a real charge must not share a record. Aggregated per lever and never totalled.
Third-party diagnostics are scrubbed to numeric values only, so a lever logging a
matched command cannot put session text in the database. Existing databases are
migrated.

The re-read rate is instrumented — the cost side of a truncation, and the one
input the ledger cannot derive. Break-even sits at a 41% re-read rate, so the
difference between 10% and 50% is +$468 and −$118 on the same corpus. Measured in
shadow without changing a prompt: a request carries the whole conversation, so the
body already shows whether the agent went back to a target a lever proposed to cut.

Measured on this machine's 144 transcripts: 20.0% all tools, 0.1% Bash only.
The distinction that decides it is pagination — a later Read at a higher offset
fetches fresh bytes and would have happened anyway. Counting it as damage takes the
figure from 20.0% to 28.3%, across the break-even line, for behaviour the lever did
not cause.

Grounded references beside each metric. Every tile carries a comparison and its
provenance: SELF (your own distribution), PEER (another agent, same machine,
same window), PUBLISHED (a provider constant with the source URL and as_of
already in pricing.py), MEASURED (derived here, derivation attached), or
NO REF.

That last one matters. There is no verifiable figure for the quality-optimal
conversation-turn count, so it renders as NO REF with what establishing one would
take — a replay eval — rather than an invented number. Same standard
data/model_market/benchmarks.yaml already holds, where an empty source means
nobody has pointed at the leaderboard yet.

An off/shadow/prod preview. Annotates every headline metric with its
counterfactual, in that metric's own unit, attributed to the skill producing it:

metric shadow via
tokens_in −365.5M tok (−8.4%) bash truncate
list_price_cost −$181.72 (−5.9%) bash truncate
cost_per_turn −$0.0035 (−5.9%) bash truncate
cost_per_commit −$0.4432 (−5.9%) bash truncate

The two rates differ on purpose. Volume falls 8.4% while cost falls 5.9%: the
removed tokens are disproportionately cache reads at 0.1×, so a saved token is
worth less than an average one. One percentage across both would overstate the
money by ~40%.

Four tiles render NO CHANGE with the reason — tokens_out (the model generates
these; removing prompt content does not shorten a reply), commits_per_session,
api_requests and conversation_turns. A blank slot and "this cannot move" look
identical to a reader and are different claims.

prod previews only. A lever is enabled in ~/.ace/config.json and nowhere else;
a dashboard that could switch one on from a hover is one that can silently start
rewriting prompts.

Two pre-existing bugs fixed on the way

  • usage_to_request_log imported ace.observability.telemetry, which does not
    exist in this distribution. It raised on every turn into the except that
    protects the response, so ~/.ace/telemetry.db stayed empty and the dashboard
    reported zero spend on a working sidecar.
  • rail_payload priced with a ctx leaked from a loop, attributing one lever's
    settings to every other lever's pricing.

Testing

98 tests, 46 of them new. No live provider call anywhere — the upstream relay and
the counting endpoint are both driven through httpx.MockTransport.

Covered specifically: the fidelity invariant (a lever stripping 96% of the prompt
still leaves the upstream bytes identical), credential latching, the pagination
distinction in the re-read instrument, the numbers-only store invariant, and
migration of an older database.

Notes for review

  • Merged origin/main in fcdde56; _nav_js from 53d3281 survives and is
    emitted. Suite green after the merge.
  • Companion branch feat/ace-skills-shared-package in ai-compute-efficiency
    provides levers that register against this contract. Neither branch needs the
    other to build.
  • feat/code-quality-metrics contains an older duplicate of some of these
    files, swept in by a parallel session. If that lands first expect conflicts; the
    version here is newer.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update

Verification

Describe the tests and checks performed to verify changes:

  • pytest passes cleanly.
  • python -m build and twine check dist/* pass.
  • E2E test script scripts/e2e_test.py passes.

Checklist

  • My code follows the code style of this project.
  • I have updated documentation where necessary.
  • I have updated CHANGELOG.md with my changes.

…BYTES_PER_TOKEN

Adds `ace.sidecar.levers`: the public contract optimization modules are written
against, containing no optimizations itself. Implementations ship separately and
register through the `ace.sidecar.levers` entry-point group, so this repository
stays a measurement product that gains levers when a package providing them is
installed, and an absent lever package is the ordinary case rather than an error.

Three properties the design turns on:

* One lever, every agent. Levers read the corpus shape `_scan`,
  `_scan_antigravity` and `_scan_codex` already agree on, never a provider's wire
  format. Supporting a fourth coding agent is a scanner, not a lever rewrite.
* Measurement is universal, actuation is not. Scoring runs off transcripts and so
  works for every agent the sidecar can read. Rewriting bytes needs a write path
  and only some agents have one; `Lever.requires_content` declares which half a
  lever needs and the registry refuses the mismatch rather than degrading.
* Levers propose, the ledger prices. No lever returns a dollar figure. Pricing
  happens once, where the tokenizer and rate catalog live, which keeps a saving
  auditable and keeps provider-specific cache economics out of a lever that is
  meant to be provider-neutral.

The ledger prices nothing it cannot count exactly: without the text in hand it
reports `unmeasurable` rather than deriving tokens from a byte ratio. It nets the
cache-write penalty against gross saving and reports a break-even turn, because an
edit to content the cache has already stored invalidates the prefix from that
point and the next turn re-writes the remainder at a premium. On a 10-turn fixture
the same result trimmed at creation nets +$0.024, while expiring it at turn 5 nets
-$0.019 and needs 17 turns to repay itself; a gross-savings-only ledger reports
the second as a win. `LedgerReport` ranks and deliberately exposes no total,
because levers scored alone can claim the same bytes.

Also corrects BYTES_PER_TOKEN, 4.0 -> 2.8. Against 4,512 text-only single-call
results from the local corpus the observed characters-per-token distribution is
p10 1.51 / median 2.16 / p90 2.64 / p95 2.82 / p99 4.34 — 4.0 sat at the 99th
percentile, the prose figure applied to code, JSON, logs and diffs. The value
chosen is the upper tail rather than the median because the derivation is
contaminated in the direction that lowers the ratio, and because `score` divides
by this constant, so the correction raises every rail figure by ~1.43x. Left
alongside it is `_check_image_bridge`, which warns once if
`insights._CHARS_PER_TOKEN` ever stops aliasing this name: the two are one
quantity — `_measure` multiplies an image's token count by it and `score` divides
by it — so images round-trip only while they agree, and are silently mispriced by
their ratio when they do not.
@contactacefleetdev
contactacefleetdev force-pushed the feat/lever-protocol-and-ledger branch from 92a9a20 to 9caa5e0 Compare August 27, 2026 18:51
contactacefleetdev and others added 7 commits August 27, 2026 11:55
Puts the measured half of the lever rail on the page beside the simulated half,
and — more importantly — makes the page say which of the two it is showing.

`levers/rail.py` sits between the scanner and the renderer so neither has to know
about levers: `insights._build_payload` calls `rail_payload` and passes the result
through, `dashboard_render` reads it. The import is lazy and wrapped, because
discovery loads third-party distributions and nothing a stranger's package does at
import time may take this dashboard down; a failure there costs the live column and
leaves every measured figure on the page intact.

Five states, only one of which may print a dollar figure:

  no_package   nothing registers against the entry-point group — the ordinary
               state for the OSS sidecar on its own
  all_off      levers installed, all resolving to `off`; presence is not consent
  no_counter   no exact token counter, so the ledger priced nothing. A byte-ratio
               fallback would produce a number here, which is why there is none
  no_content   levers ran, but the scan carries sizes and hashes rather than text
  measured     real edits, exactly counted, net of the cache-write penalty

`no_content` is the state that matters for this page. The transcript scan holds no
tool-result bytes by design, so a lever can be installed, enabled, and still price
nothing here: `measured` is unreachable from transcripts alone and needs the proxy
or a hook to supply the text. That is a property of the measurement path rather
than a bug, and it is reported distinctly from `no_counter` because the two look
identical on a page and mean opposite things about whether a lever is worth
enabling.

The live block renders separately from the headroom rows rather than merging into
them. A headroom row is a byte-turn simulation of what a lever would be worth; a
live row is a lever that ran and was priced exactly. Merging them into one number
is the most misleading thing this page could do. A live row can also read negative
— an edit to already-cached content pays a re-write premium the saving has to earn
back — and showing that is the point.

`_lever_note` now reads the actual state instead of asserting "none are wired",
which was a hardcoded truth of Phase 0 and stops being true the moment a lever
package is installed.
…esult

Completes the chain the ledger was built for. The rail could price a lever
but had nothing real to price: transcripts carry hashes and sizes, and an
exact token delta needs the bytes.

- counter.py: an exact counter built from the credential in flight. Under
  `no_key: true` the OAuth token the proxy relays is the only credential
  that can reach /v1/messages/count_tokens. No preflight probe -- the first
  count settles it; a 401/403 latches and keeps the reason so the rail can
  say why rather than going blank. A 429 deliberately does not latch.

- shadow.py: adapts a /v1/messages body to the same typed model transcripts
  produce, builds the counterfactual copy-on-write, and prices the delta
  against the turn's own billed buckets, newest first. Runs after the
  response on a worker thread; never sees the relayed bytes.

- lever_turns: a sibling table to `turns`. A counterfactual and a real
  charge must not share a record. Per-lever, never totalled. Third-party
  diagnostics are scrubbed to numeric values only.

- the rail READS the store rather than recomputing, refreshed outside the
  payload cache so the one live number is not frozen.

Rendering folds into the existing rail as rows, not a second panel: one
scoreboard a reader can compare, with measured rows tagged and scaled
separately so they can never be added to the simulated ones.

Also fixes two pre-existing bugs found on the way:
- usage_to_request_log imported ace.observability.telemetry, absent from
  this distribution. It raised on every turn into the except that protects
  the response, so ~/.ace/telemetry.db was silently empty and the dashboard
  reported zero spend on a working sidecar.
- rail_payload priced with a ctx leaked from a loop, attributing one
  lever's settings to every other lever's pricing.
A bar has to be scaled against something and both options were wrong.
Scaled against the simulated rows, a measured $0.75 renders as a 240th of
a simulated $179 -- but those are different claims, not a ratio. Scaled
within the measured group, which is what shipped, the largest measured
lever drew FULL WIDTH directly beneath the largest simulated one, so a
$0.75 measurement was visually indistinguishable from $179 of headroom.

The dollar figure and the MEASURED tag carry the row. Nothing is implied
by length.
A truncation's saving is countable and this codebase already counts it. Its
COST is a re-read that may never happen, and reporting the saving alone
quotes a gross figure as if it were net. That input was the one number the
ledger could not derive, and it decided the whole lever: break-even sits at
a 41% re-read rate, so the difference between 10% and 50% is +$468 and
-$118 on the same corpus.

Measurable in shadow, without changing a prompt. An agent request carries
the whole conversation, so when a lever proposes cutting the result at
position i, that same body already shows whether the agent later went back
to that target. No applied edit, no state kept across requests.

The distinction that decides the number: a later Read at a HIGHER offset is
pagination, not damage. It fetches fresh bytes from the file and would have
happened whether or not the earlier result was trimmed. Counting it
condemns the lever for behaviour it did not cause -- and it is most of the
signal. On this machine's 144 transcripts, "returned to the target at all"
is 28.3%; true re-reads are 20.0%.

Measured, per tool:
  all tools   20.0%  -> net $272 of a $533 gross
  Bash only    0.1%  -> net $176 of a $177 gross

So the calibration question is answered: truncation is worth having, and
scoping it to command output rather than file reads keeps essentially all
of the saving while removing essentially all of the risk.

Persisted per turn and surfaced on the measured rail row, because a rate
that lives only in an analysis script is an anecdote. Old databases are
migrated -- CREATE TABLE IF NOT EXISTS silently keeps the old shape, so a
schema change alone never reaches a developer already running the sidecar.
…adow/prod preview

Two additions, one rule between them: nothing on this page may state a number
it cannot source.

REFERENCES. A figure with nothing beside it cannot be acted on -- "$0.06 per
turn" is not high or low until something says what else it could have been.
Each tile now carries a comparison point and the receipt for it:

  SELF       the developer's own distribution over the sessions in scope
  PEER       another agent on this same machine, same window (a controlled
             comparison: one developer, one period, one corpus)
  PUBLISHED  a provider-stated constant, with the source URL and as_of that
             ace.gateway.pricing already records
  MEASURED   a figure this repo derived, with the derivation attached
  NO REF     no grounded reference exists -- said plainly

That last one is the point. The most requested number here is the optimal
conversation-turn count for coding quality, and there is no figure for it
this process can verify. It renders as NO REF with what establishing one
would take (a replay eval: the same task at varying context lengths,
scored). An invented benchmark is worse than a blank one -- a reader cannot
tell them apart, and the blank one at least prompts the right question.
This repo already holds that line for model capability claims in
data/model_market/benchmarks.yaml, where an empty `source` means nobody has
pointed at the leaderboard yet.

MODE PREVIEW. A top-level off/shadow/prod control annotates the metrics the
enabled skills would move, with per-source attribution on hover. Client-side
and inert by design: switching to `prod` previews, it does not enable
anything. A lever is enabled in ~/.ace/config.json and nowhere else -- a
dashboard that could switch one on from a hover is a dashboard that can
silently start rewriting a developer's prompts.

The attribution never sums. Levers are scored alone so their shares overlap;
the headline takes the single largest contributor and the hover says so,
the same discipline the ledger and the rail already keep. Simulated and
measured sources are labelled separately and never merged.
…does not move

The toggle previously annotated three cost tiles. It now answers the question
for every headline metric, in that metric's own unit -- tokens where the
figure is tokens, dollars where it is dollars -- and attributes each to the
skill producing it.

  tokens_in            -365.5M tok  (-8.4%)  via bash truncate
  tokens_per_commit    -892k tok    (-8.4%)
  list_price_cost      -$181.72     (-5.9%)
  cost_per_turn        -$0.0035     (-5.9%)
  cost_per_session     -$0.6310     (-5.9%)
  cost_per_commit      -$0.4432     (-5.9%)

Note the two rates. Volume falls 8.4% while cost falls 5.9%, and the gap is
the point: the removed tokens are disproportionately cache reads at 0.1x, so
a token saved is worth less than an average token. A single percentage
applied to both would have overstated the money by ~40%.

Half the value is the metrics reported as UNCHANGED, which are now computed
and stated rather than left blank:

  tokens_out           the model generates these; removing prompt content
                       does not shorten a reply
  commits_per_session  no context lever can write code
  api_requests /       only a loop guardrail moves these, and it has
  conversation_turns   detected no loop in this scope

A blank slot and "this skill cannot move this number" look identical to a
reader and are different claims. Claiming an output-token reduction for a
prompt-side lever would have been the most flattering error available here.
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.

2 participants