Skip to content

feat: record the side asked for and the side that answered on every model call - #1094

Merged
REPPL merged 21 commits into
mainfrom
feat/run-records-both-sides
Oct 18, 2026
Merged

REPPL merged 21 commits into
mainfrom
feat/run-records-both-sides

Conversation

@REPPL

@REPPL REPPL commented Oct 18, 2026

Copy link
Copy Markdown
Collaborator

Ships itd-166: every model call abcd makes now records two sides, what it asked for and what actually answered, on the receipts that already exist.

  • Provider adapter: the asked side (model, every setting sent, a sha256 of the rendered messages) and the served side (the model and upstream provider the response names, generation id, finish reason, prompt, completion, reasoning and cached token counts, cost when reported). The stream asks for usage (stream_options.include_usage); a provider whose server refuses it can turn that off with stream_usage: false, and ahoy connect asks its verification once more without the field after a 400 or 422 and writes that setting. Ordinary calls never retry.
  • Runners: the claude runner reads usage, harness-computed cost, the served models and its version from its stream. The opencode runner no longer stamps the asked model as the served one: its run mode names no model, so the served model is empty and listed as not reported, with tokens and cost summed across its steps.
  • Every field a route cannot read is listed by name with its reason (not reported, self-reported, computed by the harness, not configured). A missing, negative, null or overflowing count or cost is never recorded as a number.
  • Run state moves to schema 14 (v0.15.1 took 13); a version-13 file reads as neither side recorded and is written back at 14.
  • Reviewed by two Opus and Sonnet pairs plus a docs-fidelity pair; intent audit ingested (six criteria met, two met with concerns, both acted on).

Delivers: itd-166
Resolves: iss-2610161709506207
Resolves: iss-2610170934491794
Resolves: iss-2608290811463906
Refs: iss-2610161734413178
Refs: iss-2610161734428291
Refs: iss-2610171545099084
Refs: iss-2610180052110870
Assisted-by: Claude:claude-opus-5-5

