fix(web): Keep running, stopped, and failed rows visible in the work log - #4762

Open
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows
Open

fix(web): Keep running, stopped, and failed rows visible in the work log#4762
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows

Conversation

@mwolson

@mwolsonmwolson commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What Changed

The web work log keeps the rows that tell you what a turn is doing. Running tools stay in the log with a spinner. Interrupted tools stay visible without a success check. Collapsed work logs still show an active or interrupted tool even when newer rows would have pushed it out.

When a provider fails and the turn has no assistant message, the failed error stays in the timeline instead of only the sidebar. Recovered retries still fold like ordinary work.

Why

The server already had the right items. The web timeline treated running and interrupted tools like noise. When a finished turn collapsed its work log, it kept a final assistant message but hid a failed error, so the error only showed in the sidebar.

This is web-only. Mobile does not share these filters.

UI Changes

Running and stopped tool rows remain visible, including in compact work logs. Failed provider errors remain visible on settled turns with no assistant message. Stopped tools have no extra glyph. The interrupt row still carries the stop marker.

No before/after screenshots. Checked on a Codex turn in the web app: a foreground command showed a spinner while running, and after Stop the row stayed without a spinner or success check. A live failed provider turn had the error folded away before this change.

Checklist

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

Note

Medium Risk
Large mobile thread/orchestration migration affects caching, runtime gating, and user-facing archive/stop behavior; removing the thread-transfer report workflow is low risk but changes PR observability for transfer regressions.

Overview
Removes the CI “thread transfer impact” PR comment pipeline by deleting thread-transfer-report.yml and the trusted publisher scripts/tests that validated artifacts and upserted comparison comments. Server test shards can still upload thread-transfer-results artifacts; nothing in this diff publishes them to PRs anymore.

Mobile is moved onto shared V2 orchestration client-runtime paths. SQLite shell/thread caches now encode/decode via StoredOrchestration* schemas and ORCHESTRATION_CACHE_SCHEMA_VERSION, with tests for DateTime round-trips. Connection wiring swaps in boundedThreadSnapshotLoaderLayer and threadHistoryControllerLayer. Thread UI and actions follow projection/runtime models (useSelectedThreadProjection, thread.runtime vs legacy session, RuntimeRequestId for approvals/user input with responseCapability gating). New or expanded UX includes thread queue control, relationships banner, activity inspector (files, rollback), visit watermark dispatch, and threadCanArchive rules that allow archive when queued work has no active provider run. Review/checkpoints derive from ThreadCheckpointSummary / deriveThreadCheckpointSummaries.

Smaller follow-ons: CI installs build-essential so ACP process-tree live tests always compile their pthread fixture; README links appearance docs; desktop exposes userDataDirName / legacy dir names in tests; marketing updates the Cursor harness label; mobile theme generator adds adaptive color tokens used by the new inspector surfaces.

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

Note

Keep running, stopped, and failed rows visible in the work log and build orchestration V2 foundation

  • Adds derivePendingBackgroundWork to derive a post-settlement pending-work roster from provider-thread tasks and nonterminal turn items, gating on latest-run settlement and excluding rolled-back items
  • Updates isOrchestrationV2TurnItemVisible to hide items from rolled-back runs, queued user messages from cancelled runs, and unpaired superseded interruption results
  • Adds T3 MCP tool presentation resolver with display labels and logos for known orchestration, delegation, scheduling, and worktree tools
  • Adds the full orchestration V2 server and client runtime: provider adapters for Claude, Codex, Cursor, Grok, and OpenCode; event store, projection store, command receipt store, effect outbox, checkpoint services, session manager, run execution, thread lifecycle, context handoff, scheduled tasks, and legacy V1 importer
  • Adds database migrations 044–052, V2 contracts, MCP orchestrator and worktree toolkits, bounded thread snapshot loading, web/mobile UI components for queue control, thread details, relationships, and activity inspection
  • Risk: migrations 044–052 create new tables and backfill columns from existing payloads; the IPC EnvironmentApi replaces the legacy orchestration property with orchestrationV2, removing turn-diff and archived-shell methods

Macroscope summarized 05f47ec.

@coderabbitai

coderabbitaiBot commented Jul 28, 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: d63aaf22-b302-4873-a096-e3875d635abe

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

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 size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 28, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
@mwolsonmwolson changed the title fix(web): Keep in-flight and stopped tool rows in the work logfix(orchestrator): Keep in-flight and stopped tool rows in the work logJul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from caf6f38 to d30b4a7CompareJuly 28, 2026 17:55
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
Also from that round:
- Tests pin "no stopped indicator" properly. A stopped row could have regressed
to the dash while every assertion still passed; there is now a negative
`lucide-minus` check, and the running case asserts the spinner carries neither
`role="status"` nor `aria-label="Loading"`, so the accessibility fix cannot
silently revert.
- The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 5a7eae3 to 257f810CompareJuly 28, 2026 18:36
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 257f810 to 365949aCompareJuly 28, 2026 18:55
@mwolson
mwolson marked this pull request as ready for review July 28, 2026 18:55
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx Outdated
@macroscopeapp

macroscopeappBot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This range contains a 331-commit, 955-file orchestration V2 migration with new production workflows, persistence migrations, public API changes, authentication updates, and mobile/server integrations—not just the stated web work-log fix. Unresolved timeline rendering issues and the added product-default and static-analysis override changes add further review risk.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewJuly 28, 2026 19:18

Dismissing prior approval to re-evaluate 7d5e55c

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Jul 28, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
juliusmarmingeand others added 16 commits August 31, 2026 21:33
Retain pending admission after transient status failures and use one generation-owned retry worker. Ignore stale timers and duplicate evidence so older prompts cannot finish newer steering.
Finding: R14 status reconciliation
Model: GPT-5.6 Sol via Codex
Keep hidden local and inherited rows from consuming history pages. Preserve stop-request dependencies, source-run cutoffs, and imported history while loading related metadata from the selected cohort and using indexed watermark lookups.
Finding: P01 bounded history visibility
Model: GPT-5.6 Sol via Codex
Adapt grouped tool summaries and the floating working timer to V2 run, attempt, and queue state. Bring over the composer, keyboard, and disclosure transitions while retaining the V2 activity inspector and queue controls.
Keep OV2 web composer and grouping behavior intact; share only the existing command label parser with mobile.
Restores main features dropped by the policy replay: pingdotgg#8569 theme wiring,
pingdotgg#8850 composer banner follow-ups, pingdotgg#8855/pingdotgg#8904 composer fixes, pingdotgg#8831
settings search rework, pingdotgg#8803 workspace-mutation refresh (v2-adapted),
pingdotgg#8840 circle-alert, pingdotgg#8584 codex artifact templates, pingdotgg#8688/pingdotgg#8807/pingdotgg#8936
video + image previews (web and mobile, v2-adapted), pingdotgg#8862 Expo glass,
and the round's docs. Timeline thinking rows (pingdotgg#8984) stay on the v2
work-live system.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch from a6e0049 to 50a57b6CompareSeptember 1, 2026 05:36
juliusmarmingeand others added 3 commits September 1, 2026 00:24
The v2 equivalents of main's pingdotgg#8984 and pingdotgg#8922: a "Working for ..." header
anchors the active run, the trailing live tool row survives between
actions in past tense instead of vanishing, and a shimmering Thinking
row marks reasoning gaps. During workspace preparation the header shows
"Setting up worktree..." (driven by the local dispatch flag or the v2
run's preparing status, so remote viewers see it too), the composer
footer span is gone, and draft promotion waits until the run starts or
startup fails instead of navigating mid-preparation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 38109f8 to a9f243aCompareSeptember 1, 2026 23:26
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 1, 2026 23:26

Dismissing prior approval to re-evaluate a9f243a

if (
entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)

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.

🟡 Mediumchat/MessagesTimeline.logic.ts:783

A failed itemType: "error" with tone: "info" is rendered as a generic work-toggle instead of a work error row, so the provider error detail remains hidden and the expected provider-error-entry row never appears. deriveTurnFolds now leaves these entries visible, but the rendering branch only recognizes tone === "error"; update that branch to also recognize timelineEntryIsTerminalError.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/chat/MessagesTimeline.logic.ts around line 783:
A failed `itemType: "error"` with `tone: "info"` is rendered as a generic `work-toggle` instead of a `work` error row, so the provider error detail remains hidden and the expected `provider-error-entry` row never appears. `deriveTurnFolds` now leaves these entries visible, but the rendering branch only recognizes `tone === "error"`; update that branch to also recognize `timelineEntryIsTerminalError`.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two of these findings look like fallout from rebasing onto t3code/codex-turn-mapping: the collapsed work-log UI this PR's round-4 repair targets (a per-group visible cap and a "+N previous tool calls" expander) does not exist on this base, so the new selector, its constant, and the component tests written against it have nothing to attach to.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
Comment on lines +2505 to +2557
structuredPayload: { status: row.itemStatus } as OrchestrationV2TurnItem,
},
};
});

// Collapsed groups used to keep only slice(-1), so a later completed tool
// buried the running or stopped row the work-log filter retained.
it("keeps pinned running and stopped tools visible in a collapsed work group", () => {
const runningAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "running", label: "Active shell", itemStatus: "running" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(runningAndCompleted).toContain("Active shell");
expect(runningAndCompleted).toContain("Finished shell");
expect(runningAndCompleted).toContain("lucide-loader-circle");
expect(runningAndCompleted).not.toContain("previous tool");

const stoppedAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "stopped", label: "Interrupted shell", itemStatus: "interrupted" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(stoppedAndCompleted).toContain("Interrupted shell");
expect(stoppedAndCompleted).toContain("Finished shell");
expect(stoppedAndCompleted).toContain(', stopped"');
expect(stoppedAndCompleted).not.toContain("previous tool");
});

it("does not pin pending or waiting rows in a collapsed work group", () => {
const markup = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "pending", label: "Queued shell", itemStatus: "pending" },
{ id: "waiting", label: "Blocked shell", itemStatus: "waiting" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);

expect(markup).toContain("Finished shell");
expect(markup).not.toContain("Queued shell");
expect(markup).not.toContain("Blocked shell");
expect(markup).toContain("+2 previous tool calls");

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.

These collapsed-work-group cases assert against UI that does not exist on this target branch. Work groups render row.summary through WorkGroupToggleTimelineRow (e.g. Ran 2 commands), there is no +N previous tool calls expander string anywhere in MessagesTimeline.tsx, and no per-group visible cap that could hide Queued shell/Blocked shell — so both the pinned-row and the not-pinned expectations fail rather than guarding the fix.

Suggest retargeting them at the work-live/work-toggle row model (or removing them alongside the unused selectCollapsedWorkLogEntries) so the suite matches the shipped work-group rendering.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/ChatView.tsx

@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 2 potential issues.

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 a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Collapsed groups hide pinned tool rows

High Severity

selectCollapsedWorkLogEntries is never used when building or rendering work groups. Settled groups still emit only a work-toggle that hides every row, so running and stopped tools stay behind the summary instead of remaining visible in the compact log. The +N previous tool calls expander the new tests expect is also never rendered.

Additional Locations (2)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Failed errors stay behind work toggle

Medium Severity

deriveTurnFolds now keeps failed itemType === "error" entries out of the turn fold, but row emission still treats projected provider errors as ordinary work because their tone is info. They become a work-toggle labeled Provider error, so the failure detail stays hidden unless the group is expanded.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch 2 times, most recently from 6081201 to 95bacddCompareSeptember 2, 2026 07:19

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The selectCollapsedWorkLogEntries selector plus its collapsed-group tests, and the unused workingStepLabel / pendingBackgroundTasks props, are still in the state described in the earlier threads on MessagesTimeline.logic.ts:76, MessagesTimeline.test.tsx:2557, and MessagesTimeline.tsx:243MAX_VISIBLE_WORK_LOG_ENTRIES now type-checks, but nothing in MessagesTimeline.tsx calls the selector and the shipped work group still renders every visible entry with no per-group cap or expander. Not re-raising those inline.

Posted via Macroscope — UI Consistency

Comment on lines +2410 to +2411
const workRow = (itemStatus: OrchestrationV2TurnItem["status"] | undefined) => {
const toolLifecycleStatus = toolLifecycleStatusForItemStatus(itemStatus);

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.

These fixtures never reach SimpleWorkEntryRow, so the new lifecycle assertions do not exercise the indicators they describe. beforeEach resets activityTestState.expanded to false, and a tone: "tool" entry with a settled run (isWorking: false, latestRun: null) derives a collapsed work-toggle row (MessagesTimeline.logic.ts:1105), which renders only row.summary — no spinner and no lifecycle-suffixed aria-label. expect(markup).toContain("lucide-loader-circle") and toContain(', stopped"') therefore fail, while toContain("Ran command") passes only because that is also the group summary text.

The neighboring failed-marker case opts into the expanded path explicitly; suggest doing the same in this helper so the rows under test are the ones the PR changed:

Suggested change
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
activityTestState.expanded=true;
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);

Posted via Macroscope — UI Consistency

@macroscopeapp

Copy link
Copy Markdown
Contributor

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $248.57, which exceeds your per-review limit of $10.00.

The top 3 files driving up this estimate:

FileDiff SizeEstimate
apps/server/src/orchestration-v2/Orchestrator.ts277.03KB$13.85
apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts272.17KB$13.61
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts230.26KB$11.51

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ 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.

7 participants

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

fix(web): Keep running, stopped, and failed rows visible in the work log - #4762

Open
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows
Open

fix(web): Keep running, stopped, and failed rows visible in the work log#4762
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows

Conversation

@mwolson

@mwolsonmwolson commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What Changed

The web work log keeps the rows that tell you what a turn is doing. Running tools stay in the log with a spinner. Interrupted tools stay visible without a success check. Collapsed work logs still show an active or interrupted tool even when newer rows would have pushed it out.

When a provider fails and the turn has no assistant message, the failed error stays in the timeline instead of only the sidebar. Recovered retries still fold like ordinary work.

Why

The server already had the right items. The web timeline treated running and interrupted tools like noise. When a finished turn collapsed its work log, it kept a final assistant message but hid a failed error, so the error only showed in the sidebar.

This is web-only. Mobile does not share these filters.

UI Changes

Running and stopped tool rows remain visible, including in compact work logs. Failed provider errors remain visible on settled turns with no assistant message. Stopped tools have no extra glyph. The interrupt row still carries the stop marker.

No before/after screenshots. Checked on a Codex turn in the web app: a foreground command showed a spinner while running, and after Stop the row stayed without a spinner or success check. A live failed provider turn had the error folded away before this change.

Checklist

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

Note

Medium Risk
Large mobile thread/orchestration migration affects caching, runtime gating, and user-facing archive/stop behavior; removing the thread-transfer report workflow is low risk but changes PR observability for transfer regressions.

Overview
Removes the CI “thread transfer impact” PR comment pipeline by deleting thread-transfer-report.yml and the trusted publisher scripts/tests that validated artifacts and upserted comparison comments. Server test shards can still upload thread-transfer-results artifacts; nothing in this diff publishes them to PRs anymore.

Mobile is moved onto shared V2 orchestration client-runtime paths. SQLite shell/thread caches now encode/decode via StoredOrchestration* schemas and ORCHESTRATION_CACHE_SCHEMA_VERSION, with tests for DateTime round-trips. Connection wiring swaps in boundedThreadSnapshotLoaderLayer and threadHistoryControllerLayer. Thread UI and actions follow projection/runtime models (useSelectedThreadProjection, thread.runtime vs legacy session, RuntimeRequestId for approvals/user input with responseCapability gating). New or expanded UX includes thread queue control, relationships banner, activity inspector (files, rollback), visit watermark dispatch, and threadCanArchive rules that allow archive when queued work has no active provider run. Review/checkpoints derive from ThreadCheckpointSummary / deriveThreadCheckpointSummaries.

Smaller follow-ons: CI installs build-essential so ACP process-tree live tests always compile their pthread fixture; README links appearance docs; desktop exposes userDataDirName / legacy dir names in tests; marketing updates the Cursor harness label; mobile theme generator adds adaptive color tokens used by the new inspector surfaces.

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

Note

Keep running, stopped, and failed rows visible in the work log and build orchestration V2 foundation

  • Adds derivePendingBackgroundWork to derive a post-settlement pending-work roster from provider-thread tasks and nonterminal turn items, gating on latest-run settlement and excluding rolled-back items
  • Updates isOrchestrationV2TurnItemVisible to hide items from rolled-back runs, queued user messages from cancelled runs, and unpaired superseded interruption results
  • Adds T3 MCP tool presentation resolver with display labels and logos for known orchestration, delegation, scheduling, and worktree tools
  • Adds the full orchestration V2 server and client runtime: provider adapters for Claude, Codex, Cursor, Grok, and OpenCode; event store, projection store, command receipt store, effect outbox, checkpoint services, session manager, run execution, thread lifecycle, context handoff, scheduled tasks, and legacy V1 importer
  • Adds database migrations 044–052, V2 contracts, MCP orchestrator and worktree toolkits, bounded thread snapshot loading, web/mobile UI components for queue control, thread details, relationships, and activity inspection
  • Risk: migrations 044–052 create new tables and backfill columns from existing payloads; the IPC EnvironmentApi replaces the legacy orchestration property with orchestrationV2, removing turn-diff and archived-shell methods

Macroscope summarized 05f47ec.

@coderabbitai

coderabbitaiBot commented Jul 28, 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: d63aaf22-b302-4873-a096-e3875d635abe

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

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 size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 28, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
@mwolsonmwolson changed the title fix(web): Keep in-flight and stopped tool rows in the work logfix(orchestrator): Keep in-flight and stopped tool rows in the work logJul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from caf6f38 to d30b4a7CompareJuly 28, 2026 17:55
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
Also from that round:
- Tests pin "no stopped indicator" properly. A stopped row could have regressed
to the dash while every assertion still passed; there is now a negative
`lucide-minus` check, and the running case asserts the spinner carries neither
`role="status"` nor `aria-label="Loading"`, so the accessibility fix cannot
silently revert.
- The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 5a7eae3 to 257f810CompareJuly 28, 2026 18:36
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 257f810 to 365949aCompareJuly 28, 2026 18:55
@mwolson
mwolson marked this pull request as ready for review July 28, 2026 18:55
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx Outdated
@macroscopeapp

macroscopeappBot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This range contains a 331-commit, 955-file orchestration V2 migration with new production workflows, persistence migrations, public API changes, authentication updates, and mobile/server integrations—not just the stated web work-log fix. Unresolved timeline rendering issues and the added product-default and static-analysis override changes add further review risk.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewJuly 28, 2026 19:18

Dismissing prior approval to re-evaluate 7d5e55c

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Jul 28, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
juliusmarmingeand others added 16 commits August 31, 2026 21:33
Retain pending admission after transient status failures and use one generation-owned retry worker. Ignore stale timers and duplicate evidence so older prompts cannot finish newer steering.
Finding: R14 status reconciliation
Model: GPT-5.6 Sol via Codex
Keep hidden local and inherited rows from consuming history pages. Preserve stop-request dependencies, source-run cutoffs, and imported history while loading related metadata from the selected cohort and using indexed watermark lookups.
Finding: P01 bounded history visibility
Model: GPT-5.6 Sol via Codex
Adapt grouped tool summaries and the floating working timer to V2 run, attempt, and queue state. Bring over the composer, keyboard, and disclosure transitions while retaining the V2 activity inspector and queue controls.
Keep OV2 web composer and grouping behavior intact; share only the existing command label parser with mobile.
Restores main features dropped by the policy replay: pingdotgg#8569 theme wiring,
pingdotgg#8850 composer banner follow-ups, pingdotgg#8855/pingdotgg#8904 composer fixes, pingdotgg#8831
settings search rework, pingdotgg#8803 workspace-mutation refresh (v2-adapted),
pingdotgg#8840 circle-alert, pingdotgg#8584 codex artifact templates, pingdotgg#8688/pingdotgg#8807/pingdotgg#8936
video + image previews (web and mobile, v2-adapted), pingdotgg#8862 Expo glass,
and the round's docs. Timeline thinking rows (pingdotgg#8984) stay on the v2
work-live system.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch from a6e0049 to 50a57b6CompareSeptember 1, 2026 05:36
juliusmarmingeand others added 3 commits September 1, 2026 00:24
The v2 equivalents of main's pingdotgg#8984 and pingdotgg#8922: a "Working for ..." header
anchors the active run, the trailing live tool row survives between
actions in past tense instead of vanishing, and a shimmering Thinking
row marks reasoning gaps. During workspace preparation the header shows
"Setting up worktree..." (driven by the local dispatch flag or the v2
run's preparing status, so remote viewers see it too), the composer
footer span is gone, and draft promotion waits until the run starts or
startup fails instead of navigating mid-preparation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 38109f8 to a9f243aCompareSeptember 1, 2026 23:26
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 1, 2026 23:26

Dismissing prior approval to re-evaluate a9f243a

if (
entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)

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.

🟡 Mediumchat/MessagesTimeline.logic.ts:783

A failed itemType: "error" with tone: "info" is rendered as a generic work-toggle instead of a work error row, so the provider error detail remains hidden and the expected provider-error-entry row never appears. deriveTurnFolds now leaves these entries visible, but the rendering branch only recognizes tone === "error"; update that branch to also recognize timelineEntryIsTerminalError.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/chat/MessagesTimeline.logic.ts around line 783:
A failed `itemType: "error"` with `tone: "info"` is rendered as a generic `work-toggle` instead of a `work` error row, so the provider error detail remains hidden and the expected `provider-error-entry` row never appears. `deriveTurnFolds` now leaves these entries visible, but the rendering branch only recognizes `tone === "error"`; update that branch to also recognize `timelineEntryIsTerminalError`.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two of these findings look like fallout from rebasing onto t3code/codex-turn-mapping: the collapsed work-log UI this PR's round-4 repair targets (a per-group visible cap and a "+N previous tool calls" expander) does not exist on this base, so the new selector, its constant, and the component tests written against it have nothing to attach to.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
Comment on lines +2505 to +2557
structuredPayload: { status: row.itemStatus } as OrchestrationV2TurnItem,
},
};
});

// Collapsed groups used to keep only slice(-1), so a later completed tool
// buried the running or stopped row the work-log filter retained.
it("keeps pinned running and stopped tools visible in a collapsed work group", () => {
const runningAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "running", label: "Active shell", itemStatus: "running" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(runningAndCompleted).toContain("Active shell");
expect(runningAndCompleted).toContain("Finished shell");
expect(runningAndCompleted).toContain("lucide-loader-circle");
expect(runningAndCompleted).not.toContain("previous tool");

const stoppedAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "stopped", label: "Interrupted shell", itemStatus: "interrupted" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(stoppedAndCompleted).toContain("Interrupted shell");
expect(stoppedAndCompleted).toContain("Finished shell");
expect(stoppedAndCompleted).toContain(', stopped"');
expect(stoppedAndCompleted).not.toContain("previous tool");
});

it("does not pin pending or waiting rows in a collapsed work group", () => {
const markup = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "pending", label: "Queued shell", itemStatus: "pending" },
{ id: "waiting", label: "Blocked shell", itemStatus: "waiting" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);

expect(markup).toContain("Finished shell");
expect(markup).not.toContain("Queued shell");
expect(markup).not.toContain("Blocked shell");
expect(markup).toContain("+2 previous tool calls");

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.

These collapsed-work-group cases assert against UI that does not exist on this target branch. Work groups render row.summary through WorkGroupToggleTimelineRow (e.g. Ran 2 commands), there is no +N previous tool calls expander string anywhere in MessagesTimeline.tsx, and no per-group visible cap that could hide Queued shell/Blocked shell — so both the pinned-row and the not-pinned expectations fail rather than guarding the fix.

Suggest retargeting them at the work-live/work-toggle row model (or removing them alongside the unused selectCollapsedWorkLogEntries) so the suite matches the shipped work-group rendering.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/ChatView.tsx

@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 2 potential issues.

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 a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Collapsed groups hide pinned tool rows

High Severity

selectCollapsedWorkLogEntries is never used when building or rendering work groups. Settled groups still emit only a work-toggle that hides every row, so running and stopped tools stay behind the summary instead of remaining visible in the compact log. The +N previous tool calls expander the new tests expect is also never rendered.

Additional Locations (2)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Failed errors stay behind work toggle

Medium Severity

deriveTurnFolds now keeps failed itemType === "error" entries out of the turn fold, but row emission still treats projected provider errors as ordinary work because their tone is info. They become a work-toggle labeled Provider error, so the failure detail stays hidden unless the group is expanded.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch 2 times, most recently from 6081201 to 95bacddCompareSeptember 2, 2026 07:19

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The selectCollapsedWorkLogEntries selector plus its collapsed-group tests, and the unused workingStepLabel / pendingBackgroundTasks props, are still in the state described in the earlier threads on MessagesTimeline.logic.ts:76, MessagesTimeline.test.tsx:2557, and MessagesTimeline.tsx:243MAX_VISIBLE_WORK_LOG_ENTRIES now type-checks, but nothing in MessagesTimeline.tsx calls the selector and the shipped work group still renders every visible entry with no per-group cap or expander. Not re-raising those inline.

Posted via Macroscope — UI Consistency

Comment on lines +2410 to +2411
const workRow = (itemStatus: OrchestrationV2TurnItem["status"] | undefined) => {
const toolLifecycleStatus = toolLifecycleStatusForItemStatus(itemStatus);

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.

These fixtures never reach SimpleWorkEntryRow, so the new lifecycle assertions do not exercise the indicators they describe. beforeEach resets activityTestState.expanded to false, and a tone: "tool" entry with a settled run (isWorking: false, latestRun: null) derives a collapsed work-toggle row (MessagesTimeline.logic.ts:1105), which renders only row.summary — no spinner and no lifecycle-suffixed aria-label. expect(markup).toContain("lucide-loader-circle") and toContain(', stopped"') therefore fail, while toContain("Ran command") passes only because that is also the group summary text.

The neighboring failed-marker case opts into the expanded path explicitly; suggest doing the same in this helper so the rows under test are the ones the PR changed:

Suggested change
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
activityTestState.expanded=true;
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);

Posted via Macroscope — UI Consistency

@macroscopeapp

Copy link
Copy Markdown
Contributor

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $248.57, which exceeds your per-review limit of $10.00.

The top 3 files driving up this estimate:

FileDiff SizeEstimate
apps/server/src/orchestration-v2/Orchestrator.ts277.03KB$13.85
apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts272.17KB$13.61
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts230.26KB$11.51

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ 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.

7 participants

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

fix(web): Keep running, stopped, and failed rows visible in the work log - #4762

Open
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows
Open

fix(web): Keep running, stopped, and failed rows visible in the work log#4762
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows

Conversation

@mwolson

@mwolsonmwolson commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What Changed

The web work log keeps the rows that tell you what a turn is doing. Running tools stay in the log with a spinner. Interrupted tools stay visible without a success check. Collapsed work logs still show an active or interrupted tool even when newer rows would have pushed it out.

When a provider fails and the turn has no assistant message, the failed error stays in the timeline instead of only the sidebar. Recovered retries still fold like ordinary work.

Why

The server already had the right items. The web timeline treated running and interrupted tools like noise. When a finished turn collapsed its work log, it kept a final assistant message but hid a failed error, so the error only showed in the sidebar.

This is web-only. Mobile does not share these filters.

UI Changes

Running and stopped tool rows remain visible, including in compact work logs. Failed provider errors remain visible on settled turns with no assistant message. Stopped tools have no extra glyph. The interrupt row still carries the stop marker.

No before/after screenshots. Checked on a Codex turn in the web app: a foreground command showed a spinner while running, and after Stop the row stayed without a spinner or success check. A live failed provider turn had the error folded away before this change.

Checklist

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

Note

Medium Risk
Large mobile thread/orchestration migration affects caching, runtime gating, and user-facing archive/stop behavior; removing the thread-transfer report workflow is low risk but changes PR observability for transfer regressions.

Overview
Removes the CI “thread transfer impact” PR comment pipeline by deleting thread-transfer-report.yml and the trusted publisher scripts/tests that validated artifacts and upserted comparison comments. Server test shards can still upload thread-transfer-results artifacts; nothing in this diff publishes them to PRs anymore.

Mobile is moved onto shared V2 orchestration client-runtime paths. SQLite shell/thread caches now encode/decode via StoredOrchestration* schemas and ORCHESTRATION_CACHE_SCHEMA_VERSION, with tests for DateTime round-trips. Connection wiring swaps in boundedThreadSnapshotLoaderLayer and threadHistoryControllerLayer. Thread UI and actions follow projection/runtime models (useSelectedThreadProjection, thread.runtime vs legacy session, RuntimeRequestId for approvals/user input with responseCapability gating). New or expanded UX includes thread queue control, relationships banner, activity inspector (files, rollback), visit watermark dispatch, and threadCanArchive rules that allow archive when queued work has no active provider run. Review/checkpoints derive from ThreadCheckpointSummary / deriveThreadCheckpointSummaries.

Smaller follow-ons: CI installs build-essential so ACP process-tree live tests always compile their pthread fixture; README links appearance docs; desktop exposes userDataDirName / legacy dir names in tests; marketing updates the Cursor harness label; mobile theme generator adds adaptive color tokens used by the new inspector surfaces.

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

Note

Keep running, stopped, and failed rows visible in the work log and build orchestration V2 foundation

  • Adds derivePendingBackgroundWork to derive a post-settlement pending-work roster from provider-thread tasks and nonterminal turn items, gating on latest-run settlement and excluding rolled-back items
  • Updates isOrchestrationV2TurnItemVisible to hide items from rolled-back runs, queued user messages from cancelled runs, and unpaired superseded interruption results
  • Adds T3 MCP tool presentation resolver with display labels and logos for known orchestration, delegation, scheduling, and worktree tools
  • Adds the full orchestration V2 server and client runtime: provider adapters for Claude, Codex, Cursor, Grok, and OpenCode; event store, projection store, command receipt store, effect outbox, checkpoint services, session manager, run execution, thread lifecycle, context handoff, scheduled tasks, and legacy V1 importer
  • Adds database migrations 044–052, V2 contracts, MCP orchestrator and worktree toolkits, bounded thread snapshot loading, web/mobile UI components for queue control, thread details, relationships, and activity inspection
  • Risk: migrations 044–052 create new tables and backfill columns from existing payloads; the IPC EnvironmentApi replaces the legacy orchestration property with orchestrationV2, removing turn-diff and archived-shell methods

Macroscope summarized 05f47ec.

@coderabbitai

coderabbitaiBot commented Jul 28, 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: d63aaf22-b302-4873-a096-e3875d635abe

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

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 size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 28, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
@mwolsonmwolson changed the title fix(web): Keep in-flight and stopped tool rows in the work logfix(orchestrator): Keep in-flight and stopped tool rows in the work logJul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from caf6f38 to d30b4a7CompareJuly 28, 2026 17:55
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
Also from that round:
- Tests pin "no stopped indicator" properly. A stopped row could have regressed
to the dash while every assertion still passed; there is now a negative
`lucide-minus` check, and the running case asserts the spinner carries neither
`role="status"` nor `aria-label="Loading"`, so the accessibility fix cannot
silently revert.
- The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 5a7eae3 to 257f810CompareJuly 28, 2026 18:36
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 257f810 to 365949aCompareJuly 28, 2026 18:55
@mwolson
mwolson marked this pull request as ready for review July 28, 2026 18:55
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx Outdated
@macroscopeapp

macroscopeappBot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This range contains a 331-commit, 955-file orchestration V2 migration with new production workflows, persistence migrations, public API changes, authentication updates, and mobile/server integrations—not just the stated web work-log fix. Unresolved timeline rendering issues and the added product-default and static-analysis override changes add further review risk.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewJuly 28, 2026 19:18

Dismissing prior approval to re-evaluate 7d5e55c

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Jul 28, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
juliusmarmingeand others added 16 commits August 31, 2026 21:33
Retain pending admission after transient status failures and use one generation-owned retry worker. Ignore stale timers and duplicate evidence so older prompts cannot finish newer steering.
Finding: R14 status reconciliation
Model: GPT-5.6 Sol via Codex
Keep hidden local and inherited rows from consuming history pages. Preserve stop-request dependencies, source-run cutoffs, and imported history while loading related metadata from the selected cohort and using indexed watermark lookups.
Finding: P01 bounded history visibility
Model: GPT-5.6 Sol via Codex
Adapt grouped tool summaries and the floating working timer to V2 run, attempt, and queue state. Bring over the composer, keyboard, and disclosure transitions while retaining the V2 activity inspector and queue controls.
Keep OV2 web composer and grouping behavior intact; share only the existing command label parser with mobile.
Restores main features dropped by the policy replay: pingdotgg#8569 theme wiring,
pingdotgg#8850 composer banner follow-ups, pingdotgg#8855/pingdotgg#8904 composer fixes, pingdotgg#8831
settings search rework, pingdotgg#8803 workspace-mutation refresh (v2-adapted),
pingdotgg#8840 circle-alert, pingdotgg#8584 codex artifact templates, pingdotgg#8688/pingdotgg#8807/pingdotgg#8936
video + image previews (web and mobile, v2-adapted), pingdotgg#8862 Expo glass,
and the round's docs. Timeline thinking rows (pingdotgg#8984) stay on the v2
work-live system.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch from a6e0049 to 50a57b6CompareSeptember 1, 2026 05:36
juliusmarmingeand others added 3 commits September 1, 2026 00:24
The v2 equivalents of main's pingdotgg#8984 and pingdotgg#8922: a "Working for ..." header
anchors the active run, the trailing live tool row survives between
actions in past tense instead of vanishing, and a shimmering Thinking
row marks reasoning gaps. During workspace preparation the header shows
"Setting up worktree..." (driven by the local dispatch flag or the v2
run's preparing status, so remote viewers see it too), the composer
footer span is gone, and draft promotion waits until the run starts or
startup fails instead of navigating mid-preparation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 38109f8 to a9f243aCompareSeptember 1, 2026 23:26
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 1, 2026 23:26

Dismissing prior approval to re-evaluate a9f243a

if (
entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)

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.

🟡 Mediumchat/MessagesTimeline.logic.ts:783

A failed itemType: "error" with tone: "info" is rendered as a generic work-toggle instead of a work error row, so the provider error detail remains hidden and the expected provider-error-entry row never appears. deriveTurnFolds now leaves these entries visible, but the rendering branch only recognizes tone === "error"; update that branch to also recognize timelineEntryIsTerminalError.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/chat/MessagesTimeline.logic.ts around line 783:
A failed `itemType: "error"` with `tone: "info"` is rendered as a generic `work-toggle` instead of a `work` error row, so the provider error detail remains hidden and the expected `provider-error-entry` row never appears. `deriveTurnFolds` now leaves these entries visible, but the rendering branch only recognizes `tone === "error"`; update that branch to also recognize `timelineEntryIsTerminalError`.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two of these findings look like fallout from rebasing onto t3code/codex-turn-mapping: the collapsed work-log UI this PR's round-4 repair targets (a per-group visible cap and a "+N previous tool calls" expander) does not exist on this base, so the new selector, its constant, and the component tests written against it have nothing to attach to.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
Comment on lines +2505 to +2557
structuredPayload: { status: row.itemStatus } as OrchestrationV2TurnItem,
},
};
});

// Collapsed groups used to keep only slice(-1), so a later completed tool
// buried the running or stopped row the work-log filter retained.
it("keeps pinned running and stopped tools visible in a collapsed work group", () => {
const runningAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "running", label: "Active shell", itemStatus: "running" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(runningAndCompleted).toContain("Active shell");
expect(runningAndCompleted).toContain("Finished shell");
expect(runningAndCompleted).toContain("lucide-loader-circle");
expect(runningAndCompleted).not.toContain("previous tool");

const stoppedAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "stopped", label: "Interrupted shell", itemStatus: "interrupted" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(stoppedAndCompleted).toContain("Interrupted shell");
expect(stoppedAndCompleted).toContain("Finished shell");
expect(stoppedAndCompleted).toContain(', stopped"');
expect(stoppedAndCompleted).not.toContain("previous tool");
});

it("does not pin pending or waiting rows in a collapsed work group", () => {
const markup = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "pending", label: "Queued shell", itemStatus: "pending" },
{ id: "waiting", label: "Blocked shell", itemStatus: "waiting" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);

expect(markup).toContain("Finished shell");
expect(markup).not.toContain("Queued shell");
expect(markup).not.toContain("Blocked shell");
expect(markup).toContain("+2 previous tool calls");

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.

These collapsed-work-group cases assert against UI that does not exist on this target branch. Work groups render row.summary through WorkGroupToggleTimelineRow (e.g. Ran 2 commands), there is no +N previous tool calls expander string anywhere in MessagesTimeline.tsx, and no per-group visible cap that could hide Queued shell/Blocked shell — so both the pinned-row and the not-pinned expectations fail rather than guarding the fix.

Suggest retargeting them at the work-live/work-toggle row model (or removing them alongside the unused selectCollapsedWorkLogEntries) so the suite matches the shipped work-group rendering.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/ChatView.tsx

@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 2 potential issues.

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 a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Collapsed groups hide pinned tool rows

High Severity

selectCollapsedWorkLogEntries is never used when building or rendering work groups. Settled groups still emit only a work-toggle that hides every row, so running and stopped tools stay behind the summary instead of remaining visible in the compact log. The +N previous tool calls expander the new tests expect is also never rendered.

Additional Locations (2)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Failed errors stay behind work toggle

Medium Severity

deriveTurnFolds now keeps failed itemType === "error" entries out of the turn fold, but row emission still treats projected provider errors as ordinary work because their tone is info. They become a work-toggle labeled Provider error, so the failure detail stays hidden unless the group is expanded.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch 2 times, most recently from 6081201 to 95bacddCompareSeptember 2, 2026 07:19

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The selectCollapsedWorkLogEntries selector plus its collapsed-group tests, and the unused workingStepLabel / pendingBackgroundTasks props, are still in the state described in the earlier threads on MessagesTimeline.logic.ts:76, MessagesTimeline.test.tsx:2557, and MessagesTimeline.tsx:243MAX_VISIBLE_WORK_LOG_ENTRIES now type-checks, but nothing in MessagesTimeline.tsx calls the selector and the shipped work group still renders every visible entry with no per-group cap or expander. Not re-raising those inline.

Posted via Macroscope — UI Consistency

Comment on lines +2410 to +2411
const workRow = (itemStatus: OrchestrationV2TurnItem["status"] | undefined) => {
const toolLifecycleStatus = toolLifecycleStatusForItemStatus(itemStatus);

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.

These fixtures never reach SimpleWorkEntryRow, so the new lifecycle assertions do not exercise the indicators they describe. beforeEach resets activityTestState.expanded to false, and a tone: "tool" entry with a settled run (isWorking: false, latestRun: null) derives a collapsed work-toggle row (MessagesTimeline.logic.ts:1105), which renders only row.summary — no spinner and no lifecycle-suffixed aria-label. expect(markup).toContain("lucide-loader-circle") and toContain(', stopped"') therefore fail, while toContain("Ran command") passes only because that is also the group summary text.

The neighboring failed-marker case opts into the expanded path explicitly; suggest doing the same in this helper so the rows under test are the ones the PR changed:

Suggested change
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
activityTestState.expanded=true;
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);

Posted via Macroscope — UI Consistency

@macroscopeapp

Copy link
Copy Markdown
Contributor

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $248.57, which exceeds your per-review limit of $10.00.

The top 3 files driving up this estimate:

FileDiff SizeEstimate
apps/server/src/orchestration-v2/Orchestrator.ts277.03KB$13.85
apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts272.17KB$13.61
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts230.26KB$11.51

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ 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.

7 participants

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

fix(web): Keep running, stopped, and failed rows visible in the work log - #4762

Open
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows
Open

fix(web): Keep running, stopped, and failed rows visible in the work log#4762
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows

Conversation

@mwolson

@mwolsonmwolson commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What Changed

The web work log keeps the rows that tell you what a turn is doing. Running tools stay in the log with a spinner. Interrupted tools stay visible without a success check. Collapsed work logs still show an active or interrupted tool even when newer rows would have pushed it out.

When a provider fails and the turn has no assistant message, the failed error stays in the timeline instead of only the sidebar. Recovered retries still fold like ordinary work.

Why

The server already had the right items. The web timeline treated running and interrupted tools like noise. When a finished turn collapsed its work log, it kept a final assistant message but hid a failed error, so the error only showed in the sidebar.

This is web-only. Mobile does not share these filters.

UI Changes

Running and stopped tool rows remain visible, including in compact work logs. Failed provider errors remain visible on settled turns with no assistant message. Stopped tools have no extra glyph. The interrupt row still carries the stop marker.

No before/after screenshots. Checked on a Codex turn in the web app: a foreground command showed a spinner while running, and after Stop the row stayed without a spinner or success check. A live failed provider turn had the error folded away before this change.

Checklist

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

Note

Medium Risk
Large mobile thread/orchestration migration affects caching, runtime gating, and user-facing archive/stop behavior; removing the thread-transfer report workflow is low risk but changes PR observability for transfer regressions.

Overview
Removes the CI “thread transfer impact” PR comment pipeline by deleting thread-transfer-report.yml and the trusted publisher scripts/tests that validated artifacts and upserted comparison comments. Server test shards can still upload thread-transfer-results artifacts; nothing in this diff publishes them to PRs anymore.

Mobile is moved onto shared V2 orchestration client-runtime paths. SQLite shell/thread caches now encode/decode via StoredOrchestration* schemas and ORCHESTRATION_CACHE_SCHEMA_VERSION, with tests for DateTime round-trips. Connection wiring swaps in boundedThreadSnapshotLoaderLayer and threadHistoryControllerLayer. Thread UI and actions follow projection/runtime models (useSelectedThreadProjection, thread.runtime vs legacy session, RuntimeRequestId for approvals/user input with responseCapability gating). New or expanded UX includes thread queue control, relationships banner, activity inspector (files, rollback), visit watermark dispatch, and threadCanArchive rules that allow archive when queued work has no active provider run. Review/checkpoints derive from ThreadCheckpointSummary / deriveThreadCheckpointSummaries.

Smaller follow-ons: CI installs build-essential so ACP process-tree live tests always compile their pthread fixture; README links appearance docs; desktop exposes userDataDirName / legacy dir names in tests; marketing updates the Cursor harness label; mobile theme generator adds adaptive color tokens used by the new inspector surfaces.

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

Note

Keep running, stopped, and failed rows visible in the work log and build orchestration V2 foundation

  • Adds derivePendingBackgroundWork to derive a post-settlement pending-work roster from provider-thread tasks and nonterminal turn items, gating on latest-run settlement and excluding rolled-back items
  • Updates isOrchestrationV2TurnItemVisible to hide items from rolled-back runs, queued user messages from cancelled runs, and unpaired superseded interruption results
  • Adds T3 MCP tool presentation resolver with display labels and logos for known orchestration, delegation, scheduling, and worktree tools
  • Adds the full orchestration V2 server and client runtime: provider adapters for Claude, Codex, Cursor, Grok, and OpenCode; event store, projection store, command receipt store, effect outbox, checkpoint services, session manager, run execution, thread lifecycle, context handoff, scheduled tasks, and legacy V1 importer
  • Adds database migrations 044–052, V2 contracts, MCP orchestrator and worktree toolkits, bounded thread snapshot loading, web/mobile UI components for queue control, thread details, relationships, and activity inspection
  • Risk: migrations 044–052 create new tables and backfill columns from existing payloads; the IPC EnvironmentApi replaces the legacy orchestration property with orchestrationV2, removing turn-diff and archived-shell methods

Macroscope summarized 05f47ec.

@coderabbitai

coderabbitaiBot commented Jul 28, 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: d63aaf22-b302-4873-a096-e3875d635abe

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

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 size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 28, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
@mwolsonmwolson changed the title fix(web): Keep in-flight and stopped tool rows in the work logfix(orchestrator): Keep in-flight and stopped tool rows in the work logJul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from caf6f38 to d30b4a7CompareJuly 28, 2026 17:55
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
Also from that round:
- Tests pin "no stopped indicator" properly. A stopped row could have regressed
to the dash while every assertion still passed; there is now a negative
`lucide-minus` check, and the running case asserts the spinner carries neither
`role="status"` nor `aria-label="Loading"`, so the accessibility fix cannot
silently revert.
- The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 5a7eae3 to 257f810CompareJuly 28, 2026 18:36
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 257f810 to 365949aCompareJuly 28, 2026 18:55
@mwolson
mwolson marked this pull request as ready for review July 28, 2026 18:55
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx Outdated
@macroscopeapp

macroscopeappBot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This range contains a 331-commit, 955-file orchestration V2 migration with new production workflows, persistence migrations, public API changes, authentication updates, and mobile/server integrations—not just the stated web work-log fix. Unresolved timeline rendering issues and the added product-default and static-analysis override changes add further review risk.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewJuly 28, 2026 19:18

Dismissing prior approval to re-evaluate 7d5e55c

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Jul 28, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
juliusmarmingeand others added 16 commits August 31, 2026 21:33
Retain pending admission after transient status failures and use one generation-owned retry worker. Ignore stale timers and duplicate evidence so older prompts cannot finish newer steering.
Finding: R14 status reconciliation
Model: GPT-5.6 Sol via Codex
Keep hidden local and inherited rows from consuming history pages. Preserve stop-request dependencies, source-run cutoffs, and imported history while loading related metadata from the selected cohort and using indexed watermark lookups.
Finding: P01 bounded history visibility
Model: GPT-5.6 Sol via Codex
Adapt grouped tool summaries and the floating working timer to V2 run, attempt, and queue state. Bring over the composer, keyboard, and disclosure transitions while retaining the V2 activity inspector and queue controls.
Keep OV2 web composer and grouping behavior intact; share only the existing command label parser with mobile.
Restores main features dropped by the policy replay: pingdotgg#8569 theme wiring,
pingdotgg#8850 composer banner follow-ups, pingdotgg#8855/pingdotgg#8904 composer fixes, pingdotgg#8831
settings search rework, pingdotgg#8803 workspace-mutation refresh (v2-adapted),
pingdotgg#8840 circle-alert, pingdotgg#8584 codex artifact templates, pingdotgg#8688/pingdotgg#8807/pingdotgg#8936
video + image previews (web and mobile, v2-adapted), pingdotgg#8862 Expo glass,
and the round's docs. Timeline thinking rows (pingdotgg#8984) stay on the v2
work-live system.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch from a6e0049 to 50a57b6CompareSeptember 1, 2026 05:36
juliusmarmingeand others added 3 commits September 1, 2026 00:24
The v2 equivalents of main's pingdotgg#8984 and pingdotgg#8922: a "Working for ..." header
anchors the active run, the trailing live tool row survives between
actions in past tense instead of vanishing, and a shimmering Thinking
row marks reasoning gaps. During workspace preparation the header shows
"Setting up worktree..." (driven by the local dispatch flag or the v2
run's preparing status, so remote viewers see it too), the composer
footer span is gone, and draft promotion waits until the run starts or
startup fails instead of navigating mid-preparation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 38109f8 to a9f243aCompareSeptember 1, 2026 23:26
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 1, 2026 23:26

Dismissing prior approval to re-evaluate a9f243a

if (
entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)

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.

🟡 Mediumchat/MessagesTimeline.logic.ts:783

A failed itemType: "error" with tone: "info" is rendered as a generic work-toggle instead of a work error row, so the provider error detail remains hidden and the expected provider-error-entry row never appears. deriveTurnFolds now leaves these entries visible, but the rendering branch only recognizes tone === "error"; update that branch to also recognize timelineEntryIsTerminalError.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/chat/MessagesTimeline.logic.ts around line 783:
A failed `itemType: "error"` with `tone: "info"` is rendered as a generic `work-toggle` instead of a `work` error row, so the provider error detail remains hidden and the expected `provider-error-entry` row never appears. `deriveTurnFolds` now leaves these entries visible, but the rendering branch only recognizes `tone === "error"`; update that branch to also recognize `timelineEntryIsTerminalError`.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two of these findings look like fallout from rebasing onto t3code/codex-turn-mapping: the collapsed work-log UI this PR's round-4 repair targets (a per-group visible cap and a "+N previous tool calls" expander) does not exist on this base, so the new selector, its constant, and the component tests written against it have nothing to attach to.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
Comment on lines +2505 to +2557
structuredPayload: { status: row.itemStatus } as OrchestrationV2TurnItem,
},
};
});

// Collapsed groups used to keep only slice(-1), so a later completed tool
// buried the running or stopped row the work-log filter retained.
it("keeps pinned running and stopped tools visible in a collapsed work group", () => {
const runningAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "running", label: "Active shell", itemStatus: "running" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(runningAndCompleted).toContain("Active shell");
expect(runningAndCompleted).toContain("Finished shell");
expect(runningAndCompleted).toContain("lucide-loader-circle");
expect(runningAndCompleted).not.toContain("previous tool");

const stoppedAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "stopped", label: "Interrupted shell", itemStatus: "interrupted" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(stoppedAndCompleted).toContain("Interrupted shell");
expect(stoppedAndCompleted).toContain("Finished shell");
expect(stoppedAndCompleted).toContain(', stopped"');
expect(stoppedAndCompleted).not.toContain("previous tool");
});

it("does not pin pending or waiting rows in a collapsed work group", () => {
const markup = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "pending", label: "Queued shell", itemStatus: "pending" },
{ id: "waiting", label: "Blocked shell", itemStatus: "waiting" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);

expect(markup).toContain("Finished shell");
expect(markup).not.toContain("Queued shell");
expect(markup).not.toContain("Blocked shell");
expect(markup).toContain("+2 previous tool calls");

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.

These collapsed-work-group cases assert against UI that does not exist on this target branch. Work groups render row.summary through WorkGroupToggleTimelineRow (e.g. Ran 2 commands), there is no +N previous tool calls expander string anywhere in MessagesTimeline.tsx, and no per-group visible cap that could hide Queued shell/Blocked shell — so both the pinned-row and the not-pinned expectations fail rather than guarding the fix.

Suggest retargeting them at the work-live/work-toggle row model (or removing them alongside the unused selectCollapsedWorkLogEntries) so the suite matches the shipped work-group rendering.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/ChatView.tsx

@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 2 potential issues.

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 a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Collapsed groups hide pinned tool rows

High Severity

selectCollapsedWorkLogEntries is never used when building or rendering work groups. Settled groups still emit only a work-toggle that hides every row, so running and stopped tools stay behind the summary instead of remaining visible in the compact log. The +N previous tool calls expander the new tests expect is also never rendered.

Additional Locations (2)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Failed errors stay behind work toggle

Medium Severity

deriveTurnFolds now keeps failed itemType === "error" entries out of the turn fold, but row emission still treats projected provider errors as ordinary work because their tone is info. They become a work-toggle labeled Provider error, so the failure detail stays hidden unless the group is expanded.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch 2 times, most recently from 6081201 to 95bacddCompareSeptember 2, 2026 07:19

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The selectCollapsedWorkLogEntries selector plus its collapsed-group tests, and the unused workingStepLabel / pendingBackgroundTasks props, are still in the state described in the earlier threads on MessagesTimeline.logic.ts:76, MessagesTimeline.test.tsx:2557, and MessagesTimeline.tsx:243MAX_VISIBLE_WORK_LOG_ENTRIES now type-checks, but nothing in MessagesTimeline.tsx calls the selector and the shipped work group still renders every visible entry with no per-group cap or expander. Not re-raising those inline.

Posted via Macroscope — UI Consistency

Comment on lines +2410 to +2411
const workRow = (itemStatus: OrchestrationV2TurnItem["status"] | undefined) => {
const toolLifecycleStatus = toolLifecycleStatusForItemStatus(itemStatus);

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.

These fixtures never reach SimpleWorkEntryRow, so the new lifecycle assertions do not exercise the indicators they describe. beforeEach resets activityTestState.expanded to false, and a tone: "tool" entry with a settled run (isWorking: false, latestRun: null) derives a collapsed work-toggle row (MessagesTimeline.logic.ts:1105), which renders only row.summary — no spinner and no lifecycle-suffixed aria-label. expect(markup).toContain("lucide-loader-circle") and toContain(', stopped"') therefore fail, while toContain("Ran command") passes only because that is also the group summary text.

The neighboring failed-marker case opts into the expanded path explicitly; suggest doing the same in this helper so the rows under test are the ones the PR changed:

Suggested change
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
activityTestState.expanded=true;
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);

Posted via Macroscope — UI Consistency

@macroscopeapp

Copy link
Copy Markdown
Contributor

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $248.57, which exceeds your per-review limit of $10.00.

The top 3 files driving up this estimate:

FileDiff SizeEstimate
apps/server/src/orchestration-v2/Orchestrator.ts277.03KB$13.85
apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts272.17KB$13.61
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts230.26KB$11.51

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ 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.

7 participants

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

fix(web): Keep running, stopped, and failed rows visible in the work log - #4762

Open
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows
Open

fix(web): Keep running, stopped, and failed rows visible in the work log#4762
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows

Conversation

@mwolson

@mwolsonmwolson commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What Changed

The web work log keeps the rows that tell you what a turn is doing. Running tools stay in the log with a spinner. Interrupted tools stay visible without a success check. Collapsed work logs still show an active or interrupted tool even when newer rows would have pushed it out.

When a provider fails and the turn has no assistant message, the failed error stays in the timeline instead of only the sidebar. Recovered retries still fold like ordinary work.

Why

The server already had the right items. The web timeline treated running and interrupted tools like noise. When a finished turn collapsed its work log, it kept a final assistant message but hid a failed error, so the error only showed in the sidebar.

This is web-only. Mobile does not share these filters.

UI Changes

Running and stopped tool rows remain visible, including in compact work logs. Failed provider errors remain visible on settled turns with no assistant message. Stopped tools have no extra glyph. The interrupt row still carries the stop marker.

No before/after screenshots. Checked on a Codex turn in the web app: a foreground command showed a spinner while running, and after Stop the row stayed without a spinner or success check. A live failed provider turn had the error folded away before this change.

Checklist

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

Note

Medium Risk
Large mobile thread/orchestration migration affects caching, runtime gating, and user-facing archive/stop behavior; removing the thread-transfer report workflow is low risk but changes PR observability for transfer regressions.

Overview
Removes the CI “thread transfer impact” PR comment pipeline by deleting thread-transfer-report.yml and the trusted publisher scripts/tests that validated artifacts and upserted comparison comments. Server test shards can still upload thread-transfer-results artifacts; nothing in this diff publishes them to PRs anymore.

Mobile is moved onto shared V2 orchestration client-runtime paths. SQLite shell/thread caches now encode/decode via StoredOrchestration* schemas and ORCHESTRATION_CACHE_SCHEMA_VERSION, with tests for DateTime round-trips. Connection wiring swaps in boundedThreadSnapshotLoaderLayer and threadHistoryControllerLayer. Thread UI and actions follow projection/runtime models (useSelectedThreadProjection, thread.runtime vs legacy session, RuntimeRequestId for approvals/user input with responseCapability gating). New or expanded UX includes thread queue control, relationships banner, activity inspector (files, rollback), visit watermark dispatch, and threadCanArchive rules that allow archive when queued work has no active provider run. Review/checkpoints derive from ThreadCheckpointSummary / deriveThreadCheckpointSummaries.

Smaller follow-ons: CI installs build-essential so ACP process-tree live tests always compile their pthread fixture; README links appearance docs; desktop exposes userDataDirName / legacy dir names in tests; marketing updates the Cursor harness label; mobile theme generator adds adaptive color tokens used by the new inspector surfaces.

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

Note

Keep running, stopped, and failed rows visible in the work log and build orchestration V2 foundation

  • Adds derivePendingBackgroundWork to derive a post-settlement pending-work roster from provider-thread tasks and nonterminal turn items, gating on latest-run settlement and excluding rolled-back items
  • Updates isOrchestrationV2TurnItemVisible to hide items from rolled-back runs, queued user messages from cancelled runs, and unpaired superseded interruption results
  • Adds T3 MCP tool presentation resolver with display labels and logos for known orchestration, delegation, scheduling, and worktree tools
  • Adds the full orchestration V2 server and client runtime: provider adapters for Claude, Codex, Cursor, Grok, and OpenCode; event store, projection store, command receipt store, effect outbox, checkpoint services, session manager, run execution, thread lifecycle, context handoff, scheduled tasks, and legacy V1 importer
  • Adds database migrations 044–052, V2 contracts, MCP orchestrator and worktree toolkits, bounded thread snapshot loading, web/mobile UI components for queue control, thread details, relationships, and activity inspection
  • Risk: migrations 044–052 create new tables and backfill columns from existing payloads; the IPC EnvironmentApi replaces the legacy orchestration property with orchestrationV2, removing turn-diff and archived-shell methods

Macroscope summarized 05f47ec.

@coderabbitai

coderabbitaiBot commented Jul 28, 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: d63aaf22-b302-4873-a096-e3875d635abe

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

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 size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 28, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
@mwolsonmwolson changed the title fix(web): Keep in-flight and stopped tool rows in the work logfix(orchestrator): Keep in-flight and stopped tool rows in the work logJul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from caf6f38 to d30b4a7CompareJuly 28, 2026 17:55
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
Also from that round:
- Tests pin "no stopped indicator" properly. A stopped row could have regressed
to the dash while every assertion still passed; there is now a negative
`lucide-minus` check, and the running case asserts the spinner carries neither
`role="status"` nor `aria-label="Loading"`, so the accessibility fix cannot
silently revert.
- The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 5a7eae3 to 257f810CompareJuly 28, 2026 18:36
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 257f810 to 365949aCompareJuly 28, 2026 18:55
@mwolson
mwolson marked this pull request as ready for review July 28, 2026 18:55
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx Outdated
@macroscopeapp

macroscopeappBot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This range contains a 331-commit, 955-file orchestration V2 migration with new production workflows, persistence migrations, public API changes, authentication updates, and mobile/server integrations—not just the stated web work-log fix. Unresolved timeline rendering issues and the added product-default and static-analysis override changes add further review risk.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewJuly 28, 2026 19:18

Dismissing prior approval to re-evaluate 7d5e55c

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Jul 28, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
juliusmarmingeand others added 16 commits August 31, 2026 21:33
Retain pending admission after transient status failures and use one generation-owned retry worker. Ignore stale timers and duplicate evidence so older prompts cannot finish newer steering.
Finding: R14 status reconciliation
Model: GPT-5.6 Sol via Codex
Keep hidden local and inherited rows from consuming history pages. Preserve stop-request dependencies, source-run cutoffs, and imported history while loading related metadata from the selected cohort and using indexed watermark lookups.
Finding: P01 bounded history visibility
Model: GPT-5.6 Sol via Codex
Adapt grouped tool summaries and the floating working timer to V2 run, attempt, and queue state. Bring over the composer, keyboard, and disclosure transitions while retaining the V2 activity inspector and queue controls.
Keep OV2 web composer and grouping behavior intact; share only the existing command label parser with mobile.
Restores main features dropped by the policy replay: pingdotgg#8569 theme wiring,
pingdotgg#8850 composer banner follow-ups, pingdotgg#8855/pingdotgg#8904 composer fixes, pingdotgg#8831
settings search rework, pingdotgg#8803 workspace-mutation refresh (v2-adapted),
pingdotgg#8840 circle-alert, pingdotgg#8584 codex artifact templates, pingdotgg#8688/pingdotgg#8807/pingdotgg#8936
video + image previews (web and mobile, v2-adapted), pingdotgg#8862 Expo glass,
and the round's docs. Timeline thinking rows (pingdotgg#8984) stay on the v2
work-live system.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch from a6e0049 to 50a57b6CompareSeptember 1, 2026 05:36
juliusmarmingeand others added 3 commits September 1, 2026 00:24
The v2 equivalents of main's pingdotgg#8984 and pingdotgg#8922: a "Working for ..." header
anchors the active run, the trailing live tool row survives between
actions in past tense instead of vanishing, and a shimmering Thinking
row marks reasoning gaps. During workspace preparation the header shows
"Setting up worktree..." (driven by the local dispatch flag or the v2
run's preparing status, so remote viewers see it too), the composer
footer span is gone, and draft promotion waits until the run starts or
startup fails instead of navigating mid-preparation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 38109f8 to a9f243aCompareSeptember 1, 2026 23:26
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 1, 2026 23:26

Dismissing prior approval to re-evaluate a9f243a

if (
entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)

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.

🟡 Mediumchat/MessagesTimeline.logic.ts:783

A failed itemType: "error" with tone: "info" is rendered as a generic work-toggle instead of a work error row, so the provider error detail remains hidden and the expected provider-error-entry row never appears. deriveTurnFolds now leaves these entries visible, but the rendering branch only recognizes tone === "error"; update that branch to also recognize timelineEntryIsTerminalError.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/chat/MessagesTimeline.logic.ts around line 783:
A failed `itemType: "error"` with `tone: "info"` is rendered as a generic `work-toggle` instead of a `work` error row, so the provider error detail remains hidden and the expected `provider-error-entry` row never appears. `deriveTurnFolds` now leaves these entries visible, but the rendering branch only recognizes `tone === "error"`; update that branch to also recognize `timelineEntryIsTerminalError`.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two of these findings look like fallout from rebasing onto t3code/codex-turn-mapping: the collapsed work-log UI this PR's round-4 repair targets (a per-group visible cap and a "+N previous tool calls" expander) does not exist on this base, so the new selector, its constant, and the component tests written against it have nothing to attach to.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
Comment on lines +2505 to +2557
structuredPayload: { status: row.itemStatus } as OrchestrationV2TurnItem,
},
};
});

// Collapsed groups used to keep only slice(-1), so a later completed tool
// buried the running or stopped row the work-log filter retained.
it("keeps pinned running and stopped tools visible in a collapsed work group", () => {
const runningAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "running", label: "Active shell", itemStatus: "running" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(runningAndCompleted).toContain("Active shell");
expect(runningAndCompleted).toContain("Finished shell");
expect(runningAndCompleted).toContain("lucide-loader-circle");
expect(runningAndCompleted).not.toContain("previous tool");

const stoppedAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "stopped", label: "Interrupted shell", itemStatus: "interrupted" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(stoppedAndCompleted).toContain("Interrupted shell");
expect(stoppedAndCompleted).toContain("Finished shell");
expect(stoppedAndCompleted).toContain(', stopped"');
expect(stoppedAndCompleted).not.toContain("previous tool");
});

it("does not pin pending or waiting rows in a collapsed work group", () => {
const markup = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "pending", label: "Queued shell", itemStatus: "pending" },
{ id: "waiting", label: "Blocked shell", itemStatus: "waiting" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);

expect(markup).toContain("Finished shell");
expect(markup).not.toContain("Queued shell");
expect(markup).not.toContain("Blocked shell");
expect(markup).toContain("+2 previous tool calls");

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.

These collapsed-work-group cases assert against UI that does not exist on this target branch. Work groups render row.summary through WorkGroupToggleTimelineRow (e.g. Ran 2 commands), there is no +N previous tool calls expander string anywhere in MessagesTimeline.tsx, and no per-group visible cap that could hide Queued shell/Blocked shell — so both the pinned-row and the not-pinned expectations fail rather than guarding the fix.

Suggest retargeting them at the work-live/work-toggle row model (or removing them alongside the unused selectCollapsedWorkLogEntries) so the suite matches the shipped work-group rendering.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/ChatView.tsx

@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 2 potential issues.

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 a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Collapsed groups hide pinned tool rows

High Severity

selectCollapsedWorkLogEntries is never used when building or rendering work groups. Settled groups still emit only a work-toggle that hides every row, so running and stopped tools stay behind the summary instead of remaining visible in the compact log. The +N previous tool calls expander the new tests expect is also never rendered.

Additional Locations (2)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Failed errors stay behind work toggle

Medium Severity

deriveTurnFolds now keeps failed itemType === "error" entries out of the turn fold, but row emission still treats projected provider errors as ordinary work because their tone is info. They become a work-toggle labeled Provider error, so the failure detail stays hidden unless the group is expanded.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch 2 times, most recently from 6081201 to 95bacddCompareSeptember 2, 2026 07:19

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The selectCollapsedWorkLogEntries selector plus its collapsed-group tests, and the unused workingStepLabel / pendingBackgroundTasks props, are still in the state described in the earlier threads on MessagesTimeline.logic.ts:76, MessagesTimeline.test.tsx:2557, and MessagesTimeline.tsx:243MAX_VISIBLE_WORK_LOG_ENTRIES now type-checks, but nothing in MessagesTimeline.tsx calls the selector and the shipped work group still renders every visible entry with no per-group cap or expander. Not re-raising those inline.

Posted via Macroscope — UI Consistency

Comment on lines +2410 to +2411
const workRow = (itemStatus: OrchestrationV2TurnItem["status"] | undefined) => {
const toolLifecycleStatus = toolLifecycleStatusForItemStatus(itemStatus);

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.

These fixtures never reach SimpleWorkEntryRow, so the new lifecycle assertions do not exercise the indicators they describe. beforeEach resets activityTestState.expanded to false, and a tone: "tool" entry with a settled run (isWorking: false, latestRun: null) derives a collapsed work-toggle row (MessagesTimeline.logic.ts:1105), which renders only row.summary — no spinner and no lifecycle-suffixed aria-label. expect(markup).toContain("lucide-loader-circle") and toContain(', stopped"') therefore fail, while toContain("Ran command") passes only because that is also the group summary text.

The neighboring failed-marker case opts into the expanded path explicitly; suggest doing the same in this helper so the rows under test are the ones the PR changed:

Suggested change
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
activityTestState.expanded=true;
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);

Posted via Macroscope — UI Consistency

@macroscopeapp

Copy link
Copy Markdown
Contributor

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $248.57, which exceeds your per-review limit of $10.00.

The top 3 files driving up this estimate:

FileDiff SizeEstimate
apps/server/src/orchestration-v2/Orchestrator.ts277.03KB$13.85
apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts272.17KB$13.61
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts230.26KB$11.51

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ 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.

7 participants

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

fix(web): Keep running, stopped, and failed rows visible in the work log - #4762

Open
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows
Open

fix(web): Keep running, stopped, and failed rows visible in the work log#4762
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows

Conversation

@mwolson

@mwolsonmwolson commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What Changed

The web work log keeps the rows that tell you what a turn is doing. Running tools stay in the log with a spinner. Interrupted tools stay visible without a success check. Collapsed work logs still show an active or interrupted tool even when newer rows would have pushed it out.

When a provider fails and the turn has no assistant message, the failed error stays in the timeline instead of only the sidebar. Recovered retries still fold like ordinary work.

Why

The server already had the right items. The web timeline treated running and interrupted tools like noise. When a finished turn collapsed its work log, it kept a final assistant message but hid a failed error, so the error only showed in the sidebar.

This is web-only. Mobile does not share these filters.

UI Changes

Running and stopped tool rows remain visible, including in compact work logs. Failed provider errors remain visible on settled turns with no assistant message. Stopped tools have no extra glyph. The interrupt row still carries the stop marker.

No before/after screenshots. Checked on a Codex turn in the web app: a foreground command showed a spinner while running, and after Stop the row stayed without a spinner or success check. A live failed provider turn had the error folded away before this change.

Checklist

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

Note

Medium Risk
Large mobile thread/orchestration migration affects caching, runtime gating, and user-facing archive/stop behavior; removing the thread-transfer report workflow is low risk but changes PR observability for transfer regressions.

Overview
Removes the CI “thread transfer impact” PR comment pipeline by deleting thread-transfer-report.yml and the trusted publisher scripts/tests that validated artifacts and upserted comparison comments. Server test shards can still upload thread-transfer-results artifacts; nothing in this diff publishes them to PRs anymore.

Mobile is moved onto shared V2 orchestration client-runtime paths. SQLite shell/thread caches now encode/decode via StoredOrchestration* schemas and ORCHESTRATION_CACHE_SCHEMA_VERSION, with tests for DateTime round-trips. Connection wiring swaps in boundedThreadSnapshotLoaderLayer and threadHistoryControllerLayer. Thread UI and actions follow projection/runtime models (useSelectedThreadProjection, thread.runtime vs legacy session, RuntimeRequestId for approvals/user input with responseCapability gating). New or expanded UX includes thread queue control, relationships banner, activity inspector (files, rollback), visit watermark dispatch, and threadCanArchive rules that allow archive when queued work has no active provider run. Review/checkpoints derive from ThreadCheckpointSummary / deriveThreadCheckpointSummaries.

Smaller follow-ons: CI installs build-essential so ACP process-tree live tests always compile their pthread fixture; README links appearance docs; desktop exposes userDataDirName / legacy dir names in tests; marketing updates the Cursor harness label; mobile theme generator adds adaptive color tokens used by the new inspector surfaces.

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

Note

Keep running, stopped, and failed rows visible in the work log and build orchestration V2 foundation

  • Adds derivePendingBackgroundWork to derive a post-settlement pending-work roster from provider-thread tasks and nonterminal turn items, gating on latest-run settlement and excluding rolled-back items
  • Updates isOrchestrationV2TurnItemVisible to hide items from rolled-back runs, queued user messages from cancelled runs, and unpaired superseded interruption results
  • Adds T3 MCP tool presentation resolver with display labels and logos for known orchestration, delegation, scheduling, and worktree tools
  • Adds the full orchestration V2 server and client runtime: provider adapters for Claude, Codex, Cursor, Grok, and OpenCode; event store, projection store, command receipt store, effect outbox, checkpoint services, session manager, run execution, thread lifecycle, context handoff, scheduled tasks, and legacy V1 importer
  • Adds database migrations 044–052, V2 contracts, MCP orchestrator and worktree toolkits, bounded thread snapshot loading, web/mobile UI components for queue control, thread details, relationships, and activity inspection
  • Risk: migrations 044–052 create new tables and backfill columns from existing payloads; the IPC EnvironmentApi replaces the legacy orchestration property with orchestrationV2, removing turn-diff and archived-shell methods

Macroscope summarized 05f47ec.

@coderabbitai

coderabbitaiBot commented Jul 28, 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: d63aaf22-b302-4873-a096-e3875d635abe

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

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 size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 28, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
@mwolsonmwolson changed the title fix(web): Keep in-flight and stopped tool rows in the work logfix(orchestrator): Keep in-flight and stopped tool rows in the work logJul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from caf6f38 to d30b4a7CompareJuly 28, 2026 17:55
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
Also from that round:
- Tests pin "no stopped indicator" properly. A stopped row could have regressed
to the dash while every assertion still passed; there is now a negative
`lucide-minus` check, and the running case asserts the spinner carries neither
`role="status"` nor `aria-label="Loading"`, so the accessibility fix cannot
silently revert.
- The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 5a7eae3 to 257f810CompareJuly 28, 2026 18:36
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 257f810 to 365949aCompareJuly 28, 2026 18:55
@mwolson
mwolson marked this pull request as ready for review July 28, 2026 18:55
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx Outdated
@macroscopeapp

macroscopeappBot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This range contains a 331-commit, 955-file orchestration V2 migration with new production workflows, persistence migrations, public API changes, authentication updates, and mobile/server integrations—not just the stated web work-log fix. Unresolved timeline rendering issues and the added product-default and static-analysis override changes add further review risk.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewJuly 28, 2026 19:18

Dismissing prior approval to re-evaluate 7d5e55c

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Jul 28, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
juliusmarmingeand others added 16 commits August 31, 2026 21:33
Retain pending admission after transient status failures and use one generation-owned retry worker. Ignore stale timers and duplicate evidence so older prompts cannot finish newer steering.
Finding: R14 status reconciliation
Model: GPT-5.6 Sol via Codex
Keep hidden local and inherited rows from consuming history pages. Preserve stop-request dependencies, source-run cutoffs, and imported history while loading related metadata from the selected cohort and using indexed watermark lookups.
Finding: P01 bounded history visibility
Model: GPT-5.6 Sol via Codex
Adapt grouped tool summaries and the floating working timer to V2 run, attempt, and queue state. Bring over the composer, keyboard, and disclosure transitions while retaining the V2 activity inspector and queue controls.
Keep OV2 web composer and grouping behavior intact; share only the existing command label parser with mobile.
Restores main features dropped by the policy replay: pingdotgg#8569 theme wiring,
pingdotgg#8850 composer banner follow-ups, pingdotgg#8855/pingdotgg#8904 composer fixes, pingdotgg#8831
settings search rework, pingdotgg#8803 workspace-mutation refresh (v2-adapted),
pingdotgg#8840 circle-alert, pingdotgg#8584 codex artifact templates, pingdotgg#8688/pingdotgg#8807/pingdotgg#8936
video + image previews (web and mobile, v2-adapted), pingdotgg#8862 Expo glass,
and the round's docs. Timeline thinking rows (pingdotgg#8984) stay on the v2
work-live system.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch from a6e0049 to 50a57b6CompareSeptember 1, 2026 05:36
juliusmarmingeand others added 3 commits September 1, 2026 00:24
The v2 equivalents of main's pingdotgg#8984 and pingdotgg#8922: a "Working for ..." header
anchors the active run, the trailing live tool row survives between
actions in past tense instead of vanishing, and a shimmering Thinking
row marks reasoning gaps. During workspace preparation the header shows
"Setting up worktree..." (driven by the local dispatch flag or the v2
run's preparing status, so remote viewers see it too), the composer
footer span is gone, and draft promotion waits until the run starts or
startup fails instead of navigating mid-preparation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 38109f8 to a9f243aCompareSeptember 1, 2026 23:26
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 1, 2026 23:26

Dismissing prior approval to re-evaluate a9f243a

if (
entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)

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.

🟡 Mediumchat/MessagesTimeline.logic.ts:783

A failed itemType: "error" with tone: "info" is rendered as a generic work-toggle instead of a work error row, so the provider error detail remains hidden and the expected provider-error-entry row never appears. deriveTurnFolds now leaves these entries visible, but the rendering branch only recognizes tone === "error"; update that branch to also recognize timelineEntryIsTerminalError.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/chat/MessagesTimeline.logic.ts around line 783:
A failed `itemType: "error"` with `tone: "info"` is rendered as a generic `work-toggle` instead of a `work` error row, so the provider error detail remains hidden and the expected `provider-error-entry` row never appears. `deriveTurnFolds` now leaves these entries visible, but the rendering branch only recognizes `tone === "error"`; update that branch to also recognize `timelineEntryIsTerminalError`.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two of these findings look like fallout from rebasing onto t3code/codex-turn-mapping: the collapsed work-log UI this PR's round-4 repair targets (a per-group visible cap and a "+N previous tool calls" expander) does not exist on this base, so the new selector, its constant, and the component tests written against it have nothing to attach to.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
Comment on lines +2505 to +2557
structuredPayload: { status: row.itemStatus } as OrchestrationV2TurnItem,
},
};
});

// Collapsed groups used to keep only slice(-1), so a later completed tool
// buried the running or stopped row the work-log filter retained.
it("keeps pinned running and stopped tools visible in a collapsed work group", () => {
const runningAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "running", label: "Active shell", itemStatus: "running" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(runningAndCompleted).toContain("Active shell");
expect(runningAndCompleted).toContain("Finished shell");
expect(runningAndCompleted).toContain("lucide-loader-circle");
expect(runningAndCompleted).not.toContain("previous tool");

const stoppedAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "stopped", label: "Interrupted shell", itemStatus: "interrupted" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(stoppedAndCompleted).toContain("Interrupted shell");
expect(stoppedAndCompleted).toContain("Finished shell");
expect(stoppedAndCompleted).toContain(', stopped"');
expect(stoppedAndCompleted).not.toContain("previous tool");
});

it("does not pin pending or waiting rows in a collapsed work group", () => {
const markup = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "pending", label: "Queued shell", itemStatus: "pending" },
{ id: "waiting", label: "Blocked shell", itemStatus: "waiting" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);

expect(markup).toContain("Finished shell");
expect(markup).not.toContain("Queued shell");
expect(markup).not.toContain("Blocked shell");
expect(markup).toContain("+2 previous tool calls");

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.

These collapsed-work-group cases assert against UI that does not exist on this target branch. Work groups render row.summary through WorkGroupToggleTimelineRow (e.g. Ran 2 commands), there is no +N previous tool calls expander string anywhere in MessagesTimeline.tsx, and no per-group visible cap that could hide Queued shell/Blocked shell — so both the pinned-row and the not-pinned expectations fail rather than guarding the fix.

Suggest retargeting them at the work-live/work-toggle row model (or removing them alongside the unused selectCollapsedWorkLogEntries) so the suite matches the shipped work-group rendering.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/ChatView.tsx

@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 2 potential issues.

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 a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Collapsed groups hide pinned tool rows

High Severity

selectCollapsedWorkLogEntries is never used when building or rendering work groups. Settled groups still emit only a work-toggle that hides every row, so running and stopped tools stay behind the summary instead of remaining visible in the compact log. The +N previous tool calls expander the new tests expect is also never rendered.

Additional Locations (2)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Failed errors stay behind work toggle

Medium Severity

deriveTurnFolds now keeps failed itemType === "error" entries out of the turn fold, but row emission still treats projected provider errors as ordinary work because their tone is info. They become a work-toggle labeled Provider error, so the failure detail stays hidden unless the group is expanded.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch 2 times, most recently from 6081201 to 95bacddCompareSeptember 2, 2026 07:19

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The selectCollapsedWorkLogEntries selector plus its collapsed-group tests, and the unused workingStepLabel / pendingBackgroundTasks props, are still in the state described in the earlier threads on MessagesTimeline.logic.ts:76, MessagesTimeline.test.tsx:2557, and MessagesTimeline.tsx:243MAX_VISIBLE_WORK_LOG_ENTRIES now type-checks, but nothing in MessagesTimeline.tsx calls the selector and the shipped work group still renders every visible entry with no per-group cap or expander. Not re-raising those inline.

Posted via Macroscope — UI Consistency

Comment on lines +2410 to +2411
const workRow = (itemStatus: OrchestrationV2TurnItem["status"] | undefined) => {
const toolLifecycleStatus = toolLifecycleStatusForItemStatus(itemStatus);

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.

These fixtures never reach SimpleWorkEntryRow, so the new lifecycle assertions do not exercise the indicators they describe. beforeEach resets activityTestState.expanded to false, and a tone: "tool" entry with a settled run (isWorking: false, latestRun: null) derives a collapsed work-toggle row (MessagesTimeline.logic.ts:1105), which renders only row.summary — no spinner and no lifecycle-suffixed aria-label. expect(markup).toContain("lucide-loader-circle") and toContain(', stopped"') therefore fail, while toContain("Ran command") passes only because that is also the group summary text.

The neighboring failed-marker case opts into the expanded path explicitly; suggest doing the same in this helper so the rows under test are the ones the PR changed:

Suggested change
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
activityTestState.expanded=true;
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);

Posted via Macroscope — UI Consistency

@macroscopeapp

Copy link
Copy Markdown
Contributor

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $248.57, which exceeds your per-review limit of $10.00.

The top 3 files driving up this estimate:

FileDiff SizeEstimate
apps/server/src/orchestration-v2/Orchestrator.ts277.03KB$13.85
apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts272.17KB$13.61
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts230.26KB$11.51

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ 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.

7 participants

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

fix(web): Keep running, stopped, and failed rows visible in the work log - #4762

Open
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows
Open

fix(web): Keep running, stopped, and failed rows visible in the work log#4762
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows

Conversation

@mwolson

@mwolsonmwolson commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What Changed

The web work log keeps the rows that tell you what a turn is doing. Running tools stay in the log with a spinner. Interrupted tools stay visible without a success check. Collapsed work logs still show an active or interrupted tool even when newer rows would have pushed it out.

When a provider fails and the turn has no assistant message, the failed error stays in the timeline instead of only the sidebar. Recovered retries still fold like ordinary work.

Why

The server already had the right items. The web timeline treated running and interrupted tools like noise. When a finished turn collapsed its work log, it kept a final assistant message but hid a failed error, so the error only showed in the sidebar.

This is web-only. Mobile does not share these filters.

UI Changes

Running and stopped tool rows remain visible, including in compact work logs. Failed provider errors remain visible on settled turns with no assistant message. Stopped tools have no extra glyph. The interrupt row still carries the stop marker.

No before/after screenshots. Checked on a Codex turn in the web app: a foreground command showed a spinner while running, and after Stop the row stayed without a spinner or success check. A live failed provider turn had the error folded away before this change.

Checklist

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

Note

Medium Risk
Large mobile thread/orchestration migration affects caching, runtime gating, and user-facing archive/stop behavior; removing the thread-transfer report workflow is low risk but changes PR observability for transfer regressions.

Overview
Removes the CI “thread transfer impact” PR comment pipeline by deleting thread-transfer-report.yml and the trusted publisher scripts/tests that validated artifacts and upserted comparison comments. Server test shards can still upload thread-transfer-results artifacts; nothing in this diff publishes them to PRs anymore.

Mobile is moved onto shared V2 orchestration client-runtime paths. SQLite shell/thread caches now encode/decode via StoredOrchestration* schemas and ORCHESTRATION_CACHE_SCHEMA_VERSION, with tests for DateTime round-trips. Connection wiring swaps in boundedThreadSnapshotLoaderLayer and threadHistoryControllerLayer. Thread UI and actions follow projection/runtime models (useSelectedThreadProjection, thread.runtime vs legacy session, RuntimeRequestId for approvals/user input with responseCapability gating). New or expanded UX includes thread queue control, relationships banner, activity inspector (files, rollback), visit watermark dispatch, and threadCanArchive rules that allow archive when queued work has no active provider run. Review/checkpoints derive from ThreadCheckpointSummary / deriveThreadCheckpointSummaries.

Smaller follow-ons: CI installs build-essential so ACP process-tree live tests always compile their pthread fixture; README links appearance docs; desktop exposes userDataDirName / legacy dir names in tests; marketing updates the Cursor harness label; mobile theme generator adds adaptive color tokens used by the new inspector surfaces.

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

Note

Keep running, stopped, and failed rows visible in the work log and build orchestration V2 foundation

  • Adds derivePendingBackgroundWork to derive a post-settlement pending-work roster from provider-thread tasks and nonterminal turn items, gating on latest-run settlement and excluding rolled-back items
  • Updates isOrchestrationV2TurnItemVisible to hide items from rolled-back runs, queued user messages from cancelled runs, and unpaired superseded interruption results
  • Adds T3 MCP tool presentation resolver with display labels and logos for known orchestration, delegation, scheduling, and worktree tools
  • Adds the full orchestration V2 server and client runtime: provider adapters for Claude, Codex, Cursor, Grok, and OpenCode; event store, projection store, command receipt store, effect outbox, checkpoint services, session manager, run execution, thread lifecycle, context handoff, scheduled tasks, and legacy V1 importer
  • Adds database migrations 044–052, V2 contracts, MCP orchestrator and worktree toolkits, bounded thread snapshot loading, web/mobile UI components for queue control, thread details, relationships, and activity inspection
  • Risk: migrations 044–052 create new tables and backfill columns from existing payloads; the IPC EnvironmentApi replaces the legacy orchestration property with orchestrationV2, removing turn-diff and archived-shell methods

Macroscope summarized 05f47ec.

@coderabbitai

coderabbitaiBot commented Jul 28, 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: d63aaf22-b302-4873-a096-e3875d635abe

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

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 size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 28, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
@mwolsonmwolson changed the title fix(web): Keep in-flight and stopped tool rows in the work logfix(orchestrator): Keep in-flight and stopped tool rows in the work logJul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from caf6f38 to d30b4a7CompareJuly 28, 2026 17:55
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
Also from that round:
- Tests pin "no stopped indicator" properly. A stopped row could have regressed
to the dash while every assertion still passed; there is now a negative
`lucide-minus` check, and the running case asserts the spinner carries neither
`role="status"` nor `aria-label="Loading"`, so the accessibility fix cannot
silently revert.
- The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 5a7eae3 to 257f810CompareJuly 28, 2026 18:36
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 257f810 to 365949aCompareJuly 28, 2026 18:55
@mwolson
mwolson marked this pull request as ready for review July 28, 2026 18:55
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx Outdated
@macroscopeapp

macroscopeappBot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This range contains a 331-commit, 955-file orchestration V2 migration with new production workflows, persistence migrations, public API changes, authentication updates, and mobile/server integrations—not just the stated web work-log fix. Unresolved timeline rendering issues and the added product-default and static-analysis override changes add further review risk.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewJuly 28, 2026 19:18

Dismissing prior approval to re-evaluate 7d5e55c

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Jul 28, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
juliusmarmingeand others added 16 commits August 31, 2026 21:33
Retain pending admission after transient status failures and use one generation-owned retry worker. Ignore stale timers and duplicate evidence so older prompts cannot finish newer steering.
Finding: R14 status reconciliation
Model: GPT-5.6 Sol via Codex
Keep hidden local and inherited rows from consuming history pages. Preserve stop-request dependencies, source-run cutoffs, and imported history while loading related metadata from the selected cohort and using indexed watermark lookups.
Finding: P01 bounded history visibility
Model: GPT-5.6 Sol via Codex
Adapt grouped tool summaries and the floating working timer to V2 run, attempt, and queue state. Bring over the composer, keyboard, and disclosure transitions while retaining the V2 activity inspector and queue controls.
Keep OV2 web composer and grouping behavior intact; share only the existing command label parser with mobile.
Restores main features dropped by the policy replay: pingdotgg#8569 theme wiring,
pingdotgg#8850 composer banner follow-ups, pingdotgg#8855/pingdotgg#8904 composer fixes, pingdotgg#8831
settings search rework, pingdotgg#8803 workspace-mutation refresh (v2-adapted),
pingdotgg#8840 circle-alert, pingdotgg#8584 codex artifact templates, pingdotgg#8688/pingdotgg#8807/pingdotgg#8936
video + image previews (web and mobile, v2-adapted), pingdotgg#8862 Expo glass,
and the round's docs. Timeline thinking rows (pingdotgg#8984) stay on the v2
work-live system.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch from a6e0049 to 50a57b6CompareSeptember 1, 2026 05:36
juliusmarmingeand others added 3 commits September 1, 2026 00:24
The v2 equivalents of main's pingdotgg#8984 and pingdotgg#8922: a "Working for ..." header
anchors the active run, the trailing live tool row survives between
actions in past tense instead of vanishing, and a shimmering Thinking
row marks reasoning gaps. During workspace preparation the header shows
"Setting up worktree..." (driven by the local dispatch flag or the v2
run's preparing status, so remote viewers see it too), the composer
footer span is gone, and draft promotion waits until the run starts or
startup fails instead of navigating mid-preparation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 38109f8 to a9f243aCompareSeptember 1, 2026 23:26
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 1, 2026 23:26

Dismissing prior approval to re-evaluate a9f243a

if (
entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)

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.

🟡 Mediumchat/MessagesTimeline.logic.ts:783

A failed itemType: "error" with tone: "info" is rendered as a generic work-toggle instead of a work error row, so the provider error detail remains hidden and the expected provider-error-entry row never appears. deriveTurnFolds now leaves these entries visible, but the rendering branch only recognizes tone === "error"; update that branch to also recognize timelineEntryIsTerminalError.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/chat/MessagesTimeline.logic.ts around line 783:
A failed `itemType: "error"` with `tone: "info"` is rendered as a generic `work-toggle` instead of a `work` error row, so the provider error detail remains hidden and the expected `provider-error-entry` row never appears. `deriveTurnFolds` now leaves these entries visible, but the rendering branch only recognizes `tone === "error"`; update that branch to also recognize `timelineEntryIsTerminalError`.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two of these findings look like fallout from rebasing onto t3code/codex-turn-mapping: the collapsed work-log UI this PR's round-4 repair targets (a per-group visible cap and a "+N previous tool calls" expander) does not exist on this base, so the new selector, its constant, and the component tests written against it have nothing to attach to.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
Comment on lines +2505 to +2557
structuredPayload: { status: row.itemStatus } as OrchestrationV2TurnItem,
},
};
});

// Collapsed groups used to keep only slice(-1), so a later completed tool
// buried the running or stopped row the work-log filter retained.
it("keeps pinned running and stopped tools visible in a collapsed work group", () => {
const runningAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "running", label: "Active shell", itemStatus: "running" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(runningAndCompleted).toContain("Active shell");
expect(runningAndCompleted).toContain("Finished shell");
expect(runningAndCompleted).toContain("lucide-loader-circle");
expect(runningAndCompleted).not.toContain("previous tool");

const stoppedAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "stopped", label: "Interrupted shell", itemStatus: "interrupted" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(stoppedAndCompleted).toContain("Interrupted shell");
expect(stoppedAndCompleted).toContain("Finished shell");
expect(stoppedAndCompleted).toContain(', stopped"');
expect(stoppedAndCompleted).not.toContain("previous tool");
});

it("does not pin pending or waiting rows in a collapsed work group", () => {
const markup = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "pending", label: "Queued shell", itemStatus: "pending" },
{ id: "waiting", label: "Blocked shell", itemStatus: "waiting" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);

expect(markup).toContain("Finished shell");
expect(markup).not.toContain("Queued shell");
expect(markup).not.toContain("Blocked shell");
expect(markup).toContain("+2 previous tool calls");

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.

These collapsed-work-group cases assert against UI that does not exist on this target branch. Work groups render row.summary through WorkGroupToggleTimelineRow (e.g. Ran 2 commands), there is no +N previous tool calls expander string anywhere in MessagesTimeline.tsx, and no per-group visible cap that could hide Queued shell/Blocked shell — so both the pinned-row and the not-pinned expectations fail rather than guarding the fix.

Suggest retargeting them at the work-live/work-toggle row model (or removing them alongside the unused selectCollapsedWorkLogEntries) so the suite matches the shipped work-group rendering.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/ChatView.tsx

@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 2 potential issues.

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 a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Collapsed groups hide pinned tool rows

High Severity

selectCollapsedWorkLogEntries is never used when building or rendering work groups. Settled groups still emit only a work-toggle that hides every row, so running and stopped tools stay behind the summary instead of remaining visible in the compact log. The +N previous tool calls expander the new tests expect is also never rendered.

Additional Locations (2)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Failed errors stay behind work toggle

Medium Severity

deriveTurnFolds now keeps failed itemType === "error" entries out of the turn fold, but row emission still treats projected provider errors as ordinary work because their tone is info. They become a work-toggle labeled Provider error, so the failure detail stays hidden unless the group is expanded.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch 2 times, most recently from 6081201 to 95bacddCompareSeptember 2, 2026 07:19

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The selectCollapsedWorkLogEntries selector plus its collapsed-group tests, and the unused workingStepLabel / pendingBackgroundTasks props, are still in the state described in the earlier threads on MessagesTimeline.logic.ts:76, MessagesTimeline.test.tsx:2557, and MessagesTimeline.tsx:243MAX_VISIBLE_WORK_LOG_ENTRIES now type-checks, but nothing in MessagesTimeline.tsx calls the selector and the shipped work group still renders every visible entry with no per-group cap or expander. Not re-raising those inline.

Posted via Macroscope — UI Consistency

Comment on lines +2410 to +2411
const workRow = (itemStatus: OrchestrationV2TurnItem["status"] | undefined) => {
const toolLifecycleStatus = toolLifecycleStatusForItemStatus(itemStatus);

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.

These fixtures never reach SimpleWorkEntryRow, so the new lifecycle assertions do not exercise the indicators they describe. beforeEach resets activityTestState.expanded to false, and a tone: "tool" entry with a settled run (isWorking: false, latestRun: null) derives a collapsed work-toggle row (MessagesTimeline.logic.ts:1105), which renders only row.summary — no spinner and no lifecycle-suffixed aria-label. expect(markup).toContain("lucide-loader-circle") and toContain(', stopped"') therefore fail, while toContain("Ran command") passes only because that is also the group summary text.

The neighboring failed-marker case opts into the expanded path explicitly; suggest doing the same in this helper so the rows under test are the ones the PR changed:

Suggested change
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
activityTestState.expanded=true;
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);

Posted via Macroscope — UI Consistency

@macroscopeapp

Copy link
Copy Markdown
Contributor

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $248.57, which exceeds your per-review limit of $10.00.

The top 3 files driving up this estimate:

FileDiff SizeEstimate
apps/server/src/orchestration-v2/Orchestrator.ts277.03KB$13.85
apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts272.17KB$13.61
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts230.26KB$11.51

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ 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.

7 participants

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

fix(web): Keep running, stopped, and failed rows visible in the work log - #4762

Open
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows
Open

fix(web): Keep running, stopped, and failed rows visible in the work log#4762
mwolson wants to merge 331 commits into
pingdotgg:t3code/codex-turn-mappingfrom
mwolson:fix/web-timeline-inflight-tool-rows

Conversation

@mwolson

@mwolsonmwolson commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What Changed

The web work log keeps the rows that tell you what a turn is doing. Running tools stay in the log with a spinner. Interrupted tools stay visible without a success check. Collapsed work logs still show an active or interrupted tool even when newer rows would have pushed it out.

When a provider fails and the turn has no assistant message, the failed error stays in the timeline instead of only the sidebar. Recovered retries still fold like ordinary work.

Why

The server already had the right items. The web timeline treated running and interrupted tools like noise. When a finished turn collapsed its work log, it kept a final assistant message but hid a failed error, so the error only showed in the sidebar.

This is web-only. Mobile does not share these filters.

UI Changes

Running and stopped tool rows remain visible, including in compact work logs. Failed provider errors remain visible on settled turns with no assistant message. Stopped tools have no extra glyph. The interrupt row still carries the stop marker.

No before/after screenshots. Checked on a Codex turn in the web app: a foreground command showed a spinner while running, and after Stop the row stayed without a spinner or success check. A live failed provider turn had the error folded away before this change.

Checklist

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

Note

Medium Risk
Large mobile thread/orchestration migration affects caching, runtime gating, and user-facing archive/stop behavior; removing the thread-transfer report workflow is low risk but changes PR observability for transfer regressions.

Overview
Removes the CI “thread transfer impact” PR comment pipeline by deleting thread-transfer-report.yml and the trusted publisher scripts/tests that validated artifacts and upserted comparison comments. Server test shards can still upload thread-transfer-results artifacts; nothing in this diff publishes them to PRs anymore.

Mobile is moved onto shared V2 orchestration client-runtime paths. SQLite shell/thread caches now encode/decode via StoredOrchestration* schemas and ORCHESTRATION_CACHE_SCHEMA_VERSION, with tests for DateTime round-trips. Connection wiring swaps in boundedThreadSnapshotLoaderLayer and threadHistoryControllerLayer. Thread UI and actions follow projection/runtime models (useSelectedThreadProjection, thread.runtime vs legacy session, RuntimeRequestId for approvals/user input with responseCapability gating). New or expanded UX includes thread queue control, relationships banner, activity inspector (files, rollback), visit watermark dispatch, and threadCanArchive rules that allow archive when queued work has no active provider run. Review/checkpoints derive from ThreadCheckpointSummary / deriveThreadCheckpointSummaries.

Smaller follow-ons: CI installs build-essential so ACP process-tree live tests always compile their pthread fixture; README links appearance docs; desktop exposes userDataDirName / legacy dir names in tests; marketing updates the Cursor harness label; mobile theme generator adds adaptive color tokens used by the new inspector surfaces.

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

Note

Keep running, stopped, and failed rows visible in the work log and build orchestration V2 foundation

  • Adds derivePendingBackgroundWork to derive a post-settlement pending-work roster from provider-thread tasks and nonterminal turn items, gating on latest-run settlement and excluding rolled-back items
  • Updates isOrchestrationV2TurnItemVisible to hide items from rolled-back runs, queued user messages from cancelled runs, and unpaired superseded interruption results
  • Adds T3 MCP tool presentation resolver with display labels and logos for known orchestration, delegation, scheduling, and worktree tools
  • Adds the full orchestration V2 server and client runtime: provider adapters for Claude, Codex, Cursor, Grok, and OpenCode; event store, projection store, command receipt store, effect outbox, checkpoint services, session manager, run execution, thread lifecycle, context handoff, scheduled tasks, and legacy V1 importer
  • Adds database migrations 044–052, V2 contracts, MCP orchestrator and worktree toolkits, bounded thread snapshot loading, web/mobile UI components for queue control, thread details, relationships, and activity inspection
  • Risk: migrations 044–052 create new tables and backfill columns from existing payloads; the IPC EnvironmentApi replaces the legacy orchestration property with orchestrationV2, removing turn-diff and archived-shell methods

Macroscope summarized 05f47ec.

@coderabbitai

coderabbitaiBot commented Jul 28, 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: d63aaf22-b302-4873-a096-e3875d635abe

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

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 size:S 10-29 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Jul 28, 2026
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
@mwolsonmwolson changed the title fix(web): Keep in-flight and stopped tool rows in the work logfix(orchestrator): Keep in-flight and stopped tool rows in the work logJul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:S 10-29 changed lines (additions + deletions). labels Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from caf6f38 to d30b4a7CompareJuly 28, 2026 17:55
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Keeping these rows in the work log exposed that the row component had no
treatment for them, so they borrowed the wrong one. A stopped tool rendered a
green check with a "Completed" tooltip once the turn settled, because the
settled-turn fallback treats any neutral row as success. A running tool rendered
the "Empty" dash, which is meant for rows with no content.
Both now render their own state: a spinner tooltipped "Running" while the turn
is live, and a square tooltipped "Stopped" for an interrupted tool. An
`inProgress` row that outlives its turn is also shown as stopped rather than
completed, since the turn ended without the tool ever reporting a result.
Reported by Macroscope on pingdotgg#4762, which caught the stopped-as-completed half.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Codex review of pingdotgg#4762 caught that inferring "stopped" from a settled turn is
wrong. `activeTurnInProgress` is thread-wide, and background work legitimately
outlives the root run: `RunExecutionService` explicitly keeps ingesting a late
background command completion after root terminal, in the order running ->
root-finalized -> completed. The inference would have labelled that live work
"Stopped" and then jumped it to "Completed".
Both indicators now read the item's own lifecycle and nothing else. A genuine
interrupt already terminalizes the item at the projection layer, which is what
made the inference look unnecessary rather than harmful.
Also from that review:
- The work group's filter is now `workEntryShouldRenderInWorkLog`, a production
helper, so the predicate tests exercise the shipped policy instead of a copy
of the expression that could drift from it.
- The lifecycle joins the row's accessible name ("Ran command …, running"),
since the indicator sits inside the row button and did not contribute to it.
The spinner is decorative rather than a nested role="status" announcing a
generic "Loading".
- Component tests cover running during an active turn, running after settle,
stopped in both states, and a signal-less row staying hidden. Tooltip text is
absent from static markup, so they assert on the icon and accessible name, as
the existing failed-indicator test does.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
Also from that round:
- Tests pin "no stopped indicator" properly. A stopped row could have regressed
to the dash while every assertion still passed; there is now a negative
`lucide-minus` check, and the running case asserts the spinner carries neither
`role="status"` nor `aria-label="Loading"`, so the accessibility fix cannot
silently revert.
- The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 5a7eae3 to 257f810CompareJuly 28, 2026 18:36
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 257f810 to 365949aCompareJuly 28, 2026 18:55
@mwolson
mwolson marked this pull request as ready for review July 28, 2026 18:55
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx Outdated
@macroscopeapp

macroscopeappBot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This range contains a 331-commit, 955-file orchestration V2 migration with new production workflows, persistence migrations, public API changes, authentication updates, and mobile/server integrations—not just the stated web work-log fix. Unresolved timeline rendering issues and the added product-default and static-analysis override changes add further review risk.

Not approved because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
@macroscopeapp
macroscopeappBot dismissed their stale reviewJuly 28, 2026 19:18

Dismissing prior approval to re-evaluate 7d5e55c

@github-actionsgithub-actionsBot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Jul 28, 2026
macroscopeapp[bot]
macroscopeappBot previously approved these changes Jul 28, 2026
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
…eachable
Codex round 2 on pingdotgg#4762. Once `workEntryShouldRenderInWorkLog` admits neutral
rows only when they carry a reported lifecycle, the row's neutral handling can
never fire: `showNeutralIndicator` and the settled-turn success fallback both
require the opposite. So `turnSettled`, `hasReportedLifecycle`,
`showNeutralIndicator`, the "Empty" dash branch, and the compound success
expression were all dead.
Success is now just `workEntryIndicatesToolSuccess`, and the row no longer reads
thread-wide turn state at all.
The running test also asserts the spinner carries neither `role="status"` nor
`aria-label="Loading"`, so the accessibility fix cannot silently revert.
The comment claiming both states get their own indicator is gone, as is the
overstatement that a "Run interrupted" divider always sits beneath a stopped
row: `cancelled` maps to stopped too and has no such row.
mwolson added a commit to mwolson/t3code that referenced this pull request Jul 28, 2026
Macroscope on pingdotgg#4762. `projectedWorkEntryStatus` collapses `pending`, `running`,
and `waiting` into `inProgress`, so keying the spinner off `toolLifecycleStatus`
made a queued tool and an approval request blocked on the user both claim to be
running, with a "running" tooltip and accessible suffix to match.
That was a regression from this PR: before it, those rows reached the indicator
chain with no branch that applied and rendered nothing.
`workEntryIsExecuting` reads the projected item's real status instead, so only a
genuinely running tool spins. `pending` and `waiting` rows still render, since
showing in-flight work is the point of the PR, but they claim nothing.
The test helper now derives the projected status from the collapsed lifecycle
value, so a fixture cannot assert on a pairing the projection never emits; the
previous version let a `stopped` row carry a `running` item.
juliusmarmingeand others added 16 commits August 31, 2026 21:33
Retain pending admission after transient status failures and use one generation-owned retry worker. Ignore stale timers and duplicate evidence so older prompts cannot finish newer steering.
Finding: R14 status reconciliation
Model: GPT-5.6 Sol via Codex
Keep hidden local and inherited rows from consuming history pages. Preserve stop-request dependencies, source-run cutoffs, and imported history while loading related metadata from the selected cohort and using indexed watermark lookups.
Finding: P01 bounded history visibility
Model: GPT-5.6 Sol via Codex
Adapt grouped tool summaries and the floating working timer to V2 run, attempt, and queue state. Bring over the composer, keyboard, and disclosure transitions while retaining the V2 activity inspector and queue controls.
Keep OV2 web composer and grouping behavior intact; share only the existing command label parser with mobile.
Restores main features dropped by the policy replay: pingdotgg#8569 theme wiring,
pingdotgg#8850 composer banner follow-ups, pingdotgg#8855/pingdotgg#8904 composer fixes, pingdotgg#8831
settings search rework, pingdotgg#8803 workspace-mutation refresh (v2-adapted),
pingdotgg#8840 circle-alert, pingdotgg#8584 codex artifact templates, pingdotgg#8688/pingdotgg#8807/pingdotgg#8936
video + image previews (web and mobile, v2-adapted), pingdotgg#8862 Expo glass,
and the round's docs. Timeline thinking rows (pingdotgg#8984) stay on the v2
work-live system.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch from a6e0049 to 50a57b6CompareSeptember 1, 2026 05:36
juliusmarmingeand others added 3 commits September 1, 2026 00:24
The v2 equivalents of main's pingdotgg#8984 and pingdotgg#8922: a "Working for ..." header
anchors the active run, the trailing live tool row survives between
actions in past tense instead of vanishing, and a shimmering Thinking
row marks reasoning gaps. During workspace preparation the header shows
"Setting up worktree..." (driven by the local dispatch flag or the v2
run's preparing status, so remote viewers see it too), the composer
footer span is gone, and draft promotion waits until the run starts or
startup fails instead of navigating mid-preparation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mwolson
mwolsonforce-pushed the fix/web-timeline-inflight-tool-rows branch from 38109f8 to a9f243aCompareSeptember 1, 2026 23:26
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 1, 2026 23:26

Dismissing prior approval to re-evaluate a9f243a

if (
entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)

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.

🟡 Mediumchat/MessagesTimeline.logic.ts:783

A failed itemType: "error" with tone: "info" is rendered as a generic work-toggle instead of a work error row, so the provider error detail remains hidden and the expected provider-error-entry row never appears. deriveTurnFolds now leaves these entries visible, but the rendering branch only recognizes tone === "error"; update that branch to also recognize timelineEntryIsTerminalError.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/chat/MessagesTimeline.logic.ts around line 783:
A failed `itemType: "error"` with `tone: "info"` is rendered as a generic `work-toggle` instead of a `work` error row, so the provider error detail remains hidden and the expected `provider-error-entry` row never appears. `deriveTurnFolds` now leaves these entries visible, but the rendering branch only recognizes `tone === "error"`; update that branch to also recognize `timelineEntryIsTerminalError`.

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Two of these findings look like fallout from rebasing onto t3code/codex-turn-mapping: the collapsed work-log UI this PR's round-4 repair targets (a per-group visible cap and a "+N previous tool calls" expander) does not exist on this base, so the new selector, its constant, and the component tests written against it have nothing to attach to.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/chat/MessagesTimeline.logic.ts
Comment threadapps/web/src/components/chat/MessagesTimeline.tsx
Comment on lines +2505 to +2557
structuredPayload: { status: row.itemStatus } as OrchestrationV2TurnItem,
},
};
});

// Collapsed groups used to keep only slice(-1), so a later completed tool
// buried the running or stopped row the work-log filter retained.
it("keeps pinned running and stopped tools visible in a collapsed work group", () => {
const runningAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "running", label: "Active shell", itemStatus: "running" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(runningAndCompleted).toContain("Active shell");
expect(runningAndCompleted).toContain("Finished shell");
expect(runningAndCompleted).toContain("lucide-loader-circle");
expect(runningAndCompleted).not.toContain("previous tool");

const stoppedAndCompleted = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "stopped", label: "Interrupted shell", itemStatus: "interrupted" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);
expect(stoppedAndCompleted).toContain("Interrupted shell");
expect(stoppedAndCompleted).toContain("Finished shell");
expect(stoppedAndCompleted).toContain(', stopped"');
expect(stoppedAndCompleted).not.toContain("previous tool");
});

it("does not pin pending or waiting rows in a collapsed work group", () => {
const markup = renderToStaticMarkup(
<MessagesTimeline
{...buildProps()}
timelineEntries={multiToolWorkEntries([
{ id: "pending", label: "Queued shell", itemStatus: "pending" },
{ id: "waiting", label: "Blocked shell", itemStatus: "waiting" },
{ id: "completed", label: "Finished shell", itemStatus: "completed" },
])}
/>,
);

expect(markup).toContain("Finished shell");
expect(markup).not.toContain("Queued shell");
expect(markup).not.toContain("Blocked shell");
expect(markup).toContain("+2 previous tool calls");

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.

These collapsed-work-group cases assert against UI that does not exist on this target branch. Work groups render row.summary through WorkGroupToggleTimelineRow (e.g. Ran 2 commands), there is no +N previous tool calls expander string anywhere in MessagesTimeline.tsx, and no per-group visible cap that could hide Queued shell/Blocked shell — so both the pinned-row and the not-pinned expectations fail rather than guarding the fix.

Suggest retargeting them at the work-live/work-toggle row model (or removing them alongside the unused selectCollapsedWorkLogEntries) so the suite matches the shipped work-group rendering.

Posted via Macroscope — UI Consistency

Comment threadapps/web/src/components/ChatView.tsx

@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 2 potential issues.

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 a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Collapsed groups hide pinned tool rows

High Severity

selectCollapsedWorkLogEntries is never used when building or rendering work groups. Settled groups still emit only a work-toggle that hides every row, so running and stopped tools stay behind the summary instead of remaining visible in the compact log. The +N previous tool calls expander the new tests expect is also never rendered.

Additional Locations (2)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

entry.id !== group.terminalEntry?.id &&
!timelineEntryIsPersistentResourceCard(entry) &&
!timelineEntryIsTerminalError(entry)
) {

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.

Failed errors stay behind work toggle

Medium Severity

deriveTurnFolds now keeps failed itemType === "error" entries out of the turn fold, but row emission still treats projected provider errors as ordinary work because their tone is info. They become a work-toggle labeled Provider error, so the failure detail stays hidden unless the group is expanded.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit a9f243a. Configure here.

@juliusmarminge
juliusmarmingeforce-pushed the t3code/codex-turn-mapping branch 2 times, most recently from 6081201 to 95bacddCompareSeptember 2, 2026 07:19

@macroscopeappmacroscopeappBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The selectCollapsedWorkLogEntries selector plus its collapsed-group tests, and the unused workingStepLabel / pendingBackgroundTasks props, are still in the state described in the earlier threads on MessagesTimeline.logic.ts:76, MessagesTimeline.test.tsx:2557, and MessagesTimeline.tsx:243MAX_VISIBLE_WORK_LOG_ENTRIES now type-checks, but nothing in MessagesTimeline.tsx calls the selector and the shipped work group still renders every visible entry with no per-group cap or expander. Not re-raising those inline.

Posted via Macroscope — UI Consistency

Comment on lines +2410 to +2411
const workRow = (itemStatus: OrchestrationV2TurnItem["status"] | undefined) => {
const toolLifecycleStatus = toolLifecycleStatusForItemStatus(itemStatus);

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.

These fixtures never reach SimpleWorkEntryRow, so the new lifecycle assertions do not exercise the indicators they describe. beforeEach resets activityTestState.expanded to false, and a tone: "tool" entry with a settled run (isWorking: false, latestRun: null) derives a collapsed work-toggle row (MessagesTimeline.logic.ts:1105), which renders only row.summary — no spinner and no lifecycle-suffixed aria-label. expect(markup).toContain("lucide-loader-circle") and toContain(', stopped"') therefore fail, while toContain("Ran command") passes only because that is also the group summary text.

The neighboring failed-marker case opts into the expanded path explicitly; suggest doing the same in this helper so the rows under test are the ones the PR changed:

Suggested change
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);
constworkRow=(itemStatus: OrchestrationV2TurnItem["status"]|undefined)=>{
activityTestState.expanded=true;
consttoolLifecycleStatus=toolLifecycleStatusForItemStatus(itemStatus);

Posted via Macroscope — UI Consistency

@macroscopeapp

Copy link
Copy Markdown
Contributor

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $248.57, which exceeds your per-review limit of $10.00.

The top 3 files driving up this estimate:

FileDiff SizeEstimate
apps/server/src/orchestration-v2/Orchestrator.ts277.03KB$13.85
apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.ts272.17KB$13.61
apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts230.26KB$11.51

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL1,000+ 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.

7 participants

@mwolson@t3dotgg@PixPMusic@juliusmarminge@nsxdavid@Yusuf007R@maria-rcks