Skip to content

perf(telemetry): a report reads its period, not the whole history - #1032

Merged
blafourcade merged 4 commits into
nextfrom
perf/report-reads-its-period
Oct 15, 2026
Merged

blafourcade merged 4 commits into
nextfrom
perf/report-reads-its-period

Conversation

@blafourcade

Copy link
Copy Markdown
Contributor

🎯 What & why

aidd telemetry report --days 7 used to read, fold and settle the whole ledger, then keep a week of it. Its cost grew with the history. A report with a period now reads only that period's days. On one year at a real rate (3,400 calls a day, 1.24M calls), --days 7 goes from ~4.2 s to ~95 ms, with the same figures. Follow-up of #1001, which left report cost out of scope.

🛠️ How it works

  • Window: a bounded period reads from the day before from to the day after to; an open side stays open (period.ts:40). A report with no period reads and settles everything, as before (report-usage-use-case.ts:66).
  • Why the figures are the same. Take any call that has a copy in the period. Its copies have been observed less than a day apart: 0.3 h at most over 262,631 real keys (perf(cli): ingesting one call rewrites its whole month #1001). So every copy of that call is in the window. foldUsage keeps the minimum of a total order, so the same copies give the same winner. Attribution is per call (attribution.ts:146), so calls left out of the window change no task or ticket. Full reasoning in contract.md.
  • The port takes a test on the day, not a set of days (usage-ledger.ts:27). A window open on one side, or --from 0001-01-01, costs the partitions on disk, not millions of set entries. Ingest passes days.has.
  • Monthly files from before perf(telemetry): the ledger is kept by day, so an ingest costs what it adds #1031: a monthly file is read, with every day of its month, when the window holds one of its days (usage-ledger-adapter.ts:135). The report then splits it, the same way ingest does.
  • Settle: a bounded report settles only what it read. It replaces the copies it loaded with their winner, so a later full read keeps the same calls.
  • Part B, measured without a new state. The unbounded report on 265k calls breaks down as: parsing and validation 0.3 s, fold 0.15 s, aggregation 0.2-0.3 s. No stage dominates, so there is no 2x gain without dropping validation. A cache was not built.
  • shiftDay (stored-usage.ts:43) replaces three copies of the day arithmetic.

🧪 How to verify

  • cd cli && pnpm test: 6512 passed, 1 skipped.
  • Property: report-window.property.integration.test.ts.
    • Setup: a real ledger whose copies straddle midnights, month ends and year ends, across daily and monthly files. Periods are bounded, one-sided or open.
    • Check: the bounded --json envelope equals the full report filtered, byte for byte, and the settled ledger folds to what a full read keeps.
    • It was shown to be a guard by breaking the window: red after 40 runs, and after 6 for the month split.
  • Red runs, bench, gates and mutation: evidence.md.
  • pnpm test:mutation:telemetry: 96.2 on the final commit (floor 96). The one survivor on a changed line is equivalent.
  • pnpm smoke: 132/0/1.
  • node scripts/check-claude-tokens-end-to-end.cjs (and --attended): 2 calls, 393 tokens, all on task demo, ticket T-1.
  • Independent review, 2 rounds, approved at 88%: review.md.
Ledger Report Before After
1.24M calls / 365 days --days 7 4.2 s 95 ms
same no period 4.9 s 4.9 s
265k calls / 28 days --days 7 0.83 s 0.21 s

⚠️ Heads-up

  • The unbounded report is unchanged: ~0.9 s at 265k calls, ~5 s at a year at the real rate. Making it faster needs a second state (a summary by day). That is not justified yet.
  • skipped_ledger_lines counts damage in the partitions read. A bounded report does not see damage outside its window.
  • A call whose copies are more than a day apart (never observed) could be counted differently by a bounded report. A report with no period still folds every copy.

✅ I certify

  • I DO CERTIFY I READ EACH LINE OF THE PULL REQUEST BECAUSE I AM A SOFTWARE ENGINEER, NOT A AI PUPPY.

🤖 Generated with Claude Code

blafourcade and others added 4 commits October 15, 2026 16:59
A report with --days, --from or --to now loads only the days of its period
and the day on each side, plus any monthly file one of them falls in, and
settles only what it read. A report with no period reads and settles the
whole ledger, as before.

The copies of one call are less than a day apart (0.3 h at most over 262,631
real keys), so a call with a copy in the period has every copy in the window
and folds to the same record: a fast-check property checks the bounded
envelope equals the full report filtered, byte for byte.

UsageLedger.load takes a test on the day instead of a set of days, so a
window costs the partitions on disk, not the length of the period.

One year at 3,400 calls a day: --days 7 goes from about 4.2 s to 95 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Review round 1: shiftDay in the stored usage domain replaces three copies of
the day length and its arithmetic; the failing storage and the September to
November days are shared test helpers. The usage skill's envelope reference,
the usage contract and the task contract say what a bounded report reads,
and evidence.md records the mutation run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
Review round 2: say outside the observed bound only an unbounded report folds
every copy, and that skipped_ledger_lines covers a month kept in one file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp
@blafourcade
blafourcade marked this pull request as ready for review October 15, 2026 16:54
@blafourcade
blafourcade requested a review from a team as a code owner October 15, 2026 16:54
@blafourcade
blafourcade merged commit ae8705f into next Oct 15, 2026
61 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