fix(server): reconcile active sessions after restart - #7463

Open
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state
Open

fix(server): reconcile active sessions after restart#7463
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state

Conversation

@ayubun

@ayubunayubun commented Aug 19, 2026

Copy link
Copy Markdown

What Changed

Reconciles provider sessions that a previous server process left running or starting before the replacement process accepts commands. Persisted runtime bindings are marked stopped, stale active turns are cleared, and provider resume cursors are preserved. Pending approval and Input cards tied to stopped sessions are marked stale on submit, so they clear instead of repeating No active provider session errors.

I have been running this reconciliation locally as my t3-code backend. It cleared my stale Working threads and preserved their resume cursors.

Why

Restarting the server while work is active can leave threads stuck on Working (or Input) forever because the replacement process inherits session state for provider processes that no longer exist. Running this reconciliation during startup repairs those threads without calling provider stop or abort, keeps the conversation resumable, and gives stale provider callbacks an actionable restart-turn path.

Fixes#4584

UI Changes

For the Input state, this fix has a minor UI change.

Before: A dead provider leaves the Input card open, and every Submit adds another generic No active provider session failure.

Before: repeated provider input failures with the stale Input card still open

After:Submit marks the callback stale, removes the dead Input card, and returns the thread to the normal composer with guidance to restart the turn.

After: stale callback guidance and the normal composer restored

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Models used

  • openai/gpt-5.6-sol: ~65%
  • anthropic/claude-fable-5: ~35%

Note

Medium Risk
Startup now mutates persisted session bindings and orchestration session state before accepting commands; a failed session.set can fail the whole boot. Binding write errors are logged and skipped.

Overview
Stops threads that a previous process left running or starting before the new server accepts commands, so they no longer sit on Working/Input forever.

reconcileProviderSessions runs at the prepared startup boundary. It marks matching directory bindings stopped (resume cursor kept, activeTurnId cleared) and dispatches thread.session.set the same way. Binding I/O failures are warnings; a failed session settle still fails startup.

Submitting leftover approval or user-input cards on a stopped session now records the existing stale-request failure instead of “No active provider session,” so the card can clear and the user can restart the turn.

Reviewed by Cursor Bugbot for commit 16271a3. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Reconcile active provider sessions on server restart and improve stale response errors

  • Adds reconcileProviderSessions to serverRuntimeStartup.ts, which reads threads from ProjectionSnapshotQuery, transitions any running or starting sessions to stopped, clears activeTurnId in provider bindings, and dispatches thread.session.set commands before the launcher trial begins.
  • Updates the thread.approval.respond and thread.user-input.respond handlers in ProviderCommandReactor.ts to use stalePendingRequestDetail with the request id instead of a generic 'no active session' message in failure details.
  • Risk: reconcileProviderSessions is called before launcher.prepareTrial; if OrchestrationEngine.dispatch fails for a running session, the startup error propagates and may block server startup.

Macroscope summarized 16271a3.

@coderabbitai

coderabbitaiBot commented Aug 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a92ee44-e5e6-49c9-9981-0189a4dacbf1

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

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-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@macroscopeapp

macroscopeappBot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds new server startup logic that forcibly reconciles (stops) any sessions that were in 'running' or 'starting' state when the server restarts. This is a significant behavioral change to the startup sequence that affects session lifecycle management and warrants review by someone familiar with the orchestration system.

You can add or adjust custom eligibility rules. Learn more.

@ayubunayubun changed the title fix(server): settle recovered OpenCode idle sessionsfix(server): reconcile OpenCode idle state after restartAug 19, 2026
@ayubunayubun changed the title fix(server): reconcile OpenCode idle state after restartfix(server): reconcile active sessions after restartAug 19, 2026
@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubun marked this pull request as draft August 19, 2026 20:09
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubunforce-pushed the fix/interrupted-session-state branch 6 times, most recently from deae80e to 008f358CompareAugust 20, 2026 05:04
Comment threadapps/server/src/serverRuntimeStartup.ts

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Effect service conventions review: one convention issue found in the new startup reconciliation tests (standalone FooShape type used instead of the inferred Foo["Service"]). The rest of the changed code (namespace imports, dependency acquisition via yield* Service, Effect.catch on a fully handled error channel, no runtime escapes) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: App restart during active turns leaves threads stuck on Working forever, with no startup reconciliation of dead provider sessions

1 participant

@ayubun
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(server): reconcile active sessions after restart - #7463

Open
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state
Open

fix(server): reconcile active sessions after restart#7463
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state

Conversation

@ayubun

@ayubunayubun commented Aug 19, 2026

Copy link
Copy Markdown

What Changed

Reconciles provider sessions that a previous server process left running or starting before the replacement process accepts commands. Persisted runtime bindings are marked stopped, stale active turns are cleared, and provider resume cursors are preserved. Pending approval and Input cards tied to stopped sessions are marked stale on submit, so they clear instead of repeating No active provider session errors.

I have been running this reconciliation locally as my t3-code backend. It cleared my stale Working threads and preserved their resume cursors.

Why

Restarting the server while work is active can leave threads stuck on Working (or Input) forever because the replacement process inherits session state for provider processes that no longer exist. Running this reconciliation during startup repairs those threads without calling provider stop or abort, keeps the conversation resumable, and gives stale provider callbacks an actionable restart-turn path.

Fixes#4584

UI Changes

For the Input state, this fix has a minor UI change.

Before: A dead provider leaves the Input card open, and every Submit adds another generic No active provider session failure.

Before: repeated provider input failures with the stale Input card still open

After:Submit marks the callback stale, removes the dead Input card, and returns the thread to the normal composer with guidance to restart the turn.

After: stale callback guidance and the normal composer restored

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Models used

  • openai/gpt-5.6-sol: ~65%
  • anthropic/claude-fable-5: ~35%

Note

Medium Risk
Startup now mutates persisted session bindings and orchestration session state before accepting commands; a failed session.set can fail the whole boot. Binding write errors are logged and skipped.

Overview
Stops threads that a previous process left running or starting before the new server accepts commands, so they no longer sit on Working/Input forever.

reconcileProviderSessions runs at the prepared startup boundary. It marks matching directory bindings stopped (resume cursor kept, activeTurnId cleared) and dispatches thread.session.set the same way. Binding I/O failures are warnings; a failed session settle still fails startup.

Submitting leftover approval or user-input cards on a stopped session now records the existing stale-request failure instead of “No active provider session,” so the card can clear and the user can restart the turn.

Reviewed by Cursor Bugbot for commit 16271a3. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Reconcile active provider sessions on server restart and improve stale response errors

  • Adds reconcileProviderSessions to serverRuntimeStartup.ts, which reads threads from ProjectionSnapshotQuery, transitions any running or starting sessions to stopped, clears activeTurnId in provider bindings, and dispatches thread.session.set commands before the launcher trial begins.
  • Updates the thread.approval.respond and thread.user-input.respond handlers in ProviderCommandReactor.ts to use stalePendingRequestDetail with the request id instead of a generic 'no active session' message in failure details.
  • Risk: reconcileProviderSessions is called before launcher.prepareTrial; if OrchestrationEngine.dispatch fails for a running session, the startup error propagates and may block server startup.

Macroscope summarized 16271a3.

@coderabbitai

coderabbitaiBot commented Aug 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a92ee44-e5e6-49c9-9981-0189a4dacbf1

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

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-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@macroscopeapp

macroscopeappBot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds new server startup logic that forcibly reconciles (stops) any sessions that were in 'running' or 'starting' state when the server restarts. This is a significant behavioral change to the startup sequence that affects session lifecycle management and warrants review by someone familiar with the orchestration system.

You can add or adjust custom eligibility rules. Learn more.

@ayubunayubun changed the title fix(server): settle recovered OpenCode idle sessionsfix(server): reconcile OpenCode idle state after restartAug 19, 2026
@ayubunayubun changed the title fix(server): reconcile OpenCode idle state after restartfix(server): reconcile active sessions after restartAug 19, 2026
@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubun marked this pull request as draft August 19, 2026 20:09
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubunforce-pushed the fix/interrupted-session-state branch 6 times, most recently from deae80e to 008f358CompareAugust 20, 2026 05:04
Comment threadapps/server/src/serverRuntimeStartup.ts

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Effect service conventions review: one convention issue found in the new startup reconciliation tests (standalone FooShape type used instead of the inferred Foo["Service"]). The rest of the changed code (namespace imports, dependency acquisition via yield* Service, Effect.catch on a fully handled error channel, no runtime escapes) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: App restart during active turns leaves threads stuck on Working forever, with no startup reconciliation of dead provider sessions

1 participant

@ayubun
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(server): reconcile active sessions after restart - #7463

Open
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state
Open

fix(server): reconcile active sessions after restart#7463
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state

Conversation

@ayubun

@ayubunayubun commented Aug 19, 2026

Copy link
Copy Markdown

What Changed

Reconciles provider sessions that a previous server process left running or starting before the replacement process accepts commands. Persisted runtime bindings are marked stopped, stale active turns are cleared, and provider resume cursors are preserved. Pending approval and Input cards tied to stopped sessions are marked stale on submit, so they clear instead of repeating No active provider session errors.

I have been running this reconciliation locally as my t3-code backend. It cleared my stale Working threads and preserved their resume cursors.

Why

Restarting the server while work is active can leave threads stuck on Working (or Input) forever because the replacement process inherits session state for provider processes that no longer exist. Running this reconciliation during startup repairs those threads without calling provider stop or abort, keeps the conversation resumable, and gives stale provider callbacks an actionable restart-turn path.

Fixes#4584

UI Changes

For the Input state, this fix has a minor UI change.

Before: A dead provider leaves the Input card open, and every Submit adds another generic No active provider session failure.

Before: repeated provider input failures with the stale Input card still open

After:Submit marks the callback stale, removes the dead Input card, and returns the thread to the normal composer with guidance to restart the turn.

After: stale callback guidance and the normal composer restored

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Models used

  • openai/gpt-5.6-sol: ~65%
  • anthropic/claude-fable-5: ~35%

Note

Medium Risk
Startup now mutates persisted session bindings and orchestration session state before accepting commands; a failed session.set can fail the whole boot. Binding write errors are logged and skipped.

Overview
Stops threads that a previous process left running or starting before the new server accepts commands, so they no longer sit on Working/Input forever.

reconcileProviderSessions runs at the prepared startup boundary. It marks matching directory bindings stopped (resume cursor kept, activeTurnId cleared) and dispatches thread.session.set the same way. Binding I/O failures are warnings; a failed session settle still fails startup.

Submitting leftover approval or user-input cards on a stopped session now records the existing stale-request failure instead of “No active provider session,” so the card can clear and the user can restart the turn.

Reviewed by Cursor Bugbot for commit 16271a3. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Reconcile active provider sessions on server restart and improve stale response errors

  • Adds reconcileProviderSessions to serverRuntimeStartup.ts, which reads threads from ProjectionSnapshotQuery, transitions any running or starting sessions to stopped, clears activeTurnId in provider bindings, and dispatches thread.session.set commands before the launcher trial begins.
  • Updates the thread.approval.respond and thread.user-input.respond handlers in ProviderCommandReactor.ts to use stalePendingRequestDetail with the request id instead of a generic 'no active session' message in failure details.
  • Risk: reconcileProviderSessions is called before launcher.prepareTrial; if OrchestrationEngine.dispatch fails for a running session, the startup error propagates and may block server startup.

Macroscope summarized 16271a3.

@coderabbitai

coderabbitaiBot commented Aug 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a92ee44-e5e6-49c9-9981-0189a4dacbf1

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

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-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@macroscopeapp

macroscopeappBot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds new server startup logic that forcibly reconciles (stops) any sessions that were in 'running' or 'starting' state when the server restarts. This is a significant behavioral change to the startup sequence that affects session lifecycle management and warrants review by someone familiar with the orchestration system.

You can add or adjust custom eligibility rules. Learn more.

@ayubunayubun changed the title fix(server): settle recovered OpenCode idle sessionsfix(server): reconcile OpenCode idle state after restartAug 19, 2026
@ayubunayubun changed the title fix(server): reconcile OpenCode idle state after restartfix(server): reconcile active sessions after restartAug 19, 2026
@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubun marked this pull request as draft August 19, 2026 20:09
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubunforce-pushed the fix/interrupted-session-state branch 6 times, most recently from deae80e to 008f358CompareAugust 20, 2026 05:04
Comment threadapps/server/src/serverRuntimeStartup.ts

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Effect service conventions review: one convention issue found in the new startup reconciliation tests (standalone FooShape type used instead of the inferred Foo["Service"]). The rest of the changed code (namespace imports, dependency acquisition via yield* Service, Effect.catch on a fully handled error channel, no runtime escapes) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: App restart during active turns leaves threads stuck on Working forever, with no startup reconciliation of dead provider sessions

1 participant

@ayubun
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(server): reconcile active sessions after restart - #7463

Open
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state
Open

fix(server): reconcile active sessions after restart#7463
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state

Conversation

@ayubun

@ayubunayubun commented Aug 19, 2026

Copy link
Copy Markdown

What Changed

Reconciles provider sessions that a previous server process left running or starting before the replacement process accepts commands. Persisted runtime bindings are marked stopped, stale active turns are cleared, and provider resume cursors are preserved. Pending approval and Input cards tied to stopped sessions are marked stale on submit, so they clear instead of repeating No active provider session errors.

I have been running this reconciliation locally as my t3-code backend. It cleared my stale Working threads and preserved their resume cursors.

Why

Restarting the server while work is active can leave threads stuck on Working (or Input) forever because the replacement process inherits session state for provider processes that no longer exist. Running this reconciliation during startup repairs those threads without calling provider stop or abort, keeps the conversation resumable, and gives stale provider callbacks an actionable restart-turn path.

Fixes#4584

UI Changes

For the Input state, this fix has a minor UI change.

Before: A dead provider leaves the Input card open, and every Submit adds another generic No active provider session failure.

Before: repeated provider input failures with the stale Input card still open

After:Submit marks the callback stale, removes the dead Input card, and returns the thread to the normal composer with guidance to restart the turn.

After: stale callback guidance and the normal composer restored

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Models used

  • openai/gpt-5.6-sol: ~65%
  • anthropic/claude-fable-5: ~35%

Note

Medium Risk
Startup now mutates persisted session bindings and orchestration session state before accepting commands; a failed session.set can fail the whole boot. Binding write errors are logged and skipped.

Overview
Stops threads that a previous process left running or starting before the new server accepts commands, so they no longer sit on Working/Input forever.

reconcileProviderSessions runs at the prepared startup boundary. It marks matching directory bindings stopped (resume cursor kept, activeTurnId cleared) and dispatches thread.session.set the same way. Binding I/O failures are warnings; a failed session settle still fails startup.

Submitting leftover approval or user-input cards on a stopped session now records the existing stale-request failure instead of “No active provider session,” so the card can clear and the user can restart the turn.

Reviewed by Cursor Bugbot for commit 16271a3. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Reconcile active provider sessions on server restart and improve stale response errors

  • Adds reconcileProviderSessions to serverRuntimeStartup.ts, which reads threads from ProjectionSnapshotQuery, transitions any running or starting sessions to stopped, clears activeTurnId in provider bindings, and dispatches thread.session.set commands before the launcher trial begins.
  • Updates the thread.approval.respond and thread.user-input.respond handlers in ProviderCommandReactor.ts to use stalePendingRequestDetail with the request id instead of a generic 'no active session' message in failure details.
  • Risk: reconcileProviderSessions is called before launcher.prepareTrial; if OrchestrationEngine.dispatch fails for a running session, the startup error propagates and may block server startup.

Macroscope summarized 16271a3.

@coderabbitai

coderabbitaiBot commented Aug 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a92ee44-e5e6-49c9-9981-0189a4dacbf1

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

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-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@macroscopeapp

macroscopeappBot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds new server startup logic that forcibly reconciles (stops) any sessions that were in 'running' or 'starting' state when the server restarts. This is a significant behavioral change to the startup sequence that affects session lifecycle management and warrants review by someone familiar with the orchestration system.

You can add or adjust custom eligibility rules. Learn more.

@ayubunayubun changed the title fix(server): settle recovered OpenCode idle sessionsfix(server): reconcile OpenCode idle state after restartAug 19, 2026
@ayubunayubun changed the title fix(server): reconcile OpenCode idle state after restartfix(server): reconcile active sessions after restartAug 19, 2026
@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubun marked this pull request as draft August 19, 2026 20:09
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubunforce-pushed the fix/interrupted-session-state branch 6 times, most recently from deae80e to 008f358CompareAugust 20, 2026 05:04
Comment threadapps/server/src/serverRuntimeStartup.ts

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Effect service conventions review: one convention issue found in the new startup reconciliation tests (standalone FooShape type used instead of the inferred Foo["Service"]). The rest of the changed code (namespace imports, dependency acquisition via yield* Service, Effect.catch on a fully handled error channel, no runtime escapes) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: App restart during active turns leaves threads stuck on Working forever, with no startup reconciliation of dead provider sessions

1 participant

@ayubun
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(server): reconcile active sessions after restart - #7463

Open
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state
Open

fix(server): reconcile active sessions after restart#7463
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state

Conversation

@ayubun

@ayubunayubun commented Aug 19, 2026

Copy link
Copy Markdown

What Changed

Reconciles provider sessions that a previous server process left running or starting before the replacement process accepts commands. Persisted runtime bindings are marked stopped, stale active turns are cleared, and provider resume cursors are preserved. Pending approval and Input cards tied to stopped sessions are marked stale on submit, so they clear instead of repeating No active provider session errors.

I have been running this reconciliation locally as my t3-code backend. It cleared my stale Working threads and preserved their resume cursors.

Why

Restarting the server while work is active can leave threads stuck on Working (or Input) forever because the replacement process inherits session state for provider processes that no longer exist. Running this reconciliation during startup repairs those threads without calling provider stop or abort, keeps the conversation resumable, and gives stale provider callbacks an actionable restart-turn path.

Fixes#4584

UI Changes

For the Input state, this fix has a minor UI change.

Before: A dead provider leaves the Input card open, and every Submit adds another generic No active provider session failure.

Before: repeated provider input failures with the stale Input card still open

After:Submit marks the callback stale, removes the dead Input card, and returns the thread to the normal composer with guidance to restart the turn.

After: stale callback guidance and the normal composer restored

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Models used

  • openai/gpt-5.6-sol: ~65%
  • anthropic/claude-fable-5: ~35%

Note

Medium Risk
Startup now mutates persisted session bindings and orchestration session state before accepting commands; a failed session.set can fail the whole boot. Binding write errors are logged and skipped.

Overview
Stops threads that a previous process left running or starting before the new server accepts commands, so they no longer sit on Working/Input forever.

reconcileProviderSessions runs at the prepared startup boundary. It marks matching directory bindings stopped (resume cursor kept, activeTurnId cleared) and dispatches thread.session.set the same way. Binding I/O failures are warnings; a failed session settle still fails startup.

Submitting leftover approval or user-input cards on a stopped session now records the existing stale-request failure instead of “No active provider session,” so the card can clear and the user can restart the turn.

Reviewed by Cursor Bugbot for commit 16271a3. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Reconcile active provider sessions on server restart and improve stale response errors

  • Adds reconcileProviderSessions to serverRuntimeStartup.ts, which reads threads from ProjectionSnapshotQuery, transitions any running or starting sessions to stopped, clears activeTurnId in provider bindings, and dispatches thread.session.set commands before the launcher trial begins.
  • Updates the thread.approval.respond and thread.user-input.respond handlers in ProviderCommandReactor.ts to use stalePendingRequestDetail with the request id instead of a generic 'no active session' message in failure details.
  • Risk: reconcileProviderSessions is called before launcher.prepareTrial; if OrchestrationEngine.dispatch fails for a running session, the startup error propagates and may block server startup.

Macroscope summarized 16271a3.

@coderabbitai

coderabbitaiBot commented Aug 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a92ee44-e5e6-49c9-9981-0189a4dacbf1

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

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-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@macroscopeapp

macroscopeappBot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds new server startup logic that forcibly reconciles (stops) any sessions that were in 'running' or 'starting' state when the server restarts. This is a significant behavioral change to the startup sequence that affects session lifecycle management and warrants review by someone familiar with the orchestration system.

You can add or adjust custom eligibility rules. Learn more.

@ayubunayubun changed the title fix(server): settle recovered OpenCode idle sessionsfix(server): reconcile OpenCode idle state after restartAug 19, 2026
@ayubunayubun changed the title fix(server): reconcile OpenCode idle state after restartfix(server): reconcile active sessions after restartAug 19, 2026
@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubun marked this pull request as draft August 19, 2026 20:09
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubunforce-pushed the fix/interrupted-session-state branch 6 times, most recently from deae80e to 008f358CompareAugust 20, 2026 05:04
Comment threadapps/server/src/serverRuntimeStartup.ts

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Effect service conventions review: one convention issue found in the new startup reconciliation tests (standalone FooShape type used instead of the inferred Foo["Service"]). The rest of the changed code (namespace imports, dependency acquisition via yield* Service, Effect.catch on a fully handled error channel, no runtime escapes) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: App restart during active turns leaves threads stuck on Working forever, with no startup reconciliation of dead provider sessions

1 participant

@ayubun
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(server): reconcile active sessions after restart - #7463

Open
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state
Open

fix(server): reconcile active sessions after restart#7463
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state

Conversation

@ayubun

@ayubunayubun commented Aug 19, 2026

Copy link
Copy Markdown

What Changed

Reconciles provider sessions that a previous server process left running or starting before the replacement process accepts commands. Persisted runtime bindings are marked stopped, stale active turns are cleared, and provider resume cursors are preserved. Pending approval and Input cards tied to stopped sessions are marked stale on submit, so they clear instead of repeating No active provider session errors.

I have been running this reconciliation locally as my t3-code backend. It cleared my stale Working threads and preserved their resume cursors.

Why

Restarting the server while work is active can leave threads stuck on Working (or Input) forever because the replacement process inherits session state for provider processes that no longer exist. Running this reconciliation during startup repairs those threads without calling provider stop or abort, keeps the conversation resumable, and gives stale provider callbacks an actionable restart-turn path.

Fixes#4584

UI Changes

For the Input state, this fix has a minor UI change.

Before: A dead provider leaves the Input card open, and every Submit adds another generic No active provider session failure.

Before: repeated provider input failures with the stale Input card still open

After:Submit marks the callback stale, removes the dead Input card, and returns the thread to the normal composer with guidance to restart the turn.

After: stale callback guidance and the normal composer restored

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Models used

  • openai/gpt-5.6-sol: ~65%
  • anthropic/claude-fable-5: ~35%

Note

Medium Risk
Startup now mutates persisted session bindings and orchestration session state before accepting commands; a failed session.set can fail the whole boot. Binding write errors are logged and skipped.

Overview
Stops threads that a previous process left running or starting before the new server accepts commands, so they no longer sit on Working/Input forever.

reconcileProviderSessions runs at the prepared startup boundary. It marks matching directory bindings stopped (resume cursor kept, activeTurnId cleared) and dispatches thread.session.set the same way. Binding I/O failures are warnings; a failed session settle still fails startup.

Submitting leftover approval or user-input cards on a stopped session now records the existing stale-request failure instead of “No active provider session,” so the card can clear and the user can restart the turn.

Reviewed by Cursor Bugbot for commit 16271a3. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Reconcile active provider sessions on server restart and improve stale response errors

  • Adds reconcileProviderSessions to serverRuntimeStartup.ts, which reads threads from ProjectionSnapshotQuery, transitions any running or starting sessions to stopped, clears activeTurnId in provider bindings, and dispatches thread.session.set commands before the launcher trial begins.
  • Updates the thread.approval.respond and thread.user-input.respond handlers in ProviderCommandReactor.ts to use stalePendingRequestDetail with the request id instead of a generic 'no active session' message in failure details.
  • Risk: reconcileProviderSessions is called before launcher.prepareTrial; if OrchestrationEngine.dispatch fails for a running session, the startup error propagates and may block server startup.

Macroscope summarized 16271a3.

@coderabbitai

coderabbitaiBot commented Aug 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a92ee44-e5e6-49c9-9981-0189a4dacbf1

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

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-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@macroscopeapp

macroscopeappBot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds new server startup logic that forcibly reconciles (stops) any sessions that were in 'running' or 'starting' state when the server restarts. This is a significant behavioral change to the startup sequence that affects session lifecycle management and warrants review by someone familiar with the orchestration system.

You can add or adjust custom eligibility rules. Learn more.

@ayubunayubun changed the title fix(server): settle recovered OpenCode idle sessionsfix(server): reconcile OpenCode idle state after restartAug 19, 2026
@ayubunayubun changed the title fix(server): reconcile OpenCode idle state after restartfix(server): reconcile active sessions after restartAug 19, 2026
@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubun marked this pull request as draft August 19, 2026 20:09
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubunforce-pushed the fix/interrupted-session-state branch 6 times, most recently from deae80e to 008f358CompareAugust 20, 2026 05:04
Comment threadapps/server/src/serverRuntimeStartup.ts

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Effect service conventions review: one convention issue found in the new startup reconciliation tests (standalone FooShape type used instead of the inferred Foo["Service"]). The rest of the changed code (namespace imports, dependency acquisition via yield* Service, Effect.catch on a fully handled error channel, no runtime escapes) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: App restart during active turns leaves threads stuck on Working forever, with no startup reconciliation of dead provider sessions

1 participant

@ayubun
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(server): reconcile active sessions after restart - #7463

Open
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state
Open

fix(server): reconcile active sessions after restart#7463
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state

Conversation

@ayubun

@ayubunayubun commented Aug 19, 2026

Copy link
Copy Markdown

What Changed

Reconciles provider sessions that a previous server process left running or starting before the replacement process accepts commands. Persisted runtime bindings are marked stopped, stale active turns are cleared, and provider resume cursors are preserved. Pending approval and Input cards tied to stopped sessions are marked stale on submit, so they clear instead of repeating No active provider session errors.

I have been running this reconciliation locally as my t3-code backend. It cleared my stale Working threads and preserved their resume cursors.

Why

Restarting the server while work is active can leave threads stuck on Working (or Input) forever because the replacement process inherits session state for provider processes that no longer exist. Running this reconciliation during startup repairs those threads without calling provider stop or abort, keeps the conversation resumable, and gives stale provider callbacks an actionable restart-turn path.

Fixes#4584

UI Changes

For the Input state, this fix has a minor UI change.

Before: A dead provider leaves the Input card open, and every Submit adds another generic No active provider session failure.

Before: repeated provider input failures with the stale Input card still open

After:Submit marks the callback stale, removes the dead Input card, and returns the thread to the normal composer with guidance to restart the turn.

After: stale callback guidance and the normal composer restored

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Models used

  • openai/gpt-5.6-sol: ~65%
  • anthropic/claude-fable-5: ~35%

Note

Medium Risk
Startup now mutates persisted session bindings and orchestration session state before accepting commands; a failed session.set can fail the whole boot. Binding write errors are logged and skipped.

Overview
Stops threads that a previous process left running or starting before the new server accepts commands, so they no longer sit on Working/Input forever.

reconcileProviderSessions runs at the prepared startup boundary. It marks matching directory bindings stopped (resume cursor kept, activeTurnId cleared) and dispatches thread.session.set the same way. Binding I/O failures are warnings; a failed session settle still fails startup.

Submitting leftover approval or user-input cards on a stopped session now records the existing stale-request failure instead of “No active provider session,” so the card can clear and the user can restart the turn.

Reviewed by Cursor Bugbot for commit 16271a3. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Reconcile active provider sessions on server restart and improve stale response errors

  • Adds reconcileProviderSessions to serverRuntimeStartup.ts, which reads threads from ProjectionSnapshotQuery, transitions any running or starting sessions to stopped, clears activeTurnId in provider bindings, and dispatches thread.session.set commands before the launcher trial begins.
  • Updates the thread.approval.respond and thread.user-input.respond handlers in ProviderCommandReactor.ts to use stalePendingRequestDetail with the request id instead of a generic 'no active session' message in failure details.
  • Risk: reconcileProviderSessions is called before launcher.prepareTrial; if OrchestrationEngine.dispatch fails for a running session, the startup error propagates and may block server startup.

Macroscope summarized 16271a3.

@coderabbitai

coderabbitaiBot commented Aug 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a92ee44-e5e6-49c9-9981-0189a4dacbf1

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

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-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@macroscopeapp

macroscopeappBot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds new server startup logic that forcibly reconciles (stops) any sessions that were in 'running' or 'starting' state when the server restarts. This is a significant behavioral change to the startup sequence that affects session lifecycle management and warrants review by someone familiar with the orchestration system.

You can add or adjust custom eligibility rules. Learn more.

@ayubunayubun changed the title fix(server): settle recovered OpenCode idle sessionsfix(server): reconcile OpenCode idle state after restartAug 19, 2026
@ayubunayubun changed the title fix(server): reconcile OpenCode idle state after restartfix(server): reconcile active sessions after restartAug 19, 2026
@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubun marked this pull request as draft August 19, 2026 20:09
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubunforce-pushed the fix/interrupted-session-state branch 6 times, most recently from deae80e to 008f358CompareAugust 20, 2026 05:04
Comment threadapps/server/src/serverRuntimeStartup.ts

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Effect service conventions review: one convention issue found in the new startup reconciliation tests (standalone FooShape type used instead of the inferred Foo["Service"]). The rest of the changed code (namespace imports, dependency acquisition via yield* Service, Effect.catch on a fully handled error channel, no runtime escapes) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: App restart during active turns leaves threads stuck on Working forever, with no startup reconciliation of dead provider sessions

1 participant

@ayubun
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(server): reconcile active sessions after restart - #7463

Open
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state
Open

fix(server): reconcile active sessions after restart#7463
ayubun wants to merge 1 commit into
pingdotgg:mainfrom
ayubun:fix/interrupted-session-state

Conversation

@ayubun

