Skip to content

fix(events): harden durable replay recovery - #15054

Merged
teamleaderleo merged 1 commit into
manaflow-ai:mainfrom
teamleaderleo:fix/durable-event-replay-followup
Sep 27, 2026
Merged

teamleaderleo merged 1 commit into
manaflow-ai:mainfrom
teamleaderleo:fix/durable-event-replay-followup

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 27, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

The durable replay fix merged in #15030 still had four edge cases during startup recovery:

  • a reconnecting client could be closed as a slow consumer when the restored window exceeded the live queue limit;
  • sequence rebasing was only in memory, so later restarts could renumber the same records;
  • a subscriber joining while queued publishes were being flushed could miss events already added to the retained window;
  • if a log segment was unreadable, the next sequence could move backwards and reuse numbers from the skipped segment.

Changes

  • Add a replay path with separate accounting from live backpressure. The restored window remains bounded by the durable retention limit, while live events still enforce the configured pending-event limit.
  • Persist normalized event sequences back to the bounded JSONL segments after a legacy boot-segment rebase, preserving legacy_seq in memory for diagnostics.
  • Replay pending subscriptions from the retained window captured before each flush batch, so events arriving during the handoff are delivered exactly once.
  • Add an OS-locked events.jsonl.seq high-water sidecar. Recovery uses it when a segment cannot be read, and each durable publish allocates a unique sequence across cmux processes sharing the log.
  • Add regression coverage for replay backpressure, persistent rebasing, unreadable-segment high-water recovery, and the existing malformed-record gap behavior.

Validation

  • git diff --check
  • python3 scripts/verify-local.py --only swift-syntax --swift-changed origin/main
  • Native macOS XCTest/build execution is delegated to the repository CI because this checkout is running on Linux.

Changelog

  • Harden durable event replay across startup, log rotation, malformed segments, and concurrent writers.

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Hardens durable event replay recovery so restarts, log rotation, and unreadable segments no longer drop or renumber events.

  • Replays the restored window with separate accounting from live-event backpressure, so restored history is delivered in full before a subscription is treated as a slow consumer.
  • Persists normalized sequence numbers back to the JSONL segments after rebasing, and adds an OS-locked events.jsonl.seq sidecar that preserves the high-water mark when a segment can't be read.
  • Replays subscriptions from the retained window captured before each flush batch so events arriving during restore are delivered exactly once.
  • Adds regression tests for replay backpressure, persistent rebasing, and unreadable-segment recovery.

Written for commit 80f915a. Summary will update on new commits.

Review in cubic

@coderabbitai

coderabbitai Bot commented Sep 27, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 6 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 646d31a8-b418-4eb5-8b4c-e2f7d06a5ff4

📥 Commits

Reviewing files that changed from the base of the PR and between 7f97b0d and 80f915a.

📒 Files selected for processing (2)
  • Sources/CmuxEventBus.swift
  • cmuxTests/CmuxEventBusTests.swift

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Follow-up to the post-merge review of #15030 (Panda g1): the four concrete recovery failures are addressed here.

  • Restored events use a separate bounded replay queue, so a 4,096-event retained window cannot trip the 1,024-event live slow-consumer limit. Live backpressure is unchanged.
  • Legacy rebased sequences are written back to the bounded JSONL segments, so the same event keeps its cursor after later rotations/restarts.
  • Pending subscribers replay the retained window captured before each flush batch; queued publishes are then delivered once, covering subscribers that join mid-flush.
  • events.jsonl.seq is an OS-locked high-water sidecar. Recovery uses it when a segment is unreadable, and durable allocations are serialized across cmux processes so a skipped segment cannot cause sequence reuse.

The PR body documents the behavior and validation. Static checks are green; macOS compile admission is still running.

— Panda g1

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

— Toolbox g1 🔔 Reviewed the durable replay follow-up. The recovery changes preserve separate replay/live backpressure, persist sequence rebases, serialize cross-process high-water allocation, and cover malformed/unreadable segments with focused tests. Linux parse and diff checks pass; macOS compile admission is green and the remaining app-host lane is running. Enabling squash auto-merge.

@teamleaderleo
teamleaderleo enabled auto-merge (squash) September 27, 2026 19:08
@teamleaderleo
teamleaderleo merged commit 4e03ed2 into manaflow-ai:main Sep 27, 2026
62 of 63 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

Merge receipt for 80f915a879: every check was green at merge (15 verified; 16 skipped by policy). Full suite runs on main after merge.

rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 27, 2026
a64d59b tools: ui-lab renders view code in seconds; wire-app-sources.py (manaflow-ai#15049)
4e03ed2 fix(events): harden durable replay recovery (manaflow-ai#15054)
ac51546 Settings: native terminal theme gallery (manaflow-ai#14996)
867e7a0 Add native Ghostty option rows to Settings > Terminal (manaflow-ai#15005)
7f97b0d ui-tests: wait for static preflight when a reused compile skips the gate (manaflow-ai#15051)
c708e0c Add a chat view for the terminal's agent session (Claude Code, Codex) (manaflow-ai#14965)
b762a3d ci: the picker fetches kept bases' trees, not just checks their commits (manaflow-ai#15053)
2570eed docs: refresh and trim contributor build guidance (manaflow-ai#15050)
20019d3 ci: re-run by cause: host faults to Blacksmith, code failures back to the minis (manaflow-ai#15045)
36ee3e9 Add Warn Before Closing Workspace setting (manaflow-ai#14979)
4df2317 CI: run changed UI test classes in PRs, keep UI runs off Blacksmith, probe the GUI session (manaflow-ai#14964)
9efe05e Owned-pool sweeper: page the marker listing back to the runs it adopts (manaflow-ai#15033)
6361554 fix(events): restore durable replay across restarts (manaflow-ai#15030)
0bc5145 ci: place side lanes on the light minis one per idle side runner (manaflow-ai#15047)
9d4e92b ci: the E2E rule's queue-round reason names the owned pools the run may take (manaflow-ai#15044)
9e6e216 Dogfood the app from CI with JSON tours (manaflow-ai#14928)
fd3dcf6 ci: retry the picker's kept-base fetch and record how it went (manaflow-ai#15040)
3a64e0e Reload the Ghostty config when its files change, and show config errors (manaflow-ai#14859)
f412b05 test: hit-test the browser portal tab strip with its own click (manaflow-ai#15031)
64d5235 test: route the reopen-last-closed shortcut through the test's own window (manaflow-ai#15036)
7037079 ci: take the gui token in the E2E test job's step, not at job start (manaflow-ai#15037)

# Conflicts:
#	.github/workflows/ci-macos.yml
#	.github/workflows/ci.yml
#	.github/workflows/remote-daemon.yml
#	.github/workflows/test-e2e.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant