Skip to content

refactor(#912): collapse resync serialization into the lifecycle mailbox - #943

Merged
zgeoff merged 4 commits into
mainfrom
912-resync-mailbox-coalescing
Aug 17, 2026
Merged

refactor(#912): collapse resync serialization into the lifecycle mailbox#943
zgeoff merged 4 commits into
mainfrom
912-resync-mailbox-coalescing

Conversation

@zgeoff

@zgeoff zgeoff commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Description

Closes #912

Introduces createLifecycleMailbox(), collapsing with-lifecycle-turn.ts's tail-queue-and-report-fault turn wrapper and the resync single-flight/held-claim bookkeeping into one owner. Resync coalescing becomes a private ticket inside the mailbox: a non-claiming call is dropped while one is queued or running, a claiming call is held one deep with latest-arrival-wins, and the queued body is prepared synchronously at both accept and requeue so cancellation signals are captured fresh each run.

  • WorkerContext drops its six lifecycle/resync accessors for one getMailbox(): LifecycleMailbox
  • run-resync-turn.ts is now a thin binder delegating to context.getMailbox().runResyncTurn(...), its exported signature unchanged
  • run-simulation.ts, handle-start-activity-message.ts, and the runtime's onEvicted callback call context.getMailbox().runTurn(...)
  • with-lifecycle-turn.ts and its test are deleted, and the stub worker context now builds a real mailbox
  • New create-lifecycle-mailbox.test.ts covers queue ordering, cross-kind serialization, fault reporting, and the full coalescing policy
  • run-resync-turn.test.ts swaps its isResyncInFlight() postconditions for behavioral probes and adds a case for an external resync queuing behind an inline resync flow

Testing

  • bun run typecheck passes
  • bun run test passes
  • bun run lint passes
  • New tests added for new functionality

zgeoff added 3 commits August 17, 2026 11:20
Three stacked mechanisms — the lifecycle tail, the resync in-flight
flag, and the 1-deep held-claim queue — served one serialization
policy. Collapse them into create-lifecycle-mailbox.ts, a single
closure-owned mailbox exposed through WorkerContext.getMailbox().
Behavior is unchanged: turns still run strictly one at a time and
never reject, and resync coalescing still drops a non-claiming call
during the drop window and holds one claiming call, latest wins.
Wait for the inline resync's broadcast before the external call arrives, so
the new pinning test actually lands mid-window instead of racing ahead of
the queued turn's own microtask start. Replace the three conditional gate
selections in the mailbox coalescing tests with a per-avatar gate lookup, per
the no-branching-in-test-bodies rule.
The pinning test for behavior (e) waited on the inline resync's own
terminal broadcast before firing the external call, so by the time
waitFor returned the inline flow had already settled — the arrival
never actually landed inside the drop window a regression could leave
open. Gate the stub submitter's flushHeld on a test-controlled promise
instead, and wait for it to be called: that pauses the inline flow
strictly inside its own execution, so the external call now arrives
while the mailbox's resync ticket is genuinely still held.
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ace83231-0377-4915-9205-88029130584e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: ea8b1162-888c-4683-8489-d97729480ac1

📥 Commits

Reviewing files that changed from the base of the PR and between 3786cbf and 0a86630.

📒 Files selected for processing (11)
  • libs/game/idle-client/src/test-utils/create-stub-worker-context.ts
  • libs/game/idle-client/src/worker/create-lifecycle-mailbox.test.ts
  • libs/game/idle-client/src/worker/create-lifecycle-mailbox.ts
  • libs/game/idle-client/src/worker/create-worker-runtime.ts
  • libs/game/idle-client/src/worker/handle-start-activity-message.ts
  • libs/game/idle-client/src/worker/run-resync-turn.test.ts
  • libs/game/idle-client/src/worker/run-resync-turn.ts
  • libs/game/idle-client/src/worker/run-simulation.ts
  • libs/game/idle-client/src/worker/types.ts
  • libs/game/idle-client/src/worker/with-lifecycle-turn.test.ts
  • libs/game/idle-client/src/worker/with-lifecycle-turn.ts
💤 Files with no reviewable changes (2)
  • libs/game/idle-client/src/worker/with-lifecycle-turn.ts
  • libs/game/idle-client/src/worker/with-lifecycle-turn.test.ts

Included review availability: 4 reviews are currently available. Based on recent review activity, included reviews refill at 5 per hour.


📝 Walkthrough

Walkthrough

The idle worker now uses a lifecycle mailbox to serialize lifecycle turns, report turn errors, and coalesce resync requests. Worker context, runtime handlers, resync execution, simulations, and tests now use the mailbox API.

Changes

Lifecycle mailbox consolidation

Layer / File(s) Summary
Mailbox behavior and tests
libs/game/idle-client/src/worker/create-lifecycle-mailbox.ts, libs/game/idle-client/src/worker/create-lifecycle-mailbox.test.ts
Adds serialized turn execution, error reporting, resync dropping, latest-claim retention, replay, and ordering tests.
Worker context and runtime wiring
libs/game/idle-client/src/worker/types.ts, libs/game/idle-client/src/worker/create-worker-runtime.ts
Replaces lifecycle-tail and explicit resync state with getMailbox() and mailbox-backed eviction handling.
Lifecycle turn integration
libs/game/idle-client/src/worker/handle-start-activity-message.ts, libs/game/idle-client/src/worker/run-simulation.ts, libs/game/idle-client/src/worker/with-lifecycle-turn.ts
Routes start, continuation, and eviction turns through the mailbox and removes the previous helper.
Resync flow integration and validation
libs/game/idle-client/src/worker/run-resync-turn.ts, libs/game/idle-client/src/worker/run-resync-turn.test.ts
Moves resync scheduling into the mailbox and validates follow-up, cancellation, failure, expiration, and inline resync behavior.
Stub context alignment
libs/game/idle-client/src/test-utils/create-stub-worker-context.ts
Updates the worker test context to create and expose a lifecycle mailbox.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to 0a866

This refactor is merge-ready after normal checks and review; no actionable merge-blocking risk remains.

Possibly related issues

  • Issue 911 — Covers the broader lifecycle mailbox consolidation that this PR implements.

Possibly related PRs

  • zgeoff/vers#722 — Earlier worker lifecycle consolidation that this PR continues with a mailbox abstraction.
  • zgeoff/vers#724 — Earlier lifecycle-tail implementation that this PR replaces with createLifecycleMailbox.
  • zgeoff/vers#732 — Related resync scheduling and lifecycle coordination changes in the idle worker.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes consolidating resync serialization into the lifecycle mailbox.
Description check ✅ Passed The description directly explains the mailbox refactor, coalescing policy, affected components, tests, and validation results.
Linked Issues check ✅ Passed The changes implement the linked issue objectives, including mailbox serialization, resync coalescing, latest-claim retention, fresh cancellation capture, and state removal.
Out of Scope Changes check ✅ Passed The changed files support the linked issue by implementing, integrating, and testing lifecycle mailbox serialization and resync coalescing.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 912-resync-mailbox-coalescing

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

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 11 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread libs/game/idle-client/src/worker/create-lifecycle-mailbox.ts Outdated
A caller-supplied plan that throws while the ticket is set would
otherwise drop every later resync for the worker's lifetime; the
accept-through-settle span now clears the ticket in a finally, pinned
by a new mailbox test. Also rewords the factory JSDoc to stop naming
another declaration.
@zgeoff
zgeoff merged commit 20703b0 into main Aug 17, 2026
8 of 9 checks passed
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.

collapse the resync single-flight and held-claim into the lifecycle mailbox

1 participant