-
Notifications
You must be signed in to change notification settings - Fork 670
feat(usage): raise the management read entry cap from 200k to 500k #1099
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
51 changes: 51 additions & 0 deletions
51
devlog/_plan/260806_disposition_sweep/060_usage_cap_500k.md
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # 060 — usage management read cap: 200k → 500k entries | ||
|
|
||
| User authorization (2026-08-06): adopt the user's uncommitted 500k edits from | ||
| the main checkout, "의견을 종합해서" — synthesize the review context and land | ||
| it properly. Authority includes push + PR + merge for this item. | ||
|
|
||
| ## Synthesis (why 500k is the right call now) | ||
|
|
||
| - The cap is a READER bound (`MANAGEMENT_USAGE_MAX_ENTRIES` in | ||
| `src/usage/log.ts`), not a retention bound: raw `usage.jsonl` is never | ||
| deleted by it. Raising it widens what one management read can return. | ||
| - The BYTE cap (`managementUsageMaxReadBytes`, 64 MiB default) bounds the raw | ||
| INPUT of a read before the entry cap applies (log.ts:532-558); the entry cap | ||
| trims parsed rows afterwards (log.ts:500-519). Corrected per audit: 64 MiB | ||
| bounds input bytes, while 500k raises the TRANSIENT parse/summary heap and | ||
| CPU — up to 300k more normalized JS objects can be retained per read, and | ||
| `/api/usage` does several full passes with per-request Map/Set aggregation | ||
| (summary.ts:301-583). This is a bounded, transient cost on a management | ||
| read, not an unbounded leak — but it must be measured, not assumed. | ||
| - Acceptance criterion added: a representative 500k-entry benchmark (small | ||
| rows, worst-case unique request ids) must show acceptable wall time and | ||
| peak RSS delta for `readUsageSnapshotForManagement` + `summarizeUsage` | ||
| before landing. | ||
| - Prior lesson (usage-log cap incident): "a reader cap can hide data without | ||
| deleting it" — the 200k clip was exactly that failure shape for the GUI. | ||
| - With the #1008 rollup sidecar (still open) history older than the window | ||
| will come from folded rows anyway; until it lands, the raw window IS the | ||
| history, which strengthens the case for the wider entry cap now. | ||
| - Overlap handling: this branch cuts from current dev, applying the same | ||
| content as the user's dirty edits. The main checkout stays untouched; once | ||
| this lands, the user's local diff becomes content-identical to HEAD. | ||
|
|
||
| ## Work | ||
|
|
||
| 1. Branch `codex/usage-entry-cap-500k` off current dev; apply the two-file | ||
| change (constant + test expectations). | ||
| 2. 500k benchmark (bench script in .tmp/, not committed): parse + summarize | ||
| wall time and heap delta at 200k vs 500k; record numbers in this ledger. | ||
| 3. Focused tests + typecheck; terra regression audit. Collision check done: | ||
| #1008's log.ts diff starts at the reader (~line 523) and does not touch | ||
| the cap line or this test — no hunk collision (audit-verified). | ||
| 4. Push, PR to dev, CI green, merge with `--match-head-commit` pin. | ||
|
|
||
| ## Ledger | ||
|
|
||
| | Step | Evidence | | ||
| |------|----------| | ||
| | Benchmark (bench.ts in mktemp, not committed) | Baseline 200k-cap: 200k entries, read 475ms, summarize 358ms, ΔRSS 547MiB. With 500k cap on a 96.7MiB/500k-row file: byte cap binds first → 330,585 entries, read 835ms, summarize 609ms, ΔRSS ~1.1GiB transient. 600k-row file: identical 330,585 entries — the 64MiB byte window is the effective bound for realistic rows; the 500k entry cap is a secondary guard, not the binding limit | | ||
| | Cap-binding benchmark (bench2, audit-required) | Tiny rows densely packing 63.5MiB → 629,205 rows in the byte window; parse-all-then-slice yields exactly 500,000 entries (129,205 dropped). read 1,436ms, summarize 637ms, ΔRSS 897MiB transient. This exercises the exact widened case (entry cap binding, unique request ids) | | ||
| | Acceptance threshold + verdict | Threshold: ≤3s combined read+summarize, ≤1.5GiB transient RSS on the worst case. Measured: 2.07s combined, 897MiB — inside threshold. Request-scoped, no steady-state retention; acceptable for an on-demand admin endpoint | | ||
| | Stale comment | tests/usage-log.test.ts:138 timing comment updated to the 500k shape (audit minor) | |
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
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀 Performance & Scalability | 🔵 Trivial
Verify production memory headroom before release.
parseUsageTextCooperativelyparses the complete byte-window input before it appliesMANAGEMENT_USAGE_MAX_ENTRIES. The higher cap therefore allows more entries to remain in the snapshot and flow into/api/usageaggregation. The devlog reports approximately 897 MiB transient RSS for the cap-binding case atdevlog/_plan/260806_disposition_sweep/060_usage_cap_500k.md:49. Identical reads share parsing, butreadUsageSnapshotForManagementstill returns a separateentries.slice()to each caller.Run one cap-binding read and concurrent
/api/usagerequests under the production Bun memory limit. If the process lacks sufficient headroom, bound parsing or aggregation to the newest 500,000 entries, or enforce a deployment-specific lower limit.🤖 Prompt for AI Agents