Problem
Codex Limits can allocate hundreds of megabytes and block the main thread while refreshing a power-user profile. A measured QA run grew from about 129 MB physical footprint at rest to 735 MB after refresh, with a 1.1 GB peak. The current local Codex data set is 7.3 GB and contains rollout files up to 326 MB.
The causes are in the data path, not the visible chart:
- one appended record copies and rescans the full fact history for its rollout;
- a no-change refresh still flattens and re-evaluates every active fact;
- the full usage engine runs on MainActor;
- facts from past windows stay resident;
- rollout, fact-cache, and app-server reads have unbounded whole-record paths;
- malformed extreme values can trap during interval creation or integer arithmetic.
Scope
Acceptance criteria
- A refresh with no new local bytes does not allocate another full fact buffer or rerun unchanged local aggregates.
- Appending one small record performs work proportional to the delta, not the full task history.
- Large rollout and fact-cache files are processed in chunks; one oversized record returns a controlled coverage/error result instead of exhausting memory.
- Facts outside the active window do not remain resident after they are safely persisted.
- UI publication stays on MainActor, while the heavy pure evaluation does not.
- Oversized RPC lines, invalid window durations, token-sum overflow, and extreme restored counters fail without terminating the app.
- Full Swift tests, Codex client tests under Thread Sanitizer, release build, and full-screen QA pass.
- The closing comment records before/after refresh latency and memory for the same representative fixture/profile.
Non-goals
No new UI, no change to analytics meaning or retention, no automatic history deletion, no app-server restart after each refresh, and no sync/chart optimization unless the new measurements show they block these acceptance criteria.
Implemented in #33.
Problem
Codex Limits can allocate hundreds of megabytes and block the main thread while refreshing a power-user profile. A measured QA run grew from about 129 MB physical footprint at rest to 735 MB after refresh, with a 1.1 GB peak. The current local Codex data set is 7.3 GB and contains rollout files up to 326 MB.
The causes are in the data path, not the visible chart:
Scope
Acceptance criteria
Non-goals
No new UI, no change to analytics meaning or retention, no automatic history deletion, no app-server restart after each refresh, and no sync/chart optimization unless the new measurements show they block these acceptance criteria.
Implemented in #33.