Skip to content

[Bug]: Event compaction restarts from the newest event after every restart and never reaches old imported v1 events #23659

Closed as not planned

Description

@tsmith165

Note

Claude Opus 5.5 in Claude Code, writing on behalf of @tsmith165. Measured on his Mac on 2026-10-22.

Before submitting

Area

apps/server

Steps to reproduce

  1. Use a database that was migrated from v1. It should hold a few million imported v1 thread events plus a few million v2 events.
  2. Start the server with no userdata/compacted-at file. Compaction starts 1 minute after startup.
  3. Restart the server before the pass finishes, for example through a nightly update, a quit or a crash.

Expected behavior

Compaction eventually finishes. It deletes the v1 events of imported threads, which compactEventStore treats as obsolete.

Actual behavior

On this database userdata/compacted-at has never been written, and no "Compacted orchestration history" line appears in the logs we have. 3,210,165 v1 thread events remain (about 7 GiB). Every one of them belongs to a thread whose orchestration_v2_legacy_imports.transcript_imported_at is set, which is the exact rule compactEventStore uses to mark them obsolete.

Database: 44.2 GiB, with 6,618,661 events, 3,479,494 command receipts and auto_vacuum = 0.

From the 0.1.2-nightly.20261022.3526 bundle:

  • compactEventStore pages 50 events at a time, downward from MAX(sequence). The v1 events have the lowest sequences (1 to 3,188,552), so a pass reaches them only after reading all 3.4M v2 events above them.
  • Progress is not saved. throughSequence starts again at MAX(sequence) on every start, and the marker is written only after a complete pass. A restart before then throws the work away. This machine restarts at least daily for nightly updates.
  • Each page also reads payloads ([Bug]: History compaction reads every event's payload on each pass (1.1 GB scanned to delete 60 events) #21290), which makes a full pass slower on a store this size.

Possible fixes:

  • Delete imported v1 events with an indexed statement before the paged scan, in sequence batches: DELETE FROM orchestration_events WHERE sequence BETWEEN ? AND ? AND application_event_version = 1 AND aggregate_kind = 'thread' AND stream_id IN (SELECT thread_id FROM orchestration_v2_legacy_imports WHERE transcript_imported_at IS NOT NULL). Its query plan uses idx_orchestration_events_application_sequence. Receipts work the same way with command_type = 'legacy'.
  • Persist the cursor, so a restart resumes where the last pass stopped.

Impact

Major degradation or frequent failure

Version or commit

0.1.2-nightly.20261022.3526

Environment

macOS (Darwin 25.5.0), T3 Code (Nightly) desktop app

Workaround

Quit the app, take a backup, run the batched DELETE above for events and legacy receipts, then run t3 doctor --fix. We are doing this today and can add the before and after numbers here.

Activity

  1. tsmith165 commented on Oct 22, 2026

    @tsmith165
    ContributorAuthor

    Note

    Claude Opus 5.5 in Claude Code, writing on behalf of @tsmith165. Correction, 2026-10-22.

    Correction: compaction did finish on this build, so I'm closing this issue. My report was wrong.

    The server started at 06:48 local on 0.1.2-nightly.20261022.3526. Its first compaction pass finished at 07:55:08, after about 66 minutes, and wrote userdata/compacted-at. It deleted the 3.2M imported v1 thread events and about 3.39M legacy receipts. I had read the missing marker as "never finishes". On earlier builds it was most likely interrupted by restarts or not yet fixed, but I can't show that.

    After the pass, t3 doctor --fix took the database from 44.17 GiB to 20.05 GiB. auto_vacuum is now 2, and quick_check returns ok.

    The point about progress still stands, but it is minor. A restart during that 66-minute pass would start it over, because the cursor isn't saved. The event-loop stall log had 66 records (27 over 5 s) during the pass and 4 (max 3.2 s) in the 19 minutes after it. Heavy agent activity also stopped in the same window, so I can't attribute those stalls to compaction.

    Sorry for the noise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions