Skip to content

fix(parser): keep both halves of a midnight-straddling turn, and stop --provider leaking claude - #929

Open
ozymandiashh wants to merge 1 commit into
getagentseal:feat/core-extractionfrom
ozymandiashh:fix/port-parser
Open

fix(parser): keep both halves of a midnight-straddling turn, and stop --provider leaking claude#929
ozymandiashh wants to merge 1 commit into
getagentseal:feat/core-extractionfrom
ozymandiashh:fix/port-parser

Conversation

@ozymandiashh

Copy link
Copy Markdown
Collaborator

Ports upstream fixes for two defects this branch never received. Both are conservation bugs: work that happened is not where the report says it is.

A turn spanning local midnight was filtered as a unit

The range and day filter keyed on the turn's first call, so every later call that landed in the requested day was discarded along with it. A long autonomous Codex run, or Claude work that crossed midnight, made codeburn today under-report until the turn ended — and multi-day totals attributed the whole turn to its start day.

Filters now slice inside the turn. Only the calls inside the requested window survive, and the turn's timestamp re-anchors to its first surviving call, so turn-anchored rollups (category, editTurns, oneShotTurns, the daily cache) land on the day the retained calls actually happened. Cost, calls, savings and tokens bucket under each call's own local day, so day N + day N+1 conserves the whole-range total.

A sliced turn is still classified from its full call list — category, hasEdits and retries describe the whole exchange, not the surviving slice. That matches the Claude path and is deliberate.

The inverse leak, on provider-filtered runs

--provider <other> still entered the claude scan, whose orphan pass read the entire cached claude section, treated every cached PR-bearing transcript as no-longer-discovered, and re-injected it. By Project and By Model listed Anthropic spend under --provider cursor while the headline showed cursor alone.

Now guarded by an explicit in-scope check — deliberately not a directory-count check, so when claude is in scope but every transcript has been pruned, PR-attributed orphans still survive.

Blast radius

Daily-history rows and the JSON daily fallback change shape for straddling days: call-derived values move to the call's own day. Session totals and the session-cache format are unchanged.

Two caveats, stated rather than left to be found

  1. The multi-day all-provider By Activity rollup still derives today's slice from the unsliced range parse, so a straddling turn's category cost stays anchored on its start day and categories can sum below the headline on that surface. Upstream has a follow-up; it should land next.
  2. This PR does not bump the daily cache version, on purpose. A single bump in the release covers every parser-behaviour change landing with it, and fix(codex): validate rollouts structurally, guard the parse path #926 carries it. Three PRs each editing that constant would conflict on the same line and leave you asking which "16" is which. If this and fix(codex): validate rollouts structurally, guard the parse path #926 land apart, an upgrading user with a finalized rollup keeps turn-anchored days until something else forces re-hydration.

@ozymandiashh
ozymandiashh marked this pull request as draft August 5, 2026 10:03
@ozymandiashh

Copy link
Copy Markdown
Collaborator Author

Converted to draft: this was opened with only a self-review by the model that wrote it, which is not the review bar this batch is held to. Independent review by two other reviewers is running now; I will mark it ready once both have passed and any findings are applied. Apologies for the noise.

@ozymandiashh
ozymandiashh marked this pull request as ready for review August 5, 2026 13:39
@ozymandiashh
ozymandiashh marked this pull request as draft August 5, 2026 14:13
… --provider leaking claude

Ports upstream fixes for two defects this branch never received.

**A turn that spans local midnight was filtered as a unit.** The range and day
filter keyed on the turn's FIRST call, so every later call that landed in the
requested day was discarded along with it. A long autonomous Codex run, or
Claude work that crossed midnight, made `codeburn today` under-report until the
turn ended, and multi-day totals attributed the whole turn to its start day.

Range and day filters now slice inside the turn: only the calls inside the
requested window survive, and the turn's timestamp re-anchors to its first
surviving call so turn-anchored rollups — category, editTurns, oneShotTurns,
the daily cache — land on the day the retained calls actually happened. Cost,
calls, savings and tokens bucket under each call's own local day, so day N plus
day N+1 conserves the whole-range total. A sliced turn is still classified from
its FULL call list, because category, hasEdits and retries describe the whole
exchange rather than the surviving slice — matching the Claude path.

**The inverse leak hit provider-filtered runs.** `--provider <other>` still
entered the claude scan, whose orphan pass read the entire cached claude
section, treated every cached PR-bearing transcript as no-longer-discovered and
re-injected it. By Project and By Model listed Anthropic spend under
`--provider cursor` while the headline showed cursor alone. The scan is now
guarded by an explicit in-scope check — deliberately not a directory-count
check, so when claude IS in scope but every transcript has been pruned,
PR-attributed orphans still survive.

**The daily cache is bumped to 17**, because leaving it at 15 would double-count
the post-midnight half of a straddling turn for an upgrading user. A v15
rollup finalized by the pre-fix binary holds the WHOLE turn on its start day,
and the new slicing then also puts the post-midnight call on the next day —
the same cost twice, in a cache whose ten-year retention never ages it out.
The bump mints a fresh filename; adoption marks the merged result incomplete,
so the next hydration re-derives every day whose sources survive under
per-call bucketing and carries forward only what it cannot re-derive.
16 is deliberately skipped: main already spent it on the codex
structural-discovery fix (eece4cf), so claiming 16 here would load a
main-built v16 cache — which holds only the codex fix — as current and
complete and the invalidation would never fire.

Blast radius: daily-history rows, the JSON daily fallback and range-query
session totals change shape for straddling days, as call-derived values move
to the call's own day — the intended correction, asserted by this commit's
tests. The session-cache FORMAT is unchanged.

One caveat worth stating rather than leaving to be found. The multi-day
all-provider By Activity rollup still derives today's slice from the unsliced
range parse, so a straddling turn's category cost stays anchored on its start
day and categories can sum below the headline on that surface; upstream has a
follow-up for it.
@ozymandiashh
ozymandiashh marked this pull request as ready for review August 5, 2026 14:40
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