Skip to content

Bound refresh memory and prevent data-driven crashes #35

Description

@thrr87

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

  • Rebase and retain the shared timestamp parser optimization from PR Reduce refresh CPU and memory use #33.
  • Update file state incrementally instead of copying and reindexing all facts.
  • Reuse the merged local snapshot for a no-change refresh.
  • Unload fact arrays outside the active allowance interval after durable persistence.
  • Run pure usage evaluation away from MainActor and publish only the latest generation.
  • Read rollout and persisted fact JSONL incrementally with bounded working memory.
  • Bound app-server response lines and fail cleanly when the limit is exceeded.
  • Validate allowance windows and use overflow-safe token and persisted-counter arithmetic.
  • Add end-to-end regression tests and representative performance measurements.

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions