Skip to content

Persist ReviewMonitor-owned review history and logs locally #102

Description

@lynnswap

Parent: #96
Related: #99, #100, #103, #108, #110, #111

Product contract

The Codex app-server is the live execution/event transport. It is not the durable source of truth for ReviewMonitor history, sidebar membership, lifecycle timing, or displayed logs.

ReviewMonitor commits product review state and effective ordered log entries to a local SQLite database. Sidebar, detail, and authorized MCP operations read that committed product history, so app-server omissions, reconnects, refreshes, account/runtime transitions, and process restarts cannot erase it.

Selected implementation

Use direct GRDB 7.11.1 behind the existing CodexReview owner boundary.

An actual Swift 6/macOS 26 probe compared SQLiteData 1.9.0 with direct GRDB:

  • Both passed explicit-database, observation, migration rollback, error, cancellation, and close checks.
  • SQLiteData required avoiding its property-wrapper/global-default initialization path for fully explicit injection and resolved a substantially larger dependency/macro graph.
  • Direct GRDB exposed MainActor ValueObservation, explicit error callbacks, cancellable observation, transactions/migrations, and throwing close directly with a much smaller graph.

No GRDB type appears in a public or cross-target API.

Required owner model

  • One stable product review ID owns lifecycle, terminal kind/cause, duration accuracy, final result, current attempt, manual order, and internal source/reviewer thread linkage.
  • Attempt identity is composite (reviewID, attemptID); late old-attempt terminal cannot terminate the current attempt.
  • Effective log rows own immutable display ordinal and last mutation revision.
  • Every mutation increments one global database revision in the same transaction.
  • GRDB observations update one stable CodexReviewJob projection registry; the writer never directly publishes UI state.
  • UI query failure preserves last-good rows and exposes typed loading/loaded/failed state.
  • App-server runtime generations are shorter-lived than the app-lifetime history/database owner.
  • Raw deltas without stable upstream IDs are consumed once in connection order and never treated as a replay journal.

Retention and migration

Acceptance criteria

  • One logical review produces one durable row and one human-facing log; internal reviewer JSON never becomes product content.
  • Completed duration/result/log remain identical after app restart without fetching the thread from app-server.
  • During app-server omission/failure/reconnect/refresh or auth/runtime transition, last committed history stays visible.
  • Writer transaction failure publishes nothing; query failure preserves last-good data and visible error.
  • Startup orphan reviews stop advancing and show exact, lower-bound, or unavailable duration truthfully.
  • Duplicate stable receipts are idempotent; conflicting duplicates fail at the ingestion owner.
  • Current live attempt, old attempt, reviewer child, and source thread cannot satisfy one another's terminal.
  • Migration/open/read/write/close, paging, deletion, order, large history, process interruption, and restart are deterministically tested.
  • GRDB observations/cancellables and database close leave no callback/read/write after application close.
  • Signed-out and stopped/failed runtime states do not hide durable history.

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