Skip to content

fix: harden TUI API recovery states#269

Merged
TraderSamwise merged 8 commits into
masterfrom
fix/tui-zombie-recovery
Jun 30, 2026
Merged

fix: harden TUI API recovery states#269
TraderSamwise merged 8 commits into
masterfrom
fix/tui-zombie-recovery

Conversation

@TraderSamwise

@TraderSamwise TraderSamwise commented Jun 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • harden TUI API recovery and pending-state handling so stale async responses cannot overwrite local in-flight state
  • keep best-effort notification context telemetry off the repair path
  • make project-service desktop-state reads serve cached state while refreshing in the background
  • clean stale duplicate dashboard windows during restart and escalate long-running guard overlays to aimux restart instead of zombie waiting

Validation

  • yarn vitest src/multiplexer/runtime-guard.test.ts src/multiplexer/dashboard-control.test.ts src/multiplexer/tui-api-runtime.test.ts src/multiplexer/tui-runtime-mutations.test.ts src/runtime-restart.test.ts src/metadata-server.test.ts
  • yarn vitest src/multiplexer/session-launch.test.ts
  • yarn typecheck
  • yarn lint
  • yarn build
  • pre-push: yarn typecheck && yarn lint && yarn test (154 files, 2047 tests)
  • local release installed: local-guard-escalation-c2198d2
  • aimux doctor versions clean for /Users/sam/cs/aimux

Summary by CodeRabbit

  • New Features

    • Runtime guard overlay now adds a conditional waiting state and escalates to an “aimux restart” prompt after prolonged non-OK conditions.
    • Expanded dashboard pending-action synthesis to cover more session/service/worktree scenarios as updates settle.
  • Bug Fixes

    • Desktop-state snapshots now refresh asynchronously when stale.
    • Auth misconfiguration now renders an in-app error instead of failing during setup.
    • Dashboard restore/settlement and worktree removal now align with raw state availability; SSE failures no longer trigger control-plane repair.
  • Chores

    • Build/release tooling updates include new EAS environment fields and improved .env.local handling for release environment checks.

@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app Ready Ready Preview, Comment Jun 30, 2026 10:56am

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9f8a27b4-33aa-40a5-9d9b-081c765aa119

📥 Commits

Reviewing files that changed from the base of the PR and between 20eef28 and 5112200.

📒 Files selected for processing (1)
  • src/multiplexer/worktrees.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/multiplexer/worktrees.test.ts

📝 Walkthrough

Walkthrough

Updates app release/auth startup handling and changes dashboard settlement, recovery, runtime-guard, caching, and restart flows across the multiplexer and related tests.

Changes

App release config and auth

Layer / File(s) Summary
Release config and scripts
app/eas-release.config.json, app/package.json, app/scripts/check-release-env.js, app/lib/version.ts
Adds EAS environment settings, wraps release scripts with eas env:exec production --non-interactive, merges .env.local into release env validation, and updates OTA version metadata.
Auth configuration error screen
app/lib/auth.tsx
Adds auth configuration validation, changes local-mode detection, and renders an inline configuration error screen with React Native layout and styles.

Dashboard, multiplexer, and runtime behavior

Layer / File(s) Summary
Pending action synthesis expansion
src/dashboard/pending-actions.ts, src/dashboard/pending-actions.test.ts
Widens synthesis for more pending kinds, adds worktree removing markers, and updates tests to expect optimistic pending rows.
Raw dashboard caches and pending reapply
src/multiplexer/dashboard-model.ts, src/multiplexer/dashboard-model-service.test.ts, src/multiplexer/persistence-methods.ts, src/multiplexer/persistence-methods.test.ts
Stores raw dashboard snapshot fields, rebuilds pending views from raw caches, seeds worktree removal from cached or discovered worktrees, and verifies raw cache population and clearing of synthetic rows.
Raw-cache-aware dashboard settlement
src/multiplexer/dashboard-ops.ts, src/multiplexer/dashboard-ops.test.ts
Uses raw session/service lookups for settlement, changes live predicates and render timing, removes inputEpoch from lifecycle capture, and updates stop/resume/graveyard/service/create settlement tests.
Worktree settlement via raw absence
src/multiplexer/worktrees.ts, src/multiplexer/worktrees.test.ts
Adds worktreeSeed, raw worktree lookup, and stable raw-absence waiting for graveyard settlement, with tests switching to raw worktree cache clearing.
Offline session activation
src/multiplexer/dashboard-interaction.ts, src/multiplexer/dashboard-interaction.test.ts
After resuming an offline or exited session and refreshing, the code now renders immediately and returns "opened" without waiting for a live tmux window.
TUI request recovery and notification context
src/multiplexer/tui-api-runtime.ts, src/multiplexer/tui-api-runtime.test.ts, src/multiplexer/tui-runtime-mutations.ts, src/multiplexer/tui-runtime-mutations.test.ts, src/multiplexer/dashboard-control.test.ts, src/multiplexer/session-launch.test.ts
Adds recoverOnFailure, changes refresh failures to degraded, makes notification-context mutations non-recoverable with a timeout, removes requeueing, and updates the related call expectations and retry tests.
SSE recovery without control-plane repair
src/multiplexer/project-event-stream.ts, src/multiplexer/project-event-stream.test.ts
Removes the repair call during recovery and updates dashboard refresh expectations to resync without repair.
Runtime guard escalation overlay
src/multiplexer/runtime-guard.ts, src/multiplexer/index.ts, src/tui/screens/overlay-renderers.ts, src/multiplexer/runtime-guard.test.ts
Adds runtime-guard escalation timing and waiting state, tracks active duration, and conditionally renders restart instructions instead of always showing waiting text.
Desktop-state stale-while-revalidate
src/metadata-server.ts, src/metadata-server.test.ts
Returns cached desktop-state immediately and schedules background refresh when stale.
Restart cleanup for stale dashboard windows
src/runtime-restart.ts, src/runtime-restart.test.ts
Adds host-session dashboard cleanup during restart and verifies stale duplicate dashboard windows are removed.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • TraderSamwise/aimux#1: Both PRs directly modify the dashboard pending-action synthesis behavior in src/dashboard/pending-actions.ts.
  • TraderSamwise/aimux#196: Both PRs touch src/multiplexer/project-event-stream.ts and its SSE recovery flow.
  • TraderSamwise/aimux#216: Both PRs modify the runtime-guard overlay pipeline in src/multiplexer/runtime-guard.ts and src/tui/screens/overlay-renderers.ts.

Poem

🐇 I hop through raw caches, bright and neat,
Pending rows now know their seat.
When guards grow old, they call for rest,
And stale windows get their cleanup test.
Release scripts hum, auth screens glow—
The dashboard flows where rabbits go.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the PR’s main theme of hardening TUI API recovery and state-handling behavior.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/tui-zombie-recovery

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

@TraderSamwise

Copy link
Copy Markdown
Owner Author

Independent review finding (by design):

  • src/multiplexer/dashboard-interaction.ts: reviewer noted that resuming an offline agent no longer opens/focuses the tmux window after refresh. This is intentional for this PR and covered by the test resumes and refreshes an offline dashboard agent without opening it: onlining an existing offline agent should start it and leave the user on the dashboard; pressing Enter again once it is ready focuses it.

@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: 4

🤖 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 `@src/multiplexer/persistence-methods.ts`:
- Around line 942-957: The fallback worktree seed lookup in persistence-methods
should be best-effort so it cannot break removal flow. In the worktree removal
path around the cachedWorktree/listedWorktree logic, wrap the
listDesktopWorktrees() call and the derived find lookup so any exception is
swallowed and worktreeAction setup still continues. Keep the
pendingRemovals/setWorktreeAction state updates in place and ensure the removal
promise cannot remain unsettled if the seed lookup fails.

In `@src/multiplexer/worktrees.ts`:
- Around line 74-78: findRawWorktreeForSettlement currently assumes either
dashboardRawWorktreeGroupsCache or dashboardWorktreeGroupsCache is always an
array, so calling .find can throw when both are unset. Update this helper to
guard the fallback cache in the same way beginWorktreeRemoval treats it as
optional: if neither cache is an array, return undefined before searching, and
keep the same lookup logic using sameWorktreePath and the WorktreeHost cache
fields.
- Around line 94-115: The stable-absence wait in
waitForStableDashboardWorktreeAbsence is bailing out too early when
refreshDashboardModelForWorktreeSettlement returns false on an unchanged
snapshot, which prevents the stable window from completing. Update the loop so
an unchanged refresh does not immediately return false; instead keep polling and
only fail on an actual refresh/lifecycle error, while preserving the
missingSince timing and the findRawWorktreeForSettlement check for path
disappearance.

