Repository navigation
Conversation
…d cache past day files Five defects from the cost/session read-path audit (rossoctl#1566): 1. Coverage parity: the ledger's priceable rule required a non-zero token count, so a truncated OpenAI-dialect stream (200, a model, no usage block) hid a coverage gap on today/7d/month that the ring's duration windows reported. usage.Priceable is the ring's rule stated once; the ledger writer now calls it. 2. Error parity: the ledger counted any 400+/denial as an error, predating the ring's destination_private and upgrade_declined exemptions, so a guard refusal read as a failing proxy on today but not on 1h. The rule is now usage.CountsAsError, called from both. 3. Archive segments never rotated on size: a session busy past the idle window kept one segment growing without limit, and planPrune skips open segments in both its age and maxBytes loops, so the archive's size bound was unenforceable against exactly the busiest sessions. Segments now rotate at 128 MiB, checked in the tick after the flush (a segment's byte count is only real once its zstd encoder has been flushed). 4. Every ledger query re-decoded every day file in the window: agentop polls today each minute and 7d/month each five, so a month span decoded 31 files per poll and past days almost never change. Past days are now cached keyed on (size, mtime); today is never cached. 5. Four comments in core/cost described code that has since changed (the accumulation "open defect" that Counts.Add's saturating addInto closed, "NO IMPORTER ON THIS BRANCH", "neither exists at this commit", and Dropped()'s "no non-test caller") — corrected so a reader stops concluding that sums can wrap and token bounds are unenforced. Assisted-By: Claude (Anthropic AI) <noreply@anthropic.com> Signed-off-by: Hai Huang <huang195@gmail.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 47 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Member
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Closes #1566 — the cost/session read paths counted the same traffic by different rules and re-decoded on every poll. All five items from the audit, in one PR.
1. The ledger hid a coverage gap the ring reported
The ledger's priceable rule required a non-zero token count, so a truncated OpenAI-dialect stream — 200, a model, and no usage block, because every counter lives on the final chunk — was invisible on
today/7d/monthwhile the ring counted it and named it inUnpricedBy. Nine priced requests plus one of those read "9/9 priced" on today against "9/10" on the 1h window.Fix:
usage.Priceablestates the ring's rule once (model recognised; zero usage counts as priceable only when the response succeeded), and the ledger writer calls it instead of restating its own.2. The error rule was written twice and only one copy was updated
The ledger counted any
400+or denial as an error — predating the ring'sdestination_privateandupgrade_declinedexemptions — so an egress-guard refusal read as a failing proxy ontodaybut not on1h.Fix:
usage.CountsAsError(the ring's rule, exported) is now called from both halves.3. Archive segments never rotated on size
A segment closed only on 60-minute idle, the open-writer cap, or delete/clear/rename — never on size — and
planPruneskips open segments in both its age andmaxBytesloops. A session busy past the idle window kept one segment growing without limit, and the archive's size bound was unenforceable against exactly the sessions that produced the most bytes.Fix: segments rotate at 128 MiB (
WithMaxSegmentBytesto configure). The check runs in the tick after the flush, because a segment's byte count is only real once its zstd encoder has been flushed — a write-time check cannot see the cap cross. The cost is one tick of overshoot.4. Every ledger query re-decoded every day file
Queryopened and fully decoded each day file on every call with no cache. agentop pollstodayevery minute and7d/monthevery five; on the 31st, the month span decoded 31 files per poll, and past days almost never change.Fix: past days are cached in the store, keyed on the file's size and mtime (a changed past day is re-read, not served stale); the current day is never cached. Validation uses
Stat, notOpen. The "today" decision uses the writer's clock, not the machine's.5. Comments that contradicted the code
Four comments in
core/costread like notes from the middle of a PR stack: the accumulation wrap called "an open defect" thoughCounts.Addsaturates;MaxPlausibleTokensdeclared importer-less though the ledger writer imports it;plausibleTokenReport/RefusedTokenRequestsdeclared nonexistent;Dropped()declared caller-less. All corrected — a reader was concluding that sums can still wrap and token bounds are not enforced.Testing
Every fix is pinned by a test that was red on main and green after:
TestRecord_ZeroUsageSuccessIsPriceable/TestRecord_DestinationPrivateIsNotAnError— the ledger/ring parity, asserted through the ledger's own day file.TestWrite_RotatesASegmentAtTheByteCap— rotation at a one-byte cap: two segments on disk, all events readable in sequence order across the boundary.TestQuery_APastDayIsServedWithoutReopeningTheFile— the cache observed through permissions (a chmod'ed past day still answers; the uncached read cannot Open it). Runs vacuously as root.TestQuery_APastDayCacheIsInvalidatedWhenTheFileChanges/TestQuery_TodaysFileIsNeverCached— the cache's honesty both ways.Full
core/cost/...,core/session/...,core/sessionapi/...suites green;go vetandgofmtclean on the touched packages.Assisted-By: Claude (Anthropic AI) noreply@anthropic.com