@ayubunayubun commented Aug 19, 2026

Copy link
Copy Markdown

What Changed

Reconciles provider sessions that a previous server process left running or starting before the replacement process accepts commands. Persisted runtime bindings are marked stopped, stale active turns are cleared, and provider resume cursors are preserved. Pending approval and Input cards tied to stopped sessions are marked stale on submit, so they clear instead of repeating No active provider session errors.

I have been running this reconciliation locally as my t3-code backend. It cleared my stale Working threads and preserved their resume cursors.

Why

Restarting the server while work is active can leave threads stuck on Working (or Input) forever because the replacement process inherits session state for provider processes that no longer exist. Running this reconciliation during startup repairs those threads without calling provider stop or abort, keeps the conversation resumable, and gives stale provider callbacks an actionable restart-turn path.

Fixes#4584

UI Changes

For the Input state, this fix has a minor UI change.

Before: A dead provider leaves the Input card open, and every Submit adds another generic No active provider session failure.

Before: repeated provider input failures with the stale Input card still open

After:Submit marks the callback stale, removes the dead Input card, and returns the thread to the normal composer with guidance to restart the turn.

After: stale callback guidance and the normal composer restored

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Models used

  • openai/gpt-5.6-sol: ~65%
  • anthropic/claude-fable-5: ~35%

Note

Medium Risk
Startup now mutates persisted session bindings and orchestration session state before accepting commands; a failed session.set can fail the whole boot. Binding write errors are logged and skipped.

Overview
Stops threads that a previous process left running or starting before the new server accepts commands, so they no longer sit on Working/Input forever.

reconcileProviderSessions runs at the prepared startup boundary. It marks matching directory bindings stopped (resume cursor kept, activeTurnId cleared) and dispatches thread.session.set the same way. Binding I/O failures are warnings; a failed session settle still fails startup.

Submitting leftover approval or user-input cards on a stopped session now records the existing stale-request failure instead of “No active provider session,” so the card can clear and the user can restart the turn.

Reviewed by Cursor Bugbot for commit 16271a3. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Reconcile active provider sessions on server restart and improve stale response errors

  • Adds reconcileProviderSessions to serverRuntimeStartup.ts, which reads threads from ProjectionSnapshotQuery, transitions any running or starting sessions to stopped, clears activeTurnId in provider bindings, and dispatches thread.session.set commands before the launcher trial begins.
  • Updates the thread.approval.respond and thread.user-input.respond handlers in ProviderCommandReactor.ts to use stalePendingRequestDetail with the request id instead of a generic 'no active session' message in failure details.
  • Risk: reconcileProviderSessions is called before launcher.prepareTrial; if OrchestrationEngine.dispatch fails for a running session, the startup error propagates and may block server startup.

Macroscope summarized 16271a3.

@coderabbitai

coderabbitaiBot commented Aug 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto 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: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6a92ee44-e5e6-49c9-9981-0189a4dacbf1

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

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-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@macroscopeapp

macroscopeappBot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds new server startup logic that forcibly reconciles (stops) any sessions that were in 'running' or 'starting' state when the server restarts. This is a significant behavioral change to the startup sequence that affects session lifecycle management and warrants review by someone familiar with the orchestration system.

You can add or adjust custom eligibility rules. Learn more.

@ayubunayubun changed the title fix(server): settle recovered OpenCode idle sessionsfix(server): reconcile OpenCode idle state after restartAug 19, 2026
@ayubunayubun changed the title fix(server): reconcile OpenCode idle state after restartfix(server): reconcile active sessions after restartAug 19, 2026
@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubun marked this pull request as draft August 19, 2026 20:09
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 19, 2026
@ayubun
ayubunforce-pushed the fix/interrupted-session-state branch 6 times, most recently from deae80e to 008f358CompareAugust 20, 2026 05:04
Comment threadapps/server/src/serverRuntimeStartup.ts

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Effect service conventions review: one convention issue found in the new startup reconciliation tests (standalone FooShape type used instead of the inferred Foo["Service"]). The rest of the changed code (namespace imports, dependency acquisition via yield* Service, Effect.catch on a fully handled error channel, no runtime escapes) matches the conventions.

Posted via Macroscope — Effect Service Conventions

Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Comment threadapps/server/src/serverRuntimeStartup.test.ts Outdated
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:unvouchedPR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: App restart during active turns leaves threads stuck on Working forever, with no startup reconciliation of dead provider sessions

1 participant

@ayubun