In `@src/runtime-restart.ts`:
- Around line 376-383: Use the already resolved dashboard session instead of
recomputing it in cleanupHostDashboardSession(); the current call to
tmux.getProjectSession(projectRoot).sessionName can drift from the authoritative
resolvedTarget.dashboardSession.sessionName. Update
cleanupHostDashboardSession() (and the other matching call site) to accept and
pass through the resolved dashboard session name from the target/restart
resolution path, then use that value when calling cleanupStaleDashboardLinks so
stale windows are cleaned from the correct session.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: b962ee52-7bda-45d5-88c6-05422ab0e5e3

📥 Commits

Reviewing files that changed from the base of the PR and between 17293eb and 138d69b.

📒 Files selected for processing (33)
  • app/eas-release.config.json
  • app/lib/auth.tsx
  • app/lib/version.ts
  • app/package.json
  • app/scripts/check-release-env.js
  • src/dashboard/pending-actions.test.ts
  • src/dashboard/pending-actions.ts
  • src/metadata-server.test.ts
  • src/metadata-server.ts
  • src/multiplexer/dashboard-control.test.ts
  • src/multiplexer/dashboard-interaction.test.ts
  • src/multiplexer/dashboard-interaction.ts
  • src/multiplexer/dashboard-model-service.test.ts
  • src/multiplexer/dashboard-model.ts
  • src/multiplexer/dashboard-ops.test.ts
  • src/multiplexer/dashboard-ops.ts
  • src/multiplexer/index.ts
  • src/multiplexer/persistence-methods.test.ts
  • src/multiplexer/persistence-methods.ts
  • src/multiplexer/project-event-stream.test.ts
  • src/multiplexer/project-event-stream.ts
  • src/multiplexer/runtime-guard.test.ts
  • src/multiplexer/runtime-guard.ts
  • src/multiplexer/session-launch.test.ts
  • src/multiplexer/tui-api-runtime.test.ts
  • src/multiplexer/tui-api-runtime.ts
  • src/multiplexer/tui-runtime-mutations.test.ts
  • src/multiplexer/tui-runtime-mutations.ts
  • src/multiplexer/worktrees.test.ts
  • src/multiplexer/worktrees.ts
  • src/runtime-restart.test.ts
  • src/runtime-restart.ts
  • src/tui/screens/overlay-renderers.ts

Comment thread src/multiplexer/persistence-methods.ts
Comment thread src/multiplexer/worktrees.ts Outdated
Comment thread src/multiplexer/worktrees.ts
Comment thread src/runtime-restart.ts Outdated

@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 `@src/multiplexer/worktrees.test.ts`:
- Around line 861-877: The test around beginWorktreeRemoval should explicitly
verify the intermediate state after the first refreshDashboardModelFromService()
returns false, instead of only asserting the final success path. Update the
scenario in src/multiplexer/worktrees.test.ts to check that footerFlash is still
empty and the worktreeRemovalJob remains set before applyRawWorktrees clears the
pending worktrees, using the existing beginWorktreeRemoval,
attachPendingReapply, and refreshDashboardModelFromService setup.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: adfe0b59-5c17-4ab1-9b0c-c1057fcccf45

📥 Commits

Reviewing files that changed from the base of the PR and between 138d69b and 1ce41e5.

📒 Files selected for processing (6)
  • src/multiplexer/persistence-methods.test.ts
  • src/multiplexer/persistence-methods.ts
  • src/multiplexer/worktrees.test.ts
  • src/multiplexer/worktrees.ts
  • src/runtime-restart.test.ts
  • src/runtime-restart.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/runtime-restart.test.ts
  • src/multiplexer/worktrees.ts
  • src/multiplexer/persistence-methods.ts

Comment thread src/multiplexer/worktrees.test.ts
@TraderSamwise

Copy link
Copy Markdown
Owner Author

Independent sub-agent review found one medium issue: event-driven TUI refreshes were using the non-forced desktop-state path, which could consume stale cached state after a real SSE update. Fixed in 20eef28 by forcing dashboard model refreshes for project-event refreshes and updating the project-event-stream regression tests.

@TraderSamwise
TraderSamwise merged commit 8d72f27 into master Jun 30, 2026
3 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.

1 participant