REPPL added 20 commits October 17, 2026 18:51
A call through the OpenAI-compatible adapter now records the side abcd
asked for (the prompt's SHA-256 and the field the adapter added) and the
side that answered (the upstream provider, generation id, finish reason,
prompt, completion, reasoning and cached token counts, and the cost) as
the response names them, and lists every field of the fixed lists it
could not pin with its reason. The request asks for usage in the stream
unless the provider block sets stream_usage to false, and a refusal of
such a request names that setting. The harness hand-off's receipt lists
the payload's model as self-reported.

Assisted-by: Claude:claude-opus-5-5
A run through the claude or opencode runner now records the model the
runner passed and the prompt's hash beside what the harness reports: the
claude runner reads the result event's token counts, cost, stop reason
and per-model usage and the init event's version, from a fixture taken
from a real stream; the opencode runner sums its step-finish events'
tokens and cost. Each lists every field of the fixed lists it could not
pin, its cost as computed by the harness. The opencode runner no longer
stamps the asked model as the served one: run mode names no model, so
the served model is empty and listed as not reported.

Refs: iss-2610161709506207
Assisted-by: Claude:claude-opus-5-5
A runner's route record on a verified receipt or a validator's return now
carries both sides of the run, which the drive passes through from the
runner's answer. The run state moves to schema version 13: a version-12
file reads as a run whose routes recorded neither side and is written
back at 13, and a file of version 12 or lower carrying either side is
refused. The state's mask covers every new string and slice.

Assisted-by: Claude:claude-opus-5-5
A runner's route line names the model the runner asked for and the cost
when the route carries them, and a dispatched step's line names the
upstream provider and the cost the call reported. The consistency
answer's kept route file carries both sides of the call whole, with no
new file beside it. The golden harness receipts list the hand-off's
unpinned fields.

Assisted-by: Claude:claude-opus-5-5
Refs: iss-2610170934491794
Assisted-by: Claude:claude-opus-5-5
A 400 or 422 to a request that asked for usage in the stream now carries
the stream_options hint only when its body names stream_options or
include_usage; any other refusal reads as it did before. Every such
refusal is told apart as ErrUsageRefused, which only a setup acts on.

Assisted-by: Claude:claude-opus-5-5
The setup's verification call asks for usage in the stream; a server that
refuses that request with HTTP 400 or 422 is now asked once more without
it, and when that succeeds the block connect creates carries
stream_usage false and the result says so in its text and JSON forms.
--stream-usage sets the value outright. Ordinary calls are still never
retried, and a refusal on the setup path names the flag, not a block the
setup has not written.

Resolves: iss-2610170934491794
Assisted-by: Claude:claude-opus-5-5
The adapter now reads the prompt, completion and total counts as
pointers, so a count that is absent or of another type is listed in the
call record's unpinned on its own, never recorded as a zero the provider
did not report. A later usage chunk that reads fewer fields no longer
replaces an earlier, fuller one, and a usage member with no readable
field is no usage at all.

Assisted-by: Claude:claude-opus-5-5
opencode's summed cost is dropped and listed as not reported once the
sum stops being finite, so a run's state still writes, and a token sum
that would overflow is unreadable rather than wrapping negative. claude's
counts are read only when present and not negative. One cost rule,
ReadableCost (zero or more, finite), now covers opencode's steps,
claude's total_cost_usd and the adapter's usage cost.

Assisted-by: Claude:claude-opus-5-5
The test asserts two calls, a refusal and one retry, then no third;
its old name said nothing was retried.

Refs: iss-2610170934491794
Assisted-by: Claude:claude-opus-5-5
A setup whose first verification is refused for the usage field asks
once more without it, so the brief and the command page no longer say
one call, and the help sentence drops the count.

Refs: iss-2610170934491794
Assisted-by: Claude:claude-opus-5-5
Closes spc-2610170652111963, which moves itd-166 to shipped, and
resolves the opencode runner stamping the asked model as the served one.

Delivers: itd-166
Resolves: iss-2610161709506207
Refs: iss-2610161734413178, iss-2610161734428291, iss-2608290811463906
Assisted-by: Claude:claude-opus-5-5
The intent audit met six criteria and met two with concerns. Decision 4
now says what was built: ordinary calls never retry, and connect asks
its verification once more without the usage field. A runner on a local
model listing no local fields is captured for the local pin to close.

Refs: iss-2610171545099084, iss-2610161734428291
Assisted-by: Claude:claude-opus-5-5
encoding/json reads a null into a number as 0 with no error, so a
provider answering null for a count it has none of was recorded as
reporting zero.

Refs: iss-2610161709506207
Assisted-by: Claude:claude-opus-5-5
Assisted-by: Claude:claude-opus-5-5
A shipped intent may name only resolved issues. The record itd-166 grew
from was declined as its duplicate; itd-166 has now delivered it, so it
is resolved. The OpenRouter and local pins refine itd-166 later and are
not delivered by it, so their link moves to the typed-links prose only.

Refs: iss-2608290811463906, iss-2610161734413178, iss-2610161734428291
Assisted-by: Claude:claude-opus-5-5
…resolved

Refs: iss-2608290811463906
Assisted-by: Claude:claude-opus-5-5
Only the oracle's own receipt reaches it in production, so it is
unexported, and the surface tests that build a harness receipt reach it
through a ForTest seam, as the exported-reach audit requires.

Assisted-by: Claude:claude-opus-5-5
@REPPL
REPPL enabled auto-merge October 18, 2026 10:41
Assisted-by: Claude:claude-opus-5-5
@REPPL
REPPL added this pull request to the merge queue Oct 18, 2026
Merged via the queue into main with commit f9bb6fb Oct 18, 2026
15 checks passed
@REPPL
REPPL deleted the feat/run-records-both-sides branch October 18, 2026 16:31
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