Skip to content

fix(web): a failed group title stays on screen with a retry - #1468

Merged
donjor merged 1 commit into
hyprwsfrom
t3code/investigate-group-title-failure
Oct 1, 2026
Merged

donjor merged 1 commit into
hyprwsfrom
t3code/investigate-group-title-failure

Conversation

@donjor-agent

@donjor-agent donjor-agent Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

🤖 claude/anthropic claude-opus-5-5 (medium)

Refs #1467

What Changed

One app-wide owner handles every group title request: SidebarThreadGroup.title.ts.

Case Behavior
Failure toast stays until dismissed
Toast title names the group and its size
Timeout text names the budget in seconds
Retry resolves the group and live thread titles
Scope switch Retry still runs
Overlap one request per group; extras ignored
Sidebar remount (Settings and back) same owner; old toasts still prune and guard
Repeat failure one toast per group, replaced
Rename, member change, dissolve toast closes
Group changed mid-request failure dropped
Cancellation silent
Group name unchanged on failure

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
Sidebar.tsx carries three marked hook lines.

Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (RemoteEnvironmentAuthTimeoutError), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence Refs.

UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP Fetch paused the title request: held past 60 s for the real timeout, released early for a transport error.

1. Failed title stays on screen

  • Toast: names the group, states the timeout
  • Group: keeps "New group"

05-timeout-toast.png

2. Retry while the scope hides the group

  • Retry: renamed the hidden group
  • Result: "Carve Out Thread Checkouts"
Scoped away, then scoped back

15-scoped-away.png

16-retry-while-scoped-away.png

3. Regenerate over an open failure

  • First Regenerate: closed the toast
  • Second, in flight: ignored; one request
Before and after Regenerate

13-regen-failed.png

14-regen-closes-toast.png

4. Settings unmounts the sidebar

  • Settings: toast persists
  • Retry there: "Sync and Fold Thread Checkouts"
Settings, then the result

06-settings-toast.png

08-retry-result.png

5. Dissolve closes the toast

Before and after Dissolve group

17-before-dissolve.png

18-dissolve-closes-toast.png

Video

Cases 1 and 4, low frame rate:

timeout-toast-retry.mp4

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
Checks
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)

Mutating the in-flight guard or the stale prune fails a test.

Claude Opus 5.5 in Claude Code, inside T3 Code.

Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no

@donjor
donjor force-pushed the t3code/investigate-group-title-failure branch 4 times, most recently from bcda47e to 42867a6 Compare September 30, 2026 20:44
@donjor-agent

donjor-agent Bot commented Sep 30, 2026

Copy link
Copy Markdown
Author

🤖 claude/anthropic claude-opus-5-5 (medium)

Requested a rerun for one exact failed CI job on the unchanged pull-request head. GitHub may also rerun dependent jobs.

  • Head: 42867a628c8be8a2e19136f27cebbd594361218f
  • Workflow: hyprws CI; run 36774776824; pre-rerun attempt 1; open run
  • Job: Test Scripts; id 110089834543; open job
  • Check run: 110089834543
  • Genuine flake reason: fork-fold.test.ts:709 REBASE_HEAD race; PR touches only apps/web; passes 3/3 locally

@donjor-agent

donjor-agent Bot commented Sep 30, 2026

Copy link
Copy Markdown
Author

🤖 claude/anthropic claude-opus-5-5 (medium)

Browser QA: Electron dev app, head 42867a6

All five QA cases pass live against a real server.
State came from a worktree copy of real data.

Failure injection: CDP Fetch paused the thread-group-title request.

Hold Failure
Past 60 s the real client timeout
Released early a transport error

1. Failed title stays on screen

  • Trigger: new group held past 60 s
  • Toast: names the group, states the timeout
  • Group: keeps "New group"

05-timeout-toast.png

2. Retry while the scope hides the group

  • Scope: another project; toast still up
  • Retry: renamed the hidden group
  • Result: "Carve Out Thread Checkouts"
Scoped away, then scoped back

15-scoped-away.png

16-retry-while-scoped-away.png

3. Regenerate over an open failure

  • First Regenerate: closed the toast
  • Second, in flight: ignored
  • Hold log: one request
  • On release: one new toast
Before and after Regenerate

13-regen-failed.png

14-regen-closes-toast.png

4. Settings unmounts the sidebar

  • Settings: toast persists
  • Retry there: reached the server
  • Result: "Sync and Fold Thread Checkouts"
Settings, then the result

06-settings-toast.png

08-retry-result.png

5. Dissolve closes the toast

Before and after Dissolve group

17-before-dissolve.png

18-dissolve-closes-toast.png

Video

Cases 1 and 4 in one low frame rate take:

timeout-toast-retry.mp4

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
@donjor
donjor force-pushed the t3code/investigate-group-title-failure branch from 42867a6 to e356962 Compare October 1, 2026 05:26
@donjor
donjor marked this pull request as ready for review October 1, 2026 05:27
@donjor
donjor merged commit 142d452 into hyprws Oct 1, 2026
11 checks passed
@donjor
donjor deleted the t3code/investigate-group-title-failure branch October 1, 2026 05:48
donjor added a commit that referenced this pull request Oct 1, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 1, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 2, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 2, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 2, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 2, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 3, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 3, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 3, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 6, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor added a commit that referenced this pull request Oct 18, 2026
…1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor added a commit that referenced this pull request Oct 18, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 8d04468 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- 43c8c0f fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 8d04468 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- 43c8c0f fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
…1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor added a commit that referenced this pull request Oct 19, 2026
…1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 19, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 19, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 20, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 20, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 20, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 20, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 20, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 21, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 21, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 21, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 21, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 21, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 22, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 22, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 23, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 24, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 27, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
donjor pushed a commit that referenced this pull request Oct 27, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 27, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 28, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 28, 2026
Refs #1467

## What Changed

One app-wide owner handles every group title request: `SidebarThreadGroup.title.ts`.

| Case | Behavior |
| --- | --- |
| Failure | toast stays until dismissed |
| Toast title | names the group and its size |
| Timeout text | names the budget in seconds |
| Retry | resolves the group and live thread titles |
| Scope switch | Retry still runs |
| Overlap | one request per group; extras ignored |
| Sidebar remount (Settings and back) | same owner; old toasts still prune and guard |
| Repeat failure | one toast per group, replaced |
| Rename, member change, dissolve | toast closes |
| Group changed mid-request | failure dropped |
| Cancellation | silent |
| Group name | unchanged on failure |

All three entry points share the controller: context menu, drag to a new group, header Regenerate.
`Sidebar.tsx` carries three marked hook lines.

## Why

A title request that times out fails after 60 s; its toast then cleared in 5 s.
UAT saw "New group" with no error.
A controlled repro shows the timeout fails typed (`RemoteEnvironmentAuthTimeoutError`), not interrupt-only, so the toast branch ran.
That the 5 s toast was missed remains a hypothesis.

Budget alignment and the OpenCode latency cause stay open on #1467; hence `Refs`.

## UI Changes

Browser QA ran in the Electron dev app against a real server, on a copy of real data.
CDP `Fetch` paused the title request: held past 60 s for the real timeout, released early for a transport error.

### 1. Failed title stays on screen

- **Toast:** names the group, states the timeout
- **Group:** keeps "New group"

![05-timeout-toast.png](https://github.com/user-attachments/assets/29668a49-0061-42ab-9fc3-7d240bb107d1)

### 2. Retry while the scope hides the group

- **Retry:** renamed the hidden group
- **Result:** "Carve Out Thread Checkouts"

<details>
<summary>Scoped away, then scoped back</summary>

![15-scoped-away.png](https://github.com/user-attachments/assets/c726cab7-d587-4935-ad5b-92b7001d6a2b)

![16-retry-while-scoped-away.png](https://github.com/user-attachments/assets/3b02c498-3c07-43eb-8ba1-fbcf42bab593)

</details>

### 3. Regenerate over an open failure

- **First Regenerate:** closed the toast
- **Second, in flight:** ignored; one request

<details>
<summary>Before and after Regenerate</summary>

![13-regen-failed.png](https://github.com/user-attachments/assets/64e6ea42-c3af-450c-97e0-bc3090f65e38)

![14-regen-closes-toast.png](https://github.com/user-attachments/assets/cc8f5047-adbf-4783-81db-f61e709d3b50)

</details>

### 4. Settings unmounts the sidebar

- **Settings:** toast persists
- **Retry there:** "Sync and Fold Thread Checkouts"

<details>
<summary>Settings, then the result</summary>

![06-settings-toast.png](https://github.com/user-attachments/assets/871217a5-f8e7-456f-8c18-af879f77dce7)

![08-retry-result.png](https://github.com/user-attachments/assets/51196f7b-4dc2-4661-a9b0-0abb39faea20)

</details>

### 5. Dissolve closes the toast

<details>
<summary>Before and after Dissolve group</summary>

![17-before-dissolve.png](https://github.com/user-attachments/assets/cf7e0926-0908-4a85-b960-9180043d5cd9)

![18-dissolve-closes-toast.png](https://github.com/user-attachments/assets/7f93cd9b-0f7c-4081-a150-befb95848b7d)

</details>

### Video

Cases 1 and 4, low frame rate:

https://github.com/user-attachments/assets/1d09a61f-4ecf-4b51-8e02-717e179ec0cc

## Checklist

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

<details>
<summary>Checks</summary>

```text
vp test run SidebarThreadGroup.title → exit 0 (13 passed)
apps/web vp run typecheck → exit 0
vp run fork:ci → exit 0
apps/web vp run build → exit 0 (pre-rebase head)
```

Mutating the in-flight guard or the stale prune fails a test.

</details>

Claude Opus 5.5 in Claude Code, inside T3 Code.

## Fork trailers

Squashes:

- 0bc5740 fix(web): a failed group title stays on screen with a retry (#1468) (#1468)
- a4258ae fixup! fix(web): a failed group title stays on screen with a retry (#1468) (#1468)

Fork-Domain: thread-ordering
Fork-Tier: bugfix
Fork-Upstreamable: no
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant