Skip to content

id(world-replication): every subscription reads the whole journal inside the actor and retains the copy for the session (PR #4589) #4725

Closed

Description

@dezren39

Finding (from PR review, never addressed)

Every replication subscription materializes a complete copy of the world journal, and keeps it for the whole session:

  1. replication_snapshot does a full std::fs::read of the journal file, and it runs inside the world actor's serial command handler — so each new feed blocks that world's writes while the whole journal is read, and each subscriber gets its own full copy (CodeRabbit, Major).
  2. In the network layer, the owned initial snapshot local in serve_stream stays in scope across the indefinite update loop after send_snapshot finishes with it, so every long-lived follower retains a full historical journal copy for its entire session, even after compaction replaces that history (Codex, P2).

Raised on PR #4589:

No-response evidence

Still live on current main (verified 2026-11-03 via gh api raw reads)

  • pkgs/id/src/world_store.rs on main (:206-207): replication_snapshot still begins let bytes = std::fs::read(&self.path).
  • pkgs/id/src/world/actor.rs on main (:1577-1591): the ReplicationFeed handler still calls that snapshot synchronously in the actor's command handling.
  • pkgs/id/src/world_replication_net.rs on main (:114-127): serve_stream binds snapshot and passes &snapshot to send_snapshot; the owned buffer remains in scope for the whole update loop that follows.

Acceptance criteria

  • Feed setup no longer performs an unbounded full-journal read inside the actor's serial handler (incremental/bounded read, or the read moved off the actor), and the network layer drops the initial snapshot buffer once the initial transfer completes.
  • A test or measurement shows per-subscriber memory no longer scales with full journal size for the session's lifetime.
  • Or: a documented decision on this issue.

Found by the pr-comment-review job from unaddressed PR review comments.

Activity

  1. added
    kind/performancePerformance problem or optimization
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    on Nov 3, 2026
  2. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

  3. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 3, 2026
  4. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  5. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

    Triage verdict: CONFIRMED on current main (fresh gh api raw reads, 2026-11-03):

    1. pkgs/id/src/world_store.rs — replication_snapshot still begins let bytes = std::fs::read(&self.path): a full, unbounded journal read on every snapshot.
    2. pkgs/id/src/world/actor.rs — the ReplicationFeed handler subscribes, then synchronously calls journal.replication_snapshot() inside the actor's serial command handling, so each new feed blocks that world's writes for the duration of the whole-journal read.
    3. pkgs/id/src/world_replication_net.rs — serve_stream binds the owned snapshot, passes &snapshot to send_snapshot, and never drops it; the buffer stays in scope across the indefinite update loop that follows. The loop's Reset branch sends its own reset snapshot, so the initial buffer is not needed after the initial transfer — an explicit drop (or scoping the ownership to the transfer) satisfies that half.

    No decision is needed from Drew: the fix is well-scoped. Enqueued as task 6713 (small_fix, repo-health-code-pilot) carrying issue #4725's acceptance criteria, including a test/measurement showing per-subscriber memory no longer scales with full journal size for the session lifetime. Issue #4725 stays open for task 6713.

  6. 1 remaining item

  7. added
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Nov 3, 2026
  8. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: opencode-claimant
    • Queue task: 6713
    • Session / ID: ses_e5e60c2ca73ffeGixa3RwHDiLb
    • Route: opencode-route/workhorse · build

    OpenCode worker session bound and prompted for this already-claimed task.

  9. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  10. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 3, 2026
  11. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

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

    app/idPackage/app: id (pkgs/ or apps/ in this repo)kind/performancePerformance problem or optimizationpriority/normalOrdinary priority (the default)source/pr-comment-reviewFiled by the pr-comment-review jobtask/triageQueue packet kind: verify, reproduce, and route this item

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions