Skip to content

feat: report reasoning effort, and stop losing big sessions from the math - #25

Merged
AqueGen merged 6 commits into
mainfrom
feat/effort-visibility
Aug 11, 2026
Merged

feat: report reasoning effort, and stop losing big sessions from the math#25
AqueGen merged 6 commits into
mainfrom
feat/effort-visibility

Conversation

@AqueGen

@AqueGen AqueGen commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Two gaps the report had, both found by reading a real 14d run rather than the code.

Effort was invisible

The plugin is built on two knobs, and the report only ever showed one. In the live window here, 211 of 489 dispatches went to general-purpose - a type with no frontmatter pin, so every one of them inherited the session effort (high) even where the tier was correctly dropped to sonnet. Cheap model, expensive thinking, and the report scored it as a clean win.

Each dispatch now records the session effortLevel. Transcripts carry no effort field at all (verified - zero structured matches), so the settings cascade is the only observable source; the report says so instead of implying per-dispatch precision.

Effort: 2 of 3 dispatches ran on an agent type with no effort pin and inherited the session level (2 at high).
  The bundled agents pin theirs - low for scout/test-runner/verifier, medium for implementer/e2e-runner, high for reviewer - so routing a mechanical errand through a role agent buys a cheaper effort as well as a cheaper tier.
  Read from settings effortLevel, so a --effort launch flag or a mid-session change is not visible here.

Levels outside the ladder are ignored, so a typo never becomes a data point, and the section is omitted when no entry recorded an effort - old logs and machines with no effortLevel set simply do not show it.

Big sessions fell out of the token math

tokens read only the first 256KB of the parent transcript to find the session model. A long session pushes its first assistant message past that window - measured here at 6 of 60 transcripts, every one multi-MB - and those sessions were reported as (session unknown): 58 agents and 123.1M tokens excluded, concentrated in the largest sessions precisely because size is what caused it.

The lookup now falls back to the tail, taking a late-window model over none. Before and after on the same 14d window:

before:  1.81B of 3.06B comparable tokens (59%)   + (session unknown): 123.1M across 58 agents
after:   1.89B of 3.18B tokens (59%)              + no unknown row at all

The share did not move, which is the point: the excluded volume had been routing down at the same rate, so this recovers a denominator rather than improving a number.

The not-comparable note also blamed TIER_PATTERNS for both of its causes. Extending the tier table would never have fixed this one, so the note now names the unreadable-session case separately.

Tests

6 new cases, 45 pass / 0 fail: effort from the user file, project file outranking it, an out-of-ladder value ignored, only unpinned agents counted as inheriting, the section omitted when unrecorded, and the tail fallback with a >256KB model-free head. The effort tests pin both a temp CLAUDE_CONFIG_DIR and a temp cwd - without the temp cwd the result would depend on the directory the suite runs from.

…math

The report measured one of the two knobs the plugin is built on. Tier was
visible, effort was not, so a mechanical errand dispatched to an unpinned agent
type looked like a win at sonnet while it inherited the session level and
thought as hard as the session does. Each dispatch now records the session
effortLevel from the settings cascade - transcripts do not carry effort at all,
so that cascade is the only observable source - and the report prints how many
dispatches ran on an agent type with no pin and inherited it. Values outside the
ladder are ignored so a typo cannot become a data point, and the section is
omitted entirely when nothing recorded an effort.

Also fixes the session-model lookup in the tokens report, which read only the
first 256KB of the parent transcript. A long session pushes its first assistant
message past that window - 6 of 60 transcripts here, all multi-MB - and those
sessions dropped out of the routed-down math as "session unknown", taking 120M
tokens with them, concentrated in the biggest sessions precisely because size is
what caused it. The lookup now falls back to the tail, accepting a late-window
model over no model. On the author's 14d window the denominator went from 3.06B
to 3.18B with the share unchanged at 59%, so the exclusion had been hiding
volume rather than flattering the figure.

The not-comparable note blamed TIER_PATTERNS for both of its causes; it now
names the unreadable-session case separately, since extending the tier table
would never have fixed it.
Review round 1 across three independent reviewers found the effort source was
both too narrow and too wide.

Too narrow in two ways. CLAUDE_CODE_EFFORT_LEVEL overrides the settings cascade
for the whole session, and reading only settings therefore reported a level the
session did not run on - the same class of bug the model side already solved via
CLAUDE_CODE_SUBAGENT_MODEL. And an unset effortLevel is not unknown: it is the
documented model default, high wherever effort is supported and xhigh on Opus
4.7, so omitting the entry left the section blank on the commonest configuration
of all. Both sources are now read in the order Claude Code applies them, and
each entry records which rung it came from so an inferred default never reads as
a setting somebody chose.

Too wide in accepting max from a settings file, where it is rejected as
session-only. It is accepted from the env var, which is the one place it is
allowed, and ultracode is accepted nowhere.

A bad value no longer falls through to the next rung either. A local file
carrying a typo used to log the user-level value, replacing a missing data point
with a wrong one; a file that defines the key now ends the walk whatever the
value, while an unparseable file still defers, matching how the harness ignores
a broken settings file wholesale.

Three more fixes from the same round. The tokens footer still promised
session-START attribution after the tail fallback shipped, which is the opposite
bias for exactly the sessions the fallback targets; it now says so. The effort
section claimed to know which agents carry no pin when it only knows the bundled
ones, so a third-party agent pinning its own effort is now described as counted
inherited rather than silently mislabelled. And projRoot still inlined the
config-dir resolution that configDir() was extracted to remove.

Tests grew from 45 to 56: a PINNED_EFFORT frontmatter sync test guarding the
drift class 0.7.1 fixed for PINNED_MODELS, a ladder test pinning which levels
each source accepts, every precedence rung including the project file that had
no coverage at all, the env override, auto, both model defaults, the
no-fall-through rule, a malformed file, and the two report lines that had no
assertions. run() now defaults cwd to the temp config dir and blanks
CLAUDE_CODE_EFFORT_LEVEL, so no test can be decided by a settings file or an
env var belonging to whoever runs the suite.
…numbers

Review round 2 found the model default being handed to models that have no
effort knob at all. defaultEffortFor gated on "can TIER_PATTERNS rank this",
which claude-3-5-sonnet passes happily despite predating adaptive reasoning, and
a version-threshold guard would have been just as invented - it would have given
Haiku 4.5 a default, when Haiku 4.5 is simply absent from the support table.
Support is now that table, transcribed: Fable 5, Opus 5, Sonnet 5, Opus 4.8 and
Opus 4.7 take the whole ladder, Opus 4.6 and Sonnet 4.6 take everything but
xhigh, and anything unlisted supports no effort and therefore receives no level.

The same table supplies a rule that was missing: a level the model does not
support runs as the highest supported level at or below it, so xhigh configured
on an Opus 4.6 session ran as high. The log records what ran rather than what was
configured, which is the whole point of the round-1 fixes. When the session model
is unknown the clamp cannot be computed and the configured level is kept as-is -
the one figure here that is a configuration rather than an observation, and it
says so.

Two report defects both Claude reviewers caught independently. The inferred-
default count was taken over every entry while printing directly under a sentence
about the inherited subset, so a pinned agent on the model default could print
"3 of these" beneath a total of 2; it is now scoped to that subset, and the
fixture was rebuilt so the two scopings give different numbers - the old one
could not fail. And two comments the round-1 rewrite left behind still described
the settings cascade as the only observable source and promised the section is
omitted when effortLevel is unset, neither true since the env and default rungs
landed.

The two pin tables became one AGENT_PINS with model and effort columns. They were
two views of one fact - the agent frontmatter - and the report asked "is this
agent pinned" through PINNED_EFFORT while the leak section asked BUNDLED, which
is derived from the other table. One table, one sync test covering both columns,
and the deliberate difference (Explore is cheap but not pinned) stays explicit in
CHEAP_AGENTS. The ladder test that regexed the source for its own constants is
gone too: it passed on text rather than behaviour, so it is replaced by cases that
drive the hook - ultracode rejected from both sources, max from the env var only,
the clamp, and the unsupported-model cases.

Docs follow the same source. The README effort ladder promised high with no
exception; it now names the Opus 4.7 default, the support list, and the clamp,
and the routing skill carried the same gap.

57 tests pass.
Both reviewers found the same hole independently. clampEffort kept a configured
level unchanged when the session model could not be read, on the reasoning that
a configuration is better than nothing. The counter-example settles it: a Haiku
4.5 session whose transcript cannot be read, with effortLevel high in settings,
logged effort "high" - a level that does not exist on that model at all. The
clamp needs the model, because the same configured level means different things
on different models, so an unreadable model now records nothing. That matches how
every other figure in this report treats an unknown session: excluded, never
guessed.

Six precedence tests were only reaching the early return that hole created, so
dispatchWithSettings now defaults to a supported session model and takes null
explicitly. "max is accepted from the env var" was the worst of them - it had
been asserting nothing about max being supported anywhere.

The README still told maintainers to keep PINNED_MODELS and PINNED_EFFORT in
step, one commit after they became AGENT_PINS, and still claimed unsupported
levels are always recorded as what ran. Round-2 prose against round-3 code, which
is the drift that paragraph exists to warn about.

Also: the two identical EFFORT_SUPPORT rows are one alternation, and the test
named for rankability is named for support instead - the gate that actually
fires.

One reviewer recommendation declined. Folding EFFORT_SUPPORT into TIER_PATTERNS
would trade one duplication for another: tier is a property of the family, effort
support a property of the version, so a single ordered list has to repeat the
tier across every version row and add a family fallback carrying no efforts. The
tables stay separate with a consistency test pinning them together - every model
with effort support must be rankable - and the reason is now a comment on the
table rather than a decision someone has to rediscover.

59 tests pass.
The one finding Codex could produce this round came from the documentation
rather than the code, and it lands on the wording. The comments and the README
said this log records the effort that ran. Four documented states override the
reconstruction and none of them are visible to a PostToolUse hook: a /effort or
--effort choice made inside a running session, ultracode, an organization effort
cap, and the model-default hold that Fable 5, Opus 4.8 and Opus 4.7 apply on
first run "even if you previously set a different level for another model" -
which means a persisted setting can be overridden while this hook still reads it
and reports it.

The clamp still closes the one gap a hook can see, and the algorithm is
unchanged. What changes is the claim: the report and the README now name all
four blind spots and say to read the figure as what the visible sources resolve
to, not as a measurement.

59 tests pass.
Round-4 leftovers, all non-blocking, from the two reviewers that reached a
mergeable verdict.

The consistency test parsed TIER_PATTERNS with a dot-star that stops at a
newline, so reformatting that table across lines would have failed the test for
its own parsing rather than for its subject. It also checked which models appear
in the support table but never that the levels in it exist: a stray level would
pass the includes check in clampEffort and then drop out of the downward walk
silently, because indexOf returns -1 for a level the ladder does not carry. Both
are now asserted.

The README said an unsupported level is "recorded as the level that actually
ran", two lines above the paragraph explaining that none of this is a
measurement. It now says it records the level Claude Code falls back to, which is
what the clamp actually knows.

59 tests pass.
@AqueGen
AqueGen merged commit 634a32a into main Aug 11, 2026
2 checks passed
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