feat: "waiting" status for threads with open background tasks (i.e. pr monitors) - #4415

Closed
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state
Closed

feat: "waiting" status for threads with open background tasks (i.e. pr monitors)#4415
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state

Conversation

@t3dotgg

@t3dotggt3dotgg commented Jul 24, 2026

Copy link
Copy Markdown
Member

When the agent stops while background tasks (subagents, background bash, monitors) are still running, the sidebar showed Done, then flicked back to Working when a task completion woke the agent (median 13s later, from local history).

Now ingestion tracks provider-reported open tasks per thread and parks the session on the previously-unused idle status when a turn ends with tasks still open. Sidebar v2 (web + mobile) renders it as a grey Waiting label with the same elapsed timer as Working; the row recedes like other in-flight states. Waiting flips directly to Working on wake-up — no intermediate Done.

  • Task set is keyed by provider instance and cleared on exit/stop/error, so stale tasks can't park a fresh session.
  • idle was already handled as "resting" by settlement, projection, and phase logic, so no contract or migration changes; old clients degrade to today's behavior.
  • Codex/OpenCode don't emit task events — behavior unchanged there.

🤖 Generated with Claude Code


Note

Medium Risk
Changes core session lifecycle in ProviderRuntimeIngestion (when threads show ready vs idle), with broad integration tests but no contract migration—incorrect task tracking could mislabel thread state across clients.

Overview
Threads that finish a turn while provider background tasks (monitors, subagents, etc.) are still open no longer flash Done before the wake-up turn. Provider runtime ingestion now tracks open tasks per thread and provider instance and parks the session on idle instead of ready when a turn ends with tasks still open; task state is cleared on session exit, error, and stale-instance guards, with tombstones for late events.

Web sidebar v2 and the mobile thread list map idle to a muted Waiting label (same elapsed timer as Working, in-flight row treatment). Successful task completion is expected to wake the agent without an intermediate ready; only a stopped last task returns Waiting to ready.

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

Note

Add 'waiting' status for threads with open background tasks

  • Introduces a new idle session status that signals a thread is waiting on background tasks (e.g. PR monitors) rather than active user input or processing.
  • ProviderRuntimeIngestion tracks open tasks per thread/provider instance and transitions sessions to idle at rest when tasks remain open, returning to ready when the last task completes.
  • The web sidebar and mobile thread list both render idle sessions as 'Waiting' with a neutral style and an elapsed duration, treated as in-flight for display purposes.
  • Open task state is cleared on session exit or error so future sessions do not inherit the waiting state.
  • Behavioral Change: threads that previously resolved to ready while background tasks were open will now show as waiting until those tasks complete.

Macroscope summarized 368e0e1.

@coderabbitai

coderabbitaiBot commented Jul 24, 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: 91fb2c98-8548-4670-a2cd-2cbb6e8a3eee

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/sidebar-waiting-state

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:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 24, 2026
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

New feature introducing a 'waiting' status with non-trivial server-side state tracking logic for background tasks. While well-tested, new user-facing behavior and runtime session status changes warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@t3dotggt3dotgg changed the title Show Waiting state for threads with open background tasksfeat: "waiting" status for threads with open background tasks (i.e. pr monitors)Jul 24, 2026
t3dotggand others added 2 commits July 23, 2026 22:21
When the agent stops with background tasks (subagents, background bash,
monitors) still running, the thread showed Done, then flicked back to
Working when a task completion woke the agent. Track provider-reported
open tasks in ingestion and park the session on the previously-unused
"idle" status; sidebar v2 renders it as a grey "Waiting" with the same
elapsed timer as Working.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review fixes: gate the terminal-status task sweep behind the lifecycle
guard so rejected stale events cannot erase the active turn's tasks;
ignore task starts from a provider instance that doesn't match the
projected session instead of letting them displace the current set;
tombstone completed task ids so late/duplicate progress cannot re-open
a finished task and park the thread on Waiting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the t3code/sidebar-waiting-state branch from bec6dc6 to 528adb2CompareJuly 24, 2026 05:22
Comment threadapps/web/src/components/SidebarV2.tsx
A completed/failed final task wakes the agent (its notification is the
wake signal), so Waiting flips straight to Working. A stopped final task
is a kill — no wake follows — and previously left a live session parked
on Waiting until teardown. Flip that case back to ready, and tombstone
completions that outrun their start event.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 514fccf. Configure here.

Tombstones exist to stop late/duplicate progress from resurrecting a
finished task, but providers reuse task ids when an agent is resumed —
a fresh task.started after completion is real work, not a replay.
Progress stays blocked by the tombstone; an explicit start clears it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
t3dotgg added a commit that referenced this pull request Jul 24, 2026
Real-data feedback round two:
- Results render as a responsive grid (1/2/3 columns) instead of a
full-width list.
- While the sweep runs, the page shows only a progress count
("Reviewing your work — 7 of 18"); results reveal all at once when
every thread is done, so triage happens in one pass over a stable
layout instead of chasing cards as they pop in.
- The model now returns a one-sentence imperative nextStep ("Review
and merge PR #4415.") which becomes the card body — a direct answer
to "what should I do here". Summaries are capped at one sentence and
demoted to an info-icon tooltip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 24, 2026
…2.1-next
Absorb CTM tip 408efa6 (Claude replay cleanup, ACP auth/fork provenance,
derived-thread wake, fork-shell navigation wait) onto the pingdotgg#4415 Waiting
sequence pinned at main ece0508.
Conflict resolution (same intent as prior merge 616da6976):
- Sidebar/threadList Waiting uses runtime.idle (CTM/orchestrator-v2 park)
rather than session.idle from main pingdotgg#4415, including mobile tests.
- Drop ProviderRuntimeIngestion (deleted on CTM; v2 uses orchestration-v2).
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 25, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
CTM's own subagent hiding (97a04be) skips delegated children inside
buildThreadListV2Items, so the list is right, but hasAnyThreads still counts
them. A user whose only live threads are subagent children therefore gets the
in-list "No results" state instead of the full-page "No threads yet".
Also corrects the threadListV2 header comment left by the CTM merge: pingdotgg#4415
sidebar-waiting-state describes Waiting as session.idle, while this line keys
it off runtime.idle.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@t3dotgg@juliusmarminge
, '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

feat: "waiting" status for threads with open background tasks (i.e. pr monitors) - #4415

Closed
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state
Closed

feat: "waiting" status for threads with open background tasks (i.e. pr monitors)#4415
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state

Conversation

@t3dotgg

@t3dotggt3dotgg commented Jul 24, 2026

Copy link
Copy Markdown
Member

When the agent stops while background tasks (subagents, background bash, monitors) are still running, the sidebar showed Done, then flicked back to Working when a task completion woke the agent (median 13s later, from local history).

Now ingestion tracks provider-reported open tasks per thread and parks the session on the previously-unused idle status when a turn ends with tasks still open. Sidebar v2 (web + mobile) renders it as a grey Waiting label with the same elapsed timer as Working; the row recedes like other in-flight states. Waiting flips directly to Working on wake-up — no intermediate Done.

  • Task set is keyed by provider instance and cleared on exit/stop/error, so stale tasks can't park a fresh session.
  • idle was already handled as "resting" by settlement, projection, and phase logic, so no contract or migration changes; old clients degrade to today's behavior.
  • Codex/OpenCode don't emit task events — behavior unchanged there.

🤖 Generated with Claude Code


Note

Medium Risk
Changes core session lifecycle in ProviderRuntimeIngestion (when threads show ready vs idle), with broad integration tests but no contract migration—incorrect task tracking could mislabel thread state across clients.

Overview
Threads that finish a turn while provider background tasks (monitors, subagents, etc.) are still open no longer flash Done before the wake-up turn. Provider runtime ingestion now tracks open tasks per thread and provider instance and parks the session on idle instead of ready when a turn ends with tasks still open; task state is cleared on session exit, error, and stale-instance guards, with tombstones for late events.

Web sidebar v2 and the mobile thread list map idle to a muted Waiting label (same elapsed timer as Working, in-flight row treatment). Successful task completion is expected to wake the agent without an intermediate ready; only a stopped last task returns Waiting to ready.

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

Note

Add 'waiting' status for threads with open background tasks

  • Introduces a new idle session status that signals a thread is waiting on background tasks (e.g. PR monitors) rather than active user input or processing.
  • ProviderRuntimeIngestion tracks open tasks per thread/provider instance and transitions sessions to idle at rest when tasks remain open, returning to ready when the last task completes.
  • The web sidebar and mobile thread list both render idle sessions as 'Waiting' with a neutral style and an elapsed duration, treated as in-flight for display purposes.
  • Open task state is cleared on session exit or error so future sessions do not inherit the waiting state.
  • Behavioral Change: threads that previously resolved to ready while background tasks were open will now show as waiting until those tasks complete.

Macroscope summarized 368e0e1.

@coderabbitai

coderabbitaiBot commented Jul 24, 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: 91fb2c98-8548-4670-a2cd-2cbb6e8a3eee

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/sidebar-waiting-state

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:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 24, 2026
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

New feature introducing a 'waiting' status with non-trivial server-side state tracking logic for background tasks. While well-tested, new user-facing behavior and runtime session status changes warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@t3dotggt3dotgg changed the title Show Waiting state for threads with open background tasksfeat: "waiting" status for threads with open background tasks (i.e. pr monitors)Jul 24, 2026
t3dotggand others added 2 commits July 23, 2026 22:21
When the agent stops with background tasks (subagents, background bash,
monitors) still running, the thread showed Done, then flicked back to
Working when a task completion woke the agent. Track provider-reported
open tasks in ingestion and park the session on the previously-unused
"idle" status; sidebar v2 renders it as a grey "Waiting" with the same
elapsed timer as Working.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review fixes: gate the terminal-status task sweep behind the lifecycle
guard so rejected stale events cannot erase the active turn's tasks;
ignore task starts from a provider instance that doesn't match the
projected session instead of letting them displace the current set;
tombstone completed task ids so late/duplicate progress cannot re-open
a finished task and park the thread on Waiting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the t3code/sidebar-waiting-state branch from bec6dc6 to 528adb2CompareJuly 24, 2026 05:22
Comment threadapps/web/src/components/SidebarV2.tsx
A completed/failed final task wakes the agent (its notification is the
wake signal), so Waiting flips straight to Working. A stopped final task
is a kill — no wake follows — and previously left a live session parked
on Waiting until teardown. Flip that case back to ready, and tombstone
completions that outrun their start event.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 514fccf. Configure here.

Tombstones exist to stop late/duplicate progress from resurrecting a
finished task, but providers reuse task ids when an agent is resumed —
a fresh task.started after completion is real work, not a replay.
Progress stays blocked by the tombstone; an explicit start clears it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
t3dotgg added a commit that referenced this pull request Jul 24, 2026
Real-data feedback round two:
- Results render as a responsive grid (1/2/3 columns) instead of a
full-width list.
- While the sweep runs, the page shows only a progress count
("Reviewing your work — 7 of 18"); results reveal all at once when
every thread is done, so triage happens in one pass over a stable
layout instead of chasing cards as they pop in.
- The model now returns a one-sentence imperative nextStep ("Review
and merge PR #4415.") which becomes the card body — a direct answer
to "what should I do here". Summaries are capped at one sentence and
demoted to an info-icon tooltip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 24, 2026
…2.1-next
Absorb CTM tip 408efa6 (Claude replay cleanup, ACP auth/fork provenance,
derived-thread wake, fork-shell navigation wait) onto the pingdotgg#4415 Waiting
sequence pinned at main ece0508.
Conflict resolution (same intent as prior merge 616da6976):
- Sidebar/threadList Waiting uses runtime.idle (CTM/orchestrator-v2 park)
rather than session.idle from main pingdotgg#4415, including mobile tests.
- Drop ProviderRuntimeIngestion (deleted on CTM; v2 uses orchestration-v2).
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 25, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
CTM's own subagent hiding (97a04be) skips delegated children inside
buildThreadListV2Items, so the list is right, but hasAnyThreads still counts
them. A user whose only live threads are subagent children therefore gets the
in-list "No results" state instead of the full-page "No threads yet".
Also corrects the threadListV2 header comment left by the CTM merge: pingdotgg#4415
sidebar-waiting-state describes Waiting as session.idle, while this line keys
it off runtime.idle.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@t3dotgg@juliusmarminge
, '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

feat: "waiting" status for threads with open background tasks (i.e. pr monitors) - #4415

Closed
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state
Closed

feat: "waiting" status for threads with open background tasks (i.e. pr monitors)#4415
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state

Conversation

@t3dotgg

@t3dotggt3dotgg commented Jul 24, 2026

Copy link
Copy Markdown
Member

When the agent stops while background tasks (subagents, background bash, monitors) are still running, the sidebar showed Done, then flicked back to Working when a task completion woke the agent (median 13s later, from local history).

Now ingestion tracks provider-reported open tasks per thread and parks the session on the previously-unused idle status when a turn ends with tasks still open. Sidebar v2 (web + mobile) renders it as a grey Waiting label with the same elapsed timer as Working; the row recedes like other in-flight states. Waiting flips directly to Working on wake-up — no intermediate Done.

  • Task set is keyed by provider instance and cleared on exit/stop/error, so stale tasks can't park a fresh session.
  • idle was already handled as "resting" by settlement, projection, and phase logic, so no contract or migration changes; old clients degrade to today's behavior.
  • Codex/OpenCode don't emit task events — behavior unchanged there.

🤖 Generated with Claude Code


Note

Medium Risk
Changes core session lifecycle in ProviderRuntimeIngestion (when threads show ready vs idle), with broad integration tests but no contract migration—incorrect task tracking could mislabel thread state across clients.

Overview
Threads that finish a turn while provider background tasks (monitors, subagents, etc.) are still open no longer flash Done before the wake-up turn. Provider runtime ingestion now tracks open tasks per thread and provider instance and parks the session on idle instead of ready when a turn ends with tasks still open; task state is cleared on session exit, error, and stale-instance guards, with tombstones for late events.

Web sidebar v2 and the mobile thread list map idle to a muted Waiting label (same elapsed timer as Working, in-flight row treatment). Successful task completion is expected to wake the agent without an intermediate ready; only a stopped last task returns Waiting to ready.

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

Note

Add 'waiting' status for threads with open background tasks

  • Introduces a new idle session status that signals a thread is waiting on background tasks (e.g. PR monitors) rather than active user input or processing.
  • ProviderRuntimeIngestion tracks open tasks per thread/provider instance and transitions sessions to idle at rest when tasks remain open, returning to ready when the last task completes.
  • The web sidebar and mobile thread list both render idle sessions as 'Waiting' with a neutral style and an elapsed duration, treated as in-flight for display purposes.
  • Open task state is cleared on session exit or error so future sessions do not inherit the waiting state.
  • Behavioral Change: threads that previously resolved to ready while background tasks were open will now show as waiting until those tasks complete.

Macroscope summarized 368e0e1.

@coderabbitai

coderabbitaiBot commented Jul 24, 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: 91fb2c98-8548-4670-a2cd-2cbb6e8a3eee

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/sidebar-waiting-state

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:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 24, 2026
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

New feature introducing a 'waiting' status with non-trivial server-side state tracking logic for background tasks. While well-tested, new user-facing behavior and runtime session status changes warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@t3dotggt3dotgg changed the title Show Waiting state for threads with open background tasksfeat: "waiting" status for threads with open background tasks (i.e. pr monitors)Jul 24, 2026
t3dotggand others added 2 commits July 23, 2026 22:21
When the agent stops with background tasks (subagents, background bash,
monitors) still running, the thread showed Done, then flicked back to
Working when a task completion woke the agent. Track provider-reported
open tasks in ingestion and park the session on the previously-unused
"idle" status; sidebar v2 renders it as a grey "Waiting" with the same
elapsed timer as Working.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review fixes: gate the terminal-status task sweep behind the lifecycle
guard so rejected stale events cannot erase the active turn's tasks;
ignore task starts from a provider instance that doesn't match the
projected session instead of letting them displace the current set;
tombstone completed task ids so late/duplicate progress cannot re-open
a finished task and park the thread on Waiting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the t3code/sidebar-waiting-state branch from bec6dc6 to 528adb2CompareJuly 24, 2026 05:22
Comment threadapps/web/src/components/SidebarV2.tsx
A completed/failed final task wakes the agent (its notification is the
wake signal), so Waiting flips straight to Working. A stopped final task
is a kill — no wake follows — and previously left a live session parked
on Waiting until teardown. Flip that case back to ready, and tombstone
completions that outrun their start event.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 514fccf. Configure here.

Tombstones exist to stop late/duplicate progress from resurrecting a
finished task, but providers reuse task ids when an agent is resumed —
a fresh task.started after completion is real work, not a replay.
Progress stays blocked by the tombstone; an explicit start clears it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
t3dotgg added a commit that referenced this pull request Jul 24, 2026
Real-data feedback round two:
- Results render as a responsive grid (1/2/3 columns) instead of a
full-width list.
- While the sweep runs, the page shows only a progress count
("Reviewing your work — 7 of 18"); results reveal all at once when
every thread is done, so triage happens in one pass over a stable
layout instead of chasing cards as they pop in.
- The model now returns a one-sentence imperative nextStep ("Review
and merge PR #4415.") which becomes the card body — a direct answer
to "what should I do here". Summaries are capped at one sentence and
demoted to an info-icon tooltip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 24, 2026
…2.1-next
Absorb CTM tip 408efa6 (Claude replay cleanup, ACP auth/fork provenance,
derived-thread wake, fork-shell navigation wait) onto the pingdotgg#4415 Waiting
sequence pinned at main ece0508.
Conflict resolution (same intent as prior merge 616da6976):
- Sidebar/threadList Waiting uses runtime.idle (CTM/orchestrator-v2 park)
rather than session.idle from main pingdotgg#4415, including mobile tests.
- Drop ProviderRuntimeIngestion (deleted on CTM; v2 uses orchestration-v2).
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 25, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
CTM's own subagent hiding (97a04be) skips delegated children inside
buildThreadListV2Items, so the list is right, but hasAnyThreads still counts
them. A user whose only live threads are subagent children therefore gets the
in-list "No results" state instead of the full-page "No threads yet".
Also corrects the threadListV2 header comment left by the CTM merge: pingdotgg#4415
sidebar-waiting-state describes Waiting as session.idle, while this line keys
it off runtime.idle.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@t3dotgg@juliusmarminge
, '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

feat: "waiting" status for threads with open background tasks (i.e. pr monitors) - #4415

Closed
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state
Closed

feat: "waiting" status for threads with open background tasks (i.e. pr monitors)#4415
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state

Conversation

@t3dotgg

@t3dotggt3dotgg commented Jul 24, 2026

Copy link
Copy Markdown
Member

When the agent stops while background tasks (subagents, background bash, monitors) are still running, the sidebar showed Done, then flicked back to Working when a task completion woke the agent (median 13s later, from local history).

Now ingestion tracks provider-reported open tasks per thread and parks the session on the previously-unused idle status when a turn ends with tasks still open. Sidebar v2 (web + mobile) renders it as a grey Waiting label with the same elapsed timer as Working; the row recedes like other in-flight states. Waiting flips directly to Working on wake-up — no intermediate Done.

  • Task set is keyed by provider instance and cleared on exit/stop/error, so stale tasks can't park a fresh session.
  • idle was already handled as "resting" by settlement, projection, and phase logic, so no contract or migration changes; old clients degrade to today's behavior.
  • Codex/OpenCode don't emit task events — behavior unchanged there.

🤖 Generated with Claude Code


Note

Medium Risk
Changes core session lifecycle in ProviderRuntimeIngestion (when threads show ready vs idle), with broad integration tests but no contract migration—incorrect task tracking could mislabel thread state across clients.

Overview
Threads that finish a turn while provider background tasks (monitors, subagents, etc.) are still open no longer flash Done before the wake-up turn. Provider runtime ingestion now tracks open tasks per thread and provider instance and parks the session on idle instead of ready when a turn ends with tasks still open; task state is cleared on session exit, error, and stale-instance guards, with tombstones for late events.

Web sidebar v2 and the mobile thread list map idle to a muted Waiting label (same elapsed timer as Working, in-flight row treatment). Successful task completion is expected to wake the agent without an intermediate ready; only a stopped last task returns Waiting to ready.

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

Note

Add 'waiting' status for threads with open background tasks

  • Introduces a new idle session status that signals a thread is waiting on background tasks (e.g. PR monitors) rather than active user input or processing.
  • ProviderRuntimeIngestion tracks open tasks per thread/provider instance and transitions sessions to idle at rest when tasks remain open, returning to ready when the last task completes.
  • The web sidebar and mobile thread list both render idle sessions as 'Waiting' with a neutral style and an elapsed duration, treated as in-flight for display purposes.
  • Open task state is cleared on session exit or error so future sessions do not inherit the waiting state.
  • Behavioral Change: threads that previously resolved to ready while background tasks were open will now show as waiting until those tasks complete.

Macroscope summarized 368e0e1.

@coderabbitai

coderabbitaiBot commented Jul 24, 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: 91fb2c98-8548-4670-a2cd-2cbb6e8a3eee

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/sidebar-waiting-state

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:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 24, 2026
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

New feature introducing a 'waiting' status with non-trivial server-side state tracking logic for background tasks. While well-tested, new user-facing behavior and runtime session status changes warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@t3dotggt3dotgg changed the title Show Waiting state for threads with open background tasksfeat: "waiting" status for threads with open background tasks (i.e. pr monitors)Jul 24, 2026
t3dotggand others added 2 commits July 23, 2026 22:21
When the agent stops with background tasks (subagents, background bash,
monitors) still running, the thread showed Done, then flicked back to
Working when a task completion woke the agent. Track provider-reported
open tasks in ingestion and park the session on the previously-unused
"idle" status; sidebar v2 renders it as a grey "Waiting" with the same
elapsed timer as Working.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review fixes: gate the terminal-status task sweep behind the lifecycle
guard so rejected stale events cannot erase the active turn's tasks;
ignore task starts from a provider instance that doesn't match the
projected session instead of letting them displace the current set;
tombstone completed task ids so late/duplicate progress cannot re-open
a finished task and park the thread on Waiting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the t3code/sidebar-waiting-state branch from bec6dc6 to 528adb2CompareJuly 24, 2026 05:22
Comment threadapps/web/src/components/SidebarV2.tsx
A completed/failed final task wakes the agent (its notification is the
wake signal), so Waiting flips straight to Working. A stopped final task
is a kill — no wake follows — and previously left a live session parked
on Waiting until teardown. Flip that case back to ready, and tombstone
completions that outrun their start event.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 514fccf. Configure here.

Tombstones exist to stop late/duplicate progress from resurrecting a
finished task, but providers reuse task ids when an agent is resumed —
a fresh task.started after completion is real work, not a replay.
Progress stays blocked by the tombstone; an explicit start clears it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
t3dotgg added a commit that referenced this pull request Jul 24, 2026
Real-data feedback round two:
- Results render as a responsive grid (1/2/3 columns) instead of a
full-width list.
- While the sweep runs, the page shows only a progress count
("Reviewing your work — 7 of 18"); results reveal all at once when
every thread is done, so triage happens in one pass over a stable
layout instead of chasing cards as they pop in.
- The model now returns a one-sentence imperative nextStep ("Review
and merge PR #4415.") which becomes the card body — a direct answer
to "what should I do here". Summaries are capped at one sentence and
demoted to an info-icon tooltip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 24, 2026
…2.1-next
Absorb CTM tip 408efa6 (Claude replay cleanup, ACP auth/fork provenance,
derived-thread wake, fork-shell navigation wait) onto the pingdotgg#4415 Waiting
sequence pinned at main ece0508.
Conflict resolution (same intent as prior merge 616da6976):
- Sidebar/threadList Waiting uses runtime.idle (CTM/orchestrator-v2 park)
rather than session.idle from main pingdotgg#4415, including mobile tests.
- Drop ProviderRuntimeIngestion (deleted on CTM; v2 uses orchestration-v2).
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 25, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
CTM's own subagent hiding (97a04be) skips delegated children inside
buildThreadListV2Items, so the list is right, but hasAnyThreads still counts
them. A user whose only live threads are subagent children therefore gets the
in-list "No results" state instead of the full-page "No threads yet".
Also corrects the threadListV2 header comment left by the CTM merge: pingdotgg#4415
sidebar-waiting-state describes Waiting as session.idle, while this line keys
it off runtime.idle.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@t3dotgg@juliusmarminge
, '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

feat: "waiting" status for threads with open background tasks (i.e. pr monitors) - #4415

Closed
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state
Closed

feat: "waiting" status for threads with open background tasks (i.e. pr monitors)#4415
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state

Conversation

@t3dotgg

@t3dotggt3dotgg commented Jul 24, 2026

Copy link
Copy Markdown
Member

When the agent stops while background tasks (subagents, background bash, monitors) are still running, the sidebar showed Done, then flicked back to Working when a task completion woke the agent (median 13s later, from local history).

Now ingestion tracks provider-reported open tasks per thread and parks the session on the previously-unused idle status when a turn ends with tasks still open. Sidebar v2 (web + mobile) renders it as a grey Waiting label with the same elapsed timer as Working; the row recedes like other in-flight states. Waiting flips directly to Working on wake-up — no intermediate Done.

  • Task set is keyed by provider instance and cleared on exit/stop/error, so stale tasks can't park a fresh session.
  • idle was already handled as "resting" by settlement, projection, and phase logic, so no contract or migration changes; old clients degrade to today's behavior.
  • Codex/OpenCode don't emit task events — behavior unchanged there.

🤖 Generated with Claude Code


Note

Medium Risk
Changes core session lifecycle in ProviderRuntimeIngestion (when threads show ready vs idle), with broad integration tests but no contract migration—incorrect task tracking could mislabel thread state across clients.

Overview
Threads that finish a turn while provider background tasks (monitors, subagents, etc.) are still open no longer flash Done before the wake-up turn. Provider runtime ingestion now tracks open tasks per thread and provider instance and parks the session on idle instead of ready when a turn ends with tasks still open; task state is cleared on session exit, error, and stale-instance guards, with tombstones for late events.

Web sidebar v2 and the mobile thread list map idle to a muted Waiting label (same elapsed timer as Working, in-flight row treatment). Successful task completion is expected to wake the agent without an intermediate ready; only a stopped last task returns Waiting to ready.

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

Note

Add 'waiting' status for threads with open background tasks

  • Introduces a new idle session status that signals a thread is waiting on background tasks (e.g. PR monitors) rather than active user input or processing.
  • ProviderRuntimeIngestion tracks open tasks per thread/provider instance and transitions sessions to idle at rest when tasks remain open, returning to ready when the last task completes.
  • The web sidebar and mobile thread list both render idle sessions as 'Waiting' with a neutral style and an elapsed duration, treated as in-flight for display purposes.
  • Open task state is cleared on session exit or error so future sessions do not inherit the waiting state.
  • Behavioral Change: threads that previously resolved to ready while background tasks were open will now show as waiting until those tasks complete.

Macroscope summarized 368e0e1.

@coderabbitai

coderabbitaiBot commented Jul 24, 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: 91fb2c98-8548-4670-a2cd-2cbb6e8a3eee

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/sidebar-waiting-state

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:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 24, 2026
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

New feature introducing a 'waiting' status with non-trivial server-side state tracking logic for background tasks. While well-tested, new user-facing behavior and runtime session status changes warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@t3dotggt3dotgg changed the title Show Waiting state for threads with open background tasksfeat: "waiting" status for threads with open background tasks (i.e. pr monitors)Jul 24, 2026
t3dotggand others added 2 commits July 23, 2026 22:21
When the agent stops with background tasks (subagents, background bash,
monitors) still running, the thread showed Done, then flicked back to
Working when a task completion woke the agent. Track provider-reported
open tasks in ingestion and park the session on the previously-unused
"idle" status; sidebar v2 renders it as a grey "Waiting" with the same
elapsed timer as Working.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review fixes: gate the terminal-status task sweep behind the lifecycle
guard so rejected stale events cannot erase the active turn's tasks;
ignore task starts from a provider instance that doesn't match the
projected session instead of letting them displace the current set;
tombstone completed task ids so late/duplicate progress cannot re-open
a finished task and park the thread on Waiting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the t3code/sidebar-waiting-state branch from bec6dc6 to 528adb2CompareJuly 24, 2026 05:22
Comment threadapps/web/src/components/SidebarV2.tsx
A completed/failed final task wakes the agent (its notification is the
wake signal), so Waiting flips straight to Working. A stopped final task
is a kill — no wake follows — and previously left a live session parked
on Waiting until teardown. Flip that case back to ready, and tombstone
completions that outrun their start event.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 514fccf. Configure here.

Tombstones exist to stop late/duplicate progress from resurrecting a
finished task, but providers reuse task ids when an agent is resumed —
a fresh task.started after completion is real work, not a replay.
Progress stays blocked by the tombstone; an explicit start clears it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
t3dotgg added a commit that referenced this pull request Jul 24, 2026
Real-data feedback round two:
- Results render as a responsive grid (1/2/3 columns) instead of a
full-width list.
- While the sweep runs, the page shows only a progress count
("Reviewing your work — 7 of 18"); results reveal all at once when
every thread is done, so triage happens in one pass over a stable
layout instead of chasing cards as they pop in.
- The model now returns a one-sentence imperative nextStep ("Review
and merge PR #4415.") which becomes the card body — a direct answer
to "what should I do here". Summaries are capped at one sentence and
demoted to an info-icon tooltip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 24, 2026
…2.1-next
Absorb CTM tip 408efa6 (Claude replay cleanup, ACP auth/fork provenance,
derived-thread wake, fork-shell navigation wait) onto the pingdotgg#4415 Waiting
sequence pinned at main ece0508.
Conflict resolution (same intent as prior merge 616da6976):
- Sidebar/threadList Waiting uses runtime.idle (CTM/orchestrator-v2 park)
rather than session.idle from main pingdotgg#4415, including mobile tests.
- Drop ProviderRuntimeIngestion (deleted on CTM; v2 uses orchestration-v2).
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 25, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
CTM's own subagent hiding (97a04be) skips delegated children inside
buildThreadListV2Items, so the list is right, but hasAnyThreads still counts
them. A user whose only live threads are subagent children therefore gets the
in-list "No results" state instead of the full-page "No threads yet".
Also corrects the threadListV2 header comment left by the CTM merge: pingdotgg#4415
sidebar-waiting-state describes Waiting as session.idle, while this line keys
it off runtime.idle.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@t3dotgg@juliusmarminge
, '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

feat: "waiting" status for threads with open background tasks (i.e. pr monitors) - #4415

Closed
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state
Closed

feat: "waiting" status for threads with open background tasks (i.e. pr monitors)#4415
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state

Conversation

@t3dotgg

@t3dotggt3dotgg commented Jul 24, 2026

Copy link
Copy Markdown
Member

When the agent stops while background tasks (subagents, background bash, monitors) are still running, the sidebar showed Done, then flicked back to Working when a task completion woke the agent (median 13s later, from local history).

Now ingestion tracks provider-reported open tasks per thread and parks the session on the previously-unused idle status when a turn ends with tasks still open. Sidebar v2 (web + mobile) renders it as a grey Waiting label with the same elapsed timer as Working; the row recedes like other in-flight states. Waiting flips directly to Working on wake-up — no intermediate Done.

  • Task set is keyed by provider instance and cleared on exit/stop/error, so stale tasks can't park a fresh session.
  • idle was already handled as "resting" by settlement, projection, and phase logic, so no contract or migration changes; old clients degrade to today's behavior.
  • Codex/OpenCode don't emit task events — behavior unchanged there.

🤖 Generated with Claude Code


Note

Medium Risk
Changes core session lifecycle in ProviderRuntimeIngestion (when threads show ready vs idle), with broad integration tests but no contract migration—incorrect task tracking could mislabel thread state across clients.

Overview
Threads that finish a turn while provider background tasks (monitors, subagents, etc.) are still open no longer flash Done before the wake-up turn. Provider runtime ingestion now tracks open tasks per thread and provider instance and parks the session on idle instead of ready when a turn ends with tasks still open; task state is cleared on session exit, error, and stale-instance guards, with tombstones for late events.

Web sidebar v2 and the mobile thread list map idle to a muted Waiting label (same elapsed timer as Working, in-flight row treatment). Successful task completion is expected to wake the agent without an intermediate ready; only a stopped last task returns Waiting to ready.

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

Note

Add 'waiting' status for threads with open background tasks

  • Introduces a new idle session status that signals a thread is waiting on background tasks (e.g. PR monitors) rather than active user input or processing.
  • ProviderRuntimeIngestion tracks open tasks per thread/provider instance and transitions sessions to idle at rest when tasks remain open, returning to ready when the last task completes.
  • The web sidebar and mobile thread list both render idle sessions as 'Waiting' with a neutral style and an elapsed duration, treated as in-flight for display purposes.
  • Open task state is cleared on session exit or error so future sessions do not inherit the waiting state.
  • Behavioral Change: threads that previously resolved to ready while background tasks were open will now show as waiting until those tasks complete.

Macroscope summarized 368e0e1.

@coderabbitai

coderabbitaiBot commented Jul 24, 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: 91fb2c98-8548-4670-a2cd-2cbb6e8a3eee

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/sidebar-waiting-state

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:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 24, 2026
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

New feature introducing a 'waiting' status with non-trivial server-side state tracking logic for background tasks. While well-tested, new user-facing behavior and runtime session status changes warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@t3dotggt3dotgg changed the title Show Waiting state for threads with open background tasksfeat: "waiting" status for threads with open background tasks (i.e. pr monitors)Jul 24, 2026
t3dotggand others added 2 commits July 23, 2026 22:21
When the agent stops with background tasks (subagents, background bash,
monitors) still running, the thread showed Done, then flicked back to
Working when a task completion woke the agent. Track provider-reported
open tasks in ingestion and park the session on the previously-unused
"idle" status; sidebar v2 renders it as a grey "Waiting" with the same
elapsed timer as Working.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review fixes: gate the terminal-status task sweep behind the lifecycle
guard so rejected stale events cannot erase the active turn's tasks;
ignore task starts from a provider instance that doesn't match the
projected session instead of letting them displace the current set;
tombstone completed task ids so late/duplicate progress cannot re-open
a finished task and park the thread on Waiting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the t3code/sidebar-waiting-state branch from bec6dc6 to 528adb2CompareJuly 24, 2026 05:22
Comment threadapps/web/src/components/SidebarV2.tsx
A completed/failed final task wakes the agent (its notification is the
wake signal), so Waiting flips straight to Working. A stopped final task
is a kill — no wake follows — and previously left a live session parked
on Waiting until teardown. Flip that case back to ready, and tombstone
completions that outrun their start event.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 514fccf. Configure here.

Tombstones exist to stop late/duplicate progress from resurrecting a
finished task, but providers reuse task ids when an agent is resumed —
a fresh task.started after completion is real work, not a replay.
Progress stays blocked by the tombstone; an explicit start clears it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
t3dotgg added a commit that referenced this pull request Jul 24, 2026
Real-data feedback round two:
- Results render as a responsive grid (1/2/3 columns) instead of a
full-width list.
- While the sweep runs, the page shows only a progress count
("Reviewing your work — 7 of 18"); results reveal all at once when
every thread is done, so triage happens in one pass over a stable
layout instead of chasing cards as they pop in.
- The model now returns a one-sentence imperative nextStep ("Review
and merge PR #4415.") which becomes the card body — a direct answer
to "what should I do here". Summaries are capped at one sentence and
demoted to an info-icon tooltip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 24, 2026
…2.1-next
Absorb CTM tip 408efa6 (Claude replay cleanup, ACP auth/fork provenance,
derived-thread wake, fork-shell navigation wait) onto the pingdotgg#4415 Waiting
sequence pinned at main ece0508.
Conflict resolution (same intent as prior merge 616da6976):
- Sidebar/threadList Waiting uses runtime.idle (CTM/orchestrator-v2 park)
rather than session.idle from main pingdotgg#4415, including mobile tests.
- Drop ProviderRuntimeIngestion (deleted on CTM; v2 uses orchestration-v2).
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 25, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
CTM's own subagent hiding (97a04be) skips delegated children inside
buildThreadListV2Items, so the list is right, but hasAnyThreads still counts
them. A user whose only live threads are subagent children therefore gets the
in-list "No results" state instead of the full-page "No threads yet".
Also corrects the threadListV2 header comment left by the CTM merge: pingdotgg#4415
sidebar-waiting-state describes Waiting as session.idle, while this line keys
it off runtime.idle.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@t3dotgg@juliusmarminge
, '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

feat: "waiting" status for threads with open background tasks (i.e. pr monitors) - #4415

Closed
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state
Closed

feat: "waiting" status for threads with open background tasks (i.e. pr monitors)#4415
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state

Conversation

@t3dotgg

@t3dotggt3dotgg commented Jul 24, 2026

Copy link
Copy Markdown
Member

When the agent stops while background tasks (subagents, background bash, monitors) are still running, the sidebar showed Done, then flicked back to Working when a task completion woke the agent (median 13s later, from local history).

Now ingestion tracks provider-reported open tasks per thread and parks the session on the previously-unused idle status when a turn ends with tasks still open. Sidebar v2 (web + mobile) renders it as a grey Waiting label with the same elapsed timer as Working; the row recedes like other in-flight states. Waiting flips directly to Working on wake-up — no intermediate Done.

  • Task set is keyed by provider instance and cleared on exit/stop/error, so stale tasks can't park a fresh session.
  • idle was already handled as "resting" by settlement, projection, and phase logic, so no contract or migration changes; old clients degrade to today's behavior.
  • Codex/OpenCode don't emit task events — behavior unchanged there.

🤖 Generated with Claude Code


Note

Medium Risk
Changes core session lifecycle in ProviderRuntimeIngestion (when threads show ready vs idle), with broad integration tests but no contract migration—incorrect task tracking could mislabel thread state across clients.

Overview
Threads that finish a turn while provider background tasks (monitors, subagents, etc.) are still open no longer flash Done before the wake-up turn. Provider runtime ingestion now tracks open tasks per thread and provider instance and parks the session on idle instead of ready when a turn ends with tasks still open; task state is cleared on session exit, error, and stale-instance guards, with tombstones for late events.

Web sidebar v2 and the mobile thread list map idle to a muted Waiting label (same elapsed timer as Working, in-flight row treatment). Successful task completion is expected to wake the agent without an intermediate ready; only a stopped last task returns Waiting to ready.

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

Note

Add 'waiting' status for threads with open background tasks

  • Introduces a new idle session status that signals a thread is waiting on background tasks (e.g. PR monitors) rather than active user input or processing.
  • ProviderRuntimeIngestion tracks open tasks per thread/provider instance and transitions sessions to idle at rest when tasks remain open, returning to ready when the last task completes.
  • The web sidebar and mobile thread list both render idle sessions as 'Waiting' with a neutral style and an elapsed duration, treated as in-flight for display purposes.
  • Open task state is cleared on session exit or error so future sessions do not inherit the waiting state.
  • Behavioral Change: threads that previously resolved to ready while background tasks were open will now show as waiting until those tasks complete.

Macroscope summarized 368e0e1.

@coderabbitai

coderabbitaiBot commented Jul 24, 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: 91fb2c98-8548-4670-a2cd-2cbb6e8a3eee

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/sidebar-waiting-state

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:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 24, 2026
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

New feature introducing a 'waiting' status with non-trivial server-side state tracking logic for background tasks. While well-tested, new user-facing behavior and runtime session status changes warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@t3dotggt3dotgg changed the title Show Waiting state for threads with open background tasksfeat: "waiting" status for threads with open background tasks (i.e. pr monitors)Jul 24, 2026
t3dotggand others added 2 commits July 23, 2026 22:21
When the agent stops with background tasks (subagents, background bash,
monitors) still running, the thread showed Done, then flicked back to
Working when a task completion woke the agent. Track provider-reported
open tasks in ingestion and park the session on the previously-unused
"idle" status; sidebar v2 renders it as a grey "Waiting" with the same
elapsed timer as Working.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review fixes: gate the terminal-status task sweep behind the lifecycle
guard so rejected stale events cannot erase the active turn's tasks;
ignore task starts from a provider instance that doesn't match the
projected session instead of letting them displace the current set;
tombstone completed task ids so late/duplicate progress cannot re-open
a finished task and park the thread on Waiting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the t3code/sidebar-waiting-state branch from bec6dc6 to 528adb2CompareJuly 24, 2026 05:22
Comment threadapps/web/src/components/SidebarV2.tsx
A completed/failed final task wakes the agent (its notification is the
wake signal), so Waiting flips straight to Working. A stopped final task
is a kill — no wake follows — and previously left a live session parked
on Waiting until teardown. Flip that case back to ready, and tombstone
completions that outrun their start event.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 514fccf. Configure here.

Tombstones exist to stop late/duplicate progress from resurrecting a
finished task, but providers reuse task ids when an agent is resumed —
a fresh task.started after completion is real work, not a replay.
Progress stays blocked by the tombstone; an explicit start clears it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
t3dotgg added a commit that referenced this pull request Jul 24, 2026
Real-data feedback round two:
- Results render as a responsive grid (1/2/3 columns) instead of a
full-width list.
- While the sweep runs, the page shows only a progress count
("Reviewing your work — 7 of 18"); results reveal all at once when
every thread is done, so triage happens in one pass over a stable
layout instead of chasing cards as they pop in.
- The model now returns a one-sentence imperative nextStep ("Review
and merge PR #4415.") which becomes the card body — a direct answer
to "what should I do here". Summaries are capped at one sentence and
demoted to an info-icon tooltip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 24, 2026
…2.1-next
Absorb CTM tip 408efa6 (Claude replay cleanup, ACP auth/fork provenance,
derived-thread wake, fork-shell navigation wait) onto the pingdotgg#4415 Waiting
sequence pinned at main ece0508.
Conflict resolution (same intent as prior merge 616da6976):
- Sidebar/threadList Waiting uses runtime.idle (CTM/orchestrator-v2 park)
rather than session.idle from main pingdotgg#4415, including mobile tests.
- Drop ProviderRuntimeIngestion (deleted on CTM; v2 uses orchestration-v2).
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 25, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
CTM's own subagent hiding (97a04be) skips delegated children inside
buildThreadListV2Items, so the list is right, but hasAnyThreads still counts
them. A user whose only live threads are subagent children therefore gets the
in-list "No results" state instead of the full-page "No threads yet".
Also corrects the threadListV2 header comment left by the CTM merge: pingdotgg#4415
sidebar-waiting-state describes Waiting as session.idle, while this line keys
it off runtime.idle.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@t3dotgg@juliusmarminge
, '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

feat: "waiting" status for threads with open background tasks (i.e. pr monitors) - #4415

Closed
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state
Closed

feat: "waiting" status for threads with open background tasks (i.e. pr monitors)#4415
t3dotgg wants to merge 4 commits into
mainfrom
t3code/sidebar-waiting-state

Conversation

@t3dotgg

@t3dotggt3dotgg commented Jul 24, 2026

Copy link
Copy Markdown
Member

When the agent stops while background tasks (subagents, background bash, monitors) are still running, the sidebar showed Done, then flicked back to Working when a task completion woke the agent (median 13s later, from local history).

Now ingestion tracks provider-reported open tasks per thread and parks the session on the previously-unused idle status when a turn ends with tasks still open. Sidebar v2 (web + mobile) renders it as a grey Waiting label with the same elapsed timer as Working; the row recedes like other in-flight states. Waiting flips directly to Working on wake-up — no intermediate Done.

  • Task set is keyed by provider instance and cleared on exit/stop/error, so stale tasks can't park a fresh session.
  • idle was already handled as "resting" by settlement, projection, and phase logic, so no contract or migration changes; old clients degrade to today's behavior.
  • Codex/OpenCode don't emit task events — behavior unchanged there.

🤖 Generated with Claude Code


Note

Medium Risk
Changes core session lifecycle in ProviderRuntimeIngestion (when threads show ready vs idle), with broad integration tests but no contract migration—incorrect task tracking could mislabel thread state across clients.

Overview
Threads that finish a turn while provider background tasks (monitors, subagents, etc.) are still open no longer flash Done before the wake-up turn. Provider runtime ingestion now tracks open tasks per thread and provider instance and parks the session on idle instead of ready when a turn ends with tasks still open; task state is cleared on session exit, error, and stale-instance guards, with tombstones for late events.

Web sidebar v2 and the mobile thread list map idle to a muted Waiting label (same elapsed timer as Working, in-flight row treatment). Successful task completion is expected to wake the agent without an intermediate ready; only a stopped last task returns Waiting to ready.

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

Note

Add 'waiting' status for threads with open background tasks

  • Introduces a new idle session status that signals a thread is waiting on background tasks (e.g. PR monitors) rather than active user input or processing.
  • ProviderRuntimeIngestion tracks open tasks per thread/provider instance and transitions sessions to idle at rest when tasks remain open, returning to ready when the last task completes.
  • The web sidebar and mobile thread list both render idle sessions as 'Waiting' with a neutral style and an elapsed duration, treated as in-flight for display purposes.
  • Open task state is cleared on session exit or error so future sessions do not inherit the waiting state.
  • Behavioral Change: threads that previously resolved to ready while background tasks were open will now show as waiting until those tasks complete.

Macroscope summarized 368e0e1.

@coderabbitai

coderabbitaiBot commented Jul 24, 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: 91fb2c98-8548-4670-a2cd-2cbb6e8a3eee

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
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/sidebar-waiting-state

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:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 24, 2026
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
Comment threadapps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts Outdated
@macroscopeapp

macroscopeappBot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs human review

New feature introducing a 'waiting' status with non-trivial server-side state tracking logic for background tasks. While well-tested, new user-facing behavior and runtime session status changes warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@t3dotggt3dotgg changed the title Show Waiting state for threads with open background tasksfeat: "waiting" status for threads with open background tasks (i.e. pr monitors)Jul 24, 2026
t3dotggand others added 2 commits July 23, 2026 22:21
When the agent stops with background tasks (subagents, background bash,
monitors) still running, the thread showed Done, then flicked back to
Working when a task completion woke the agent. Track provider-reported
open tasks in ingestion and park the session on the previously-unused
"idle" status; sidebar v2 renders it as a grey "Waiting" with the same
elapsed timer as Working.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review fixes: gate the terminal-status task sweep behind the lifecycle
guard so rejected stale events cannot erase the active turn's tasks;
ignore task starts from a provider instance that doesn't match the
projected session instead of letting them displace the current set;
tombstone completed task ids so late/duplicate progress cannot re-open
a finished task and park the thread on Waiting.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@t3dotgg
t3dotggforce-pushed the t3code/sidebar-waiting-state branch from bec6dc6 to 528adb2CompareJuly 24, 2026 05:22
Comment threadapps/web/src/components/SidebarV2.tsx
A completed/failed final task wakes the agent (its notification is the
wake signal), so Waiting flips straight to Working. A stopped final task
is a kill — no wake follows — and previously left a live session parked
on Waiting until teardown. Flip that case back to ready, and tombstone
completions that outrun their start event.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 514fccf. Configure here.

Tombstones exist to stop late/duplicate progress from resurrecting a
finished task, but providers reuse task ids when an agent is resumed —
a fresh task.started after completion is real work, not a replay.
Progress stays blocked by the tombstone; an explicit start clears it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
t3dotgg added a commit that referenced this pull request Jul 24, 2026
Real-data feedback round two:
- Results render as a responsive grid (1/2/3 columns) instead of a
full-width list.
- While the sweep runs, the page shows only a progress count
("Reviewing your work — 7 of 18"); results reveal all at once when
every thread is done, so triage happens in one pass over a stable
layout instead of chasing cards as they pop in.
- The model now returns a one-sentence imperative nextStep ("Review
and merge PR #4415.") which becomes the card body — a direct answer
to "what should I do here". Summaries are capped at one sentence and
demoted to an info-icon tooltip.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 24, 2026
…2.1-next
Absorb CTM tip 408efa6 (Claude replay cleanup, ACP auth/fork provenance,
derived-thread wake, fork-shell navigation wait) onto the pingdotgg#4415 Waiting
sequence pinned at main ece0508.
Conflict resolution (same intent as prior merge 616da6976):
- Sidebar/threadList Waiting uses runtime.idle (CTM/orchestrator-v2 park)
rather than session.idle from main pingdotgg#4415, including mobile tests.
- Drop ProviderRuntimeIngestion (deleted on CTM; v2 uses orchestration-v2).
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 25, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
@juliusmarminge

Copy link
Copy Markdown
Member

Closing in favor of #2829 (orchestration V2).

#2829 deletes the V1 orchestration layer this PR builds on — apps/server/src/orchestration/**, provider/Layers/*Adapter.ts and provider/Services/** are removed and replaced by apps/server/src/orchestration-v2/**, with the IPC surface renamed to ORCHESTRATION_V2_WS_METHODS. The files this PR touches either no longer exist or are rewritten, so it can't be rebased — it would need reimplementing against the V2 adapters.

This is not a judgement on the change itself. Several of these are real gaps we still want fixed; the base just moved out from under them.

Once #2829 merges, please rebase onto main, port the change to the V2 equivalent, and reopen (or open a fresh PR). Ping me and I'll prioritise the review.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
…list
The conversation timeline showed a Waiting line on desktop but nothing on iOS,
and the mobile thread list showed no status at all. Mobile now derives the same
normalized post-settlement background roster the server and web derive, appends
the matching row to the thread feed, and gives the classic list resolver the
Waiting pill its web counterpart already has.
The conversation view prefers deriveThreadRuntime(projection), so
activeWorkStartedAt went null at settlement and the row it gated simply
vanished. The row is now driven by the roster rather than by run timing. The
list gap was the same shape as the classic web sidebar gap this PR fixes: the
v2 list sits behind a preference that is off, so the list that renders is the
classic one, whose resolveThreadStatus had no Waiting branch. It now ranks a
static muted Waiting pill below approvals, input, active work and failures, and
above Plan Ready. Teaching the v2 list resolver about Waiting is pingdotgg#4415
waiting-presentation's concern, not this commit's.
The derivation lives in deriveThreadPendingBackgroundWork rather than inline in
the composer hook so the policy is unit tested. It passes runs, which the web
call site in ChatView also passes, so turn items owned by a rolled_back run are
abandoned on mobile exactly as they are on desktop. Without that argument the
shared helper sees an empty rolled-back set and iOS would show Waiting where
desktop does not.
Working and Waiting are chosen from the parked runtime rather than from run
timing alone. A successful run persists as waiting with a null completedAt until
checkpoint capture lands, so deriveActiveWorkStartedAt keeps reporting a start
time for that whole window; deriveThreadWorkingStartedAt suppresses it once the
roster has parked the runtime at idle, which is how web sequences the two. A
waiting run with an empty roster still reads Working, since that is checkpoint
capture with no background work behind it.
Two defensive points. Mobile restores projections from disk and
shouldPersistThread persists only settled ones, so a cached projection is
exactly the shape that reproduces a Waiting row for work that already finished;
the roster is therefore gated on a live thread detail, and synchronizing is
refused alongside cached because a subscription passes through it before any
fresh projection arrives. And formatPendingBackgroundWorkLabel interpolates the
raw description, which for a subagent item is the whole child prompt, so the
label is clamped to two lines.
Co-authored-by: codex <codex@users.noreply.github.com>
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
Update sidebar and mobile expectations for the pingdotgg#4415 Waiting status,
repair command-suite settle/interrupt coverage after layer merges, and
remove a duplicate settledAt JSON field that broke contracts typecheck.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 30, 2026
CTM's own subagent hiding (97a04be) skips delegated children inside
buildThreadListV2Items, so the list is right, but hasAnyThreads still counts
them. A user whose only live threads are subagent children therefore gets the
in-list "No results" state instead of the full-page "No threads yet".
Also corrects the threadListV2 header comment left by the CTM merge: pingdotgg#4415
sidebar-waiting-state describes Waiting as session.idle, while this line keys
it off runtime.idle.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L100-499 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@t3dotgg@juliusmarminge