Skip to content

fix(#582): resume the continuation once a held terminal append drains - #661

Merged
zgeoff merged 9 commits into
mainfrom
582-continuation-dead-end
Jul 18, 2026
Merged

fix(#582): resume the continuation once a held terminal append drains#661
zgeoff merged 9 commits into
mainfrom
582-continuation-dead-end

Conversation

@zgeoff

@zgeoff zgeoff commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Description

Closes #582

A continuation that couldn't start after a terminal checkpoint (a same-row race, or a transport
failure on the follow-up startActivity) now leaves a pending record instead of dead-ending the
avatar; the next resync consults it and starts the row once it reads closed.

  • WorkerContext gains a PendingContinuation record; runContinuation sets it on a same-row
    CONFLICT or a transport failure, and clears it when the player picks a new activity.
  • A new continue ResyncPlan kind targets a non-active row matching the pending continuation
    (a stale pending naming a different row is ignored, and a cap still wins); reconnect now also
    resyncs when a pending continuation exists, not only a remembered resyncAvatarID.
  • The resync handler applies continue: budget gate mirrors halt-at-boundary, adopts a fresh
    CONFLICT row like runContinuation itself, and clears/reports through the existing
    resync-failure and offline paths on other outcomes.
  • Doc note in docs/architecture/game-simulation.md's offline-progress section.

Testing

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

zgeoff added 5 commits July 18, 2026 19:16
runContinuation loses the "wanted to start next" intent on a same-row CONFLICT
or a transport failure, stranding play once the terminal append it was
racing eventually drains. Record it on the worker context instead, clearing
it once a player picks a new activity, and extend the reconnect trigger to
resync for a pending continuation as well as a remembered resyncAvatarID.
A non-active row matching a pending continuation's target row plans
'continue' instead of 'none', so a resync can start the row the worker
wanted once the terminal append that closed it is acknowledged. A capped
row still rebases, and a pending naming a different row is stale and
ignored.
applyContinue starts the row a pending continuation wanted once its target
reads closed: a budget already spent halts at the boundary, a fresh
never-appended CONFLICT row is adopted directly, any other defined error
clears the pending record and reports through the resync failure status, and
a transport failure keeps it for the next reconnect. Cover both of the
issue's repro sequences end to end against the mocked stateful backend.
Sorts the merged ORPCError/isDefinedError import and teaches
pickLatestActivityID about the continue plan's activity-shaped
context, both surfaced by rebasing onto main's independent
failure-action and checkpoint-sweep work.
@coderabbitai

coderabbitai Bot commented Jul 18, 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 Plus

Run ID: 38f4a96a-9cf8-4fbb-a73d-3c06c88d5bcf

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
📝 Walkthrough

Walkthrough

Changes

Pending continuation recovery

Layer / File(s) Summary
Continuation contracts and planning
libs/game/idle-client/src/worker/types.ts, libs/game/idle-client/src/resync/*, libs/game/idle-client/src/test-utils/create-stub-worker-context.ts
Adds PendingContinuation, propagates it through resync inputs, and introduces the continue resync plan for matching closed activity rows.
Failure recording and reconnect wiring
libs/game/idle-client/src/worker/run-continuation.ts, libs/game/idle-client/src/worker/create-worker-runtime.ts, libs/game/idle-client/src/worker/handle-set-activity-message.ts, libs/game/idle-client/src/worker/run-continuation.test.ts
Records continuation intents for retryable failures, exposes them through worker context, resumes reconnect handling, and clears them on explicit activity changes.
Continuation resync execution
libs/game/idle-client/src/worker/handle-request-resync-message.ts, libs/game/idle-client/src/worker/handle-request-resync-message.test.ts
Starts continued activities, handles budget and transport errors, classifies defined failures, emits status messages, and validates pending-state transitions.
Runtime integration and documentation
libs/game/idle-client/src/worker/create-worker-runtime.test.ts, libs/game/idle-client/package.json, docs/architecture/game-simulation.md
Adds mocked transport and clock helpers, end-to-end conflict and reconnect tests, the zod test dependency, and offline-progress documentation.
Estimated code review effort: 4 (Complex) ~60 minutes

Possibly related PRs

  • zgeoff/vers#580: Adds the resync and worker continuation plumbing extended by this change.
  • zgeoff/vers#613: Refactors the test suites that this change extends with pending-continuation coverage.
  • zgeoff/vers#642: Changes resync outcome handling in the same worker module.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.82% 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
Linked Issues check ✅ Passed The changes implement pending continuations, the new continue plan, reconnect handling, and stop/cap/stale paths required by #582.
Out of Scope Changes check ✅ Passed The package, docs, tests, and runtime changes all support the continuation-resync fix; no unrelated additions stand out.
Title check ✅ Passed The title clearly describes the main change: resuming a continuation after a held terminal append drains.
Description check ✅ Passed The description matches the changeset and accurately summarizes the pending continuation and resync behavior.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 582-continuation-dead-end

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

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@libs/game/idle-client/src/worker/create-worker-runtime.ts`:
- Around line 258-261: Update the avatarID selection in the reconnect flow
around handleRequestResyncMessage to prefer pendingContinuation?.avatarID over
resyncAvatarID, while retaining null as the fallback. Add coverage for the case
where resyncAvatarID is avatar A and the pending continuation is avatar B,
asserting that avatar B is used for resynchronization.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 35dbb4c1-ec1f-422f-8e74-440792ddf9bd

📥 Commits

Reviewing files that changed from the base of the PR and between fdd27d8 and 5933e5f.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock, !bun.lock
📒 Files selected for processing (15)
  • docs/architecture/game-simulation.md
  • libs/game/idle-client/package.json
  • libs/game/idle-client/src/resync/plan-resync.test.ts
  • libs/game/idle-client/src/resync/plan-resync.ts
  • libs/game/idle-client/src/resync/run-resync.ts
  • libs/game/idle-client/src/resync/types.ts
  • libs/game/idle-client/src/test-utils/create-stub-worker-context.ts
  • libs/game/idle-client/src/worker/create-worker-runtime.test.ts
  • libs/game/idle-client/src/worker/create-worker-runtime.ts
  • libs/game/idle-client/src/worker/handle-request-resync-message.test.ts
  • libs/game/idle-client/src/worker/handle-request-resync-message.ts
  • libs/game/idle-client/src/worker/handle-set-activity-message.ts
  • libs/game/idle-client/src/worker/run-continuation.test.ts
  • libs/game/idle-client/src/worker/run-continuation.ts
  • libs/game/idle-client/src/worker/types.ts

Comment thread libs/game/idle-client/src/worker/create-worker-runtime.ts Outdated
The pending-continuation record no longer snapshots the dying simulation's
failure action: the worker context now holds the durable, reconciled value,
so a preference changed while the intent waited still applies, and the
fragile read-after-stop ordering disappears. Also covers the continue
apply's CONFLICT-adopt branch with a test.
@zgeoff zgeoff changed the title feat(#582): resync a continuation left dead-ended by an unacknowledged terminal append fix(#582): resume the continuation once a held terminal append drains Jul 18, 2026
zgeoff added 3 commits July 18, 2026 19:44
The remembered resync avatar can predate a pending continuation recorded
for another avatar; picking it first would strand the continuation on
every reconnect.
The worker runtime takes a now option beside timestep and client, so the
fast-clock test stand-in drives the tick loop by injection instead of
patching the global performance.now — the restore-ordering footgun goes
with it. The fail-first transport handler moves to test-utils per the
stand-in convention, and the authed-client helper dissolves into the
per-test inline sequence its sibling suites already use.
@zgeoff
zgeoff merged commit b3739c0 into main Jul 18, 2026
6 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.

continuation dead-ends after an unacknowledged terminal append

1 participant