Skip to content

perf(server): shell reads stop counting every turn item - #27975

Closed
Pyseph wants to merge 6 commits into
pingdotgg:mainfrom
Pyseph:perf/stored-turn-item-counts
Closed

Pyseph wants to merge 6 commits into
pingdotgg:mainfrom
Pyseph:perf/stored-turn-item-counts

Conversation

@Pyseph

@Pyseph Pyseph commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Every shell read counts each thread's turn items by walking the (thread_id, run_id) index, one entry per item. The count runs for every thread in a snapshot, and getThreadShell runs it again for the thread behind each projected shell event. On a large history this is the biggest part of the shell read, and once the index is out of the page cache it reads from disk.

On 2026-10-29, the server in #24192 (2,857 active threads, 645k turn items) spent 4.8 s of a 7.3 s phone reconnect on these counts. That was before #27106; on current main the phone's opted-in shell reads far fewer threads, but they are the busiest ones, and every shell event still recounts its thread.

Change

  • Migration 081 adds orchestration_v2_projection_turn_item_counts, one row per (thread, run), and backfills it.
  • Triggers on turn items keep it exact for every writer: the projector's upsert, projection rebuilds, and migrate-dev-db's pruning. An upsert that hits an existing item fires only the update trigger, which does nothing unless the item moved to another thread or run.
  • The two shell count queries read the table. They keep fix(server): thread lists load beyond SQLite variable limit #25696's json_each ID predicates, and perf(server): sidebar shell loads 3x faster and startup thread counts 80x faster #27106's index-first loading is untouched.
  • docs/internals/performance-regressions.md said shell counts use a covering index; that sentence now says where they come from.

Measurements

All on main at the time, 2b15ba077d, using a static copy of the shell tables from the same server: 3,047 threads, 701,015 turn items and 9,644 (thread, run) pairs. Both arms ran the real ProjectionStore code read-only against the identical file. Times are warm medians; the two rounds alternated main and branch, 15 samples each after 3 warmups. Every output was byte-identical between arms (same SHA-256).

Read main this PR
Phone's opted-in HTTP shell (105 threads) 107 / 101 ms 85 / 83 ms
Full active shell (3,032 threads) 445 / 578 ms 245 / 258 ms
getThreadShell on the 10 largest threads, total 69 / 99 ms 45 / 48 ms

Data the counts read, which is what a cold read pays for:

Count read main this PR
Phone's opted-in shell 84,133 index entries 3,750 rows
All threads 158 MB index (40,475 pages) 1.8 MB table (458 pages)

The thread rows query, the other large part of a cold shell read, is unchanged.

Write cost

20,000 real turn items, replayed through the projector's exact upsert into the same schema (WAL, synchronous = NORMAL), with and without the triggers, in ABBA order:

Workload main triggers
One transaction per upsert, like event commits: insert / re-upsert 10.8 s / 5.9 s 10.7 s / 4.9 s
One transaction for all, statement cost only: insert 1,172 ms 1,324 ms (+7.6 µs per item)
Same: re-upsert of existing items 1,122 ms 1,210 ms (+4.4 µs per item)
DELETE FROM every turn item 71 ms 503 ms (+22 µs per item)

Per event, the triggers are lost in commit cost: main alone ranged from 6.7 to 13.7 s on the per-event insert run. Deletes cost the most because a delete trigger makes SQLite delete row by row instead of clearing the table. Production code deletes turn items only in the projection rebuild, a startup repair, and in migrate-dev-db. On 700k items that adds about 15 s to a rebuild that also re-applies every event.

The migration took 1.2 s on the 701k-item copy, and its counts matched a GROUP BY over the items with no differing rows.

Verification

  • 081_TurnItemCounts.test.ts: backfills existing items, then follows a new item, a repeated upsert (not counted twice), an item moving into a run, and deletes.
  • The existing ProjectionStore case "counts each shell's own runless and live-run items, skipping rolled back and missing runs" passes unchanged against the new queries. It counts through the projector's real path, covering runless items, a rolled-back run and an item whose run has no row.
  • Passing locally: vp test run on the migration test, reconcileV2PreviewMigration, migrate-dev-db, ProjectionStore, ShellStream, FoundationPersistence (rebuild), ThreadFork.integration and TurnItemCompaction (126 tests); vp run check:changed. The other files that rebuild projections also pass: the 064 and 066 migration tests (which rebuild before 081 exists), LegacyV1ThreadImporter, ProjectService.deletion and ProviderSwitch.integration.

Not checked: cold-cache timing on the new code, since this Windows machine can't drop its file cache; the page counts above stand in for it.

Scope

This replaces #26816, which was closed under the one-problem rule for an unrelated reader-pool test. That test is gone. PixPMusic's review there found the count table useful once rebased: a free migration ID, #25696's predicates kept, and #27106's loading kept. All three are done here, along with the write costs that review measured. The reader-pool queueing gap from that review is in its own PR. Related: #24192.

Claude Opus 5.5 in T3 Code (Claude Code harness).

Shell snapshots and getThreadShell counted each thread's items by walking
the (thread_id, run_id) index, one entry per item. Migration 076 keeps one
count per (thread, run) with triggers on turn items, and the shell count
queries read it.
A count the triggers could not see change, such as one inflated by an INSERT OR REPLACE, survived a rebuild because deleting the items only decrements it. Rebuilds now clear the table before re-projecting.
@github-actions github-actions Bot added vouch:unvouched Author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Oct 31, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at ca75793

Macroscope's review found this PR approvable — Shell reads use trigger-maintained counts instead of recounting every turn item. The additive table preserves source data and can be rebuilt; reported measurements show equivalent outputs with limited migration and write overhead.

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

@coderabbitai

coderabbitai Bot commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • Resume reviews
  • Trigger review

No actionable comments were generated in the recent review.

Walkthrough

The change adds a trigger-maintained table of turn-item counts grouped by thread and run. Shell count queries now read those counts, and migration 81 is registered and covered by migration tests.

Changes: Turn-item count projections

Layer / File(s) Summary
Create and maintain turn-item counts
apps/server/src/persistence/Migrations/081_TurnItemCounts.ts, apps/server/src/persistence/Migrations/081_TurnItemCounts.test.ts, apps/server/src/persistence/Migrations.ts, apps/server/src/persistence/reconcileV2PreviewMigration.test.ts
Migration 81 creates and backfills counts grouped by thread and run. Triggers update counts on inserts, changes to thread or run, and deletes. Migration registration and upgrade test expectations include migration 81.
Read turn-item counts for shell queries
apps/server/src/orchestration-v2/ProjectionStore.ts, docs/internals/performance-regressions.md
Shell queries read stored counts instead of counting turn-item rows. Per-run counts exclude runless items; total counts exclude items from rolled-back runs, and runless counts include only runless items. The performance documentation describes the count table and retained indexes.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Refactor

Possibly related issues

  • Issue 23000 reports slow shell-list queries caused by scanning turn-item history. This change targets the same query cost with stored counts, but the issue’s proposed indexes differ and the issue is not resolved by this change.

Suggested reviewers: juliusmarminge, yash-singh1

Merge Risk: Minimal · up to fed6c

No actionable count mismatch is established at the current head. The change is mergeable after normal checks.

Pre-merge checks: Passed 3 · Inconclusive 1

Failed Failed checks: 1 inconclusive

Check name Status Explanation Resolution
Description check Inconclusive The description follows the repository template and is mostly complete. It has a Problem section with a clear problem statement and measurements, a Change section listing the migration, triggers, quer… Add a link to the triaged bug issue (or the discussion with explicit maintainer approval, including the approval comment) under "Scope and approval". If no prior issue exists, explain why this qualifies as a very small, focused fix of an ob…
Passed Passed checks: 3 passed

Check name Status Explanation
Title check Passed The title is concise, specific, and accurately describes the main performance change: shell reads no longer count every turn item.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description follows the repository template and is mostly complete. It has a Problem section with a clear problem statement and measurements, a Change section listing the migration, triggers, query changes, and doc update, and a Verification section listing specific tests and an unchecked item (cold-cache timing). The Scope and approval section is only partly satisfied: it says the PR replaces #26816 and cites related issue #24192, but it does not link a triaged bug issue or a maintainer approval comment, and it does not explain why the change qualifies without one. The Problem section also refers to other PRs (#25696, #27106, #24192) without context for a reviewer who has not read them. The template's trailing agent-model line is present ("Claude Opus 5.5 in T3 Code"). These gaps are not critical, but the scope/approval gap is material under the template's rules.

Resolution

Add a link to the triaged bug issue (or the discussion with explicit maintainer approval, including the approval comment) under "Scope and approval". If no prior issue exists, explain why this qualifies as a very small, focused fix of an obvious bug. Briefly explain the context of #25696, #27106, and #24192 so reviewers can follow the Problem section without opening them. Confirm the PR title follows a conventional commit format in plain language, since the template asks for one.

Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 6710e36 and fed6cd7.

Files selected for processing: 5

  • apps/server/src/orchestration-v2/ProjectionStore.ts
  • apps/server/src/persistence/Migrations.ts
  • apps/server/src/persistence/Migrations/081_TurnItemCounts.test.ts
  • apps/server/src/persistence/Migrations/081_TurnItemCounts.ts
  • apps/server/src/persistence/reconcileV2PreviewMigration.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Migration tests rebuild projections on databases migrated only to 064 or
066, before the counts table exists, and the extra DELETE failed there.
The triggers already keep the table exact for every writer.
@maria-rcks

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

Merged current main without rebasing. Kept main's migration 076 and moved the stored turn-item counts migration and its existing test to 077, preserving both changes and the six-file scope.

Blacksmith passed vp run check:changed github/main: formatting, lint, knip, GraphQL, affected typechecks, and 61 tests. A focused migration/projection run also passed 52 tests. Two independent read-only reviews approved 54b50f1106 with no findings.

@maria-rcks

Copy link
Copy Markdown
Collaborator

Note

Written by gpt-6.1-sol on behalf of Maria

Verified in a real dev environment

verified 54b50f11062ab24fa9342a0a49736886d9df5136 as-is on a linux boat vm. installed main and the exact pr head with vp i, then ran one background dev server at a time. used repository playwright with /usr/bin/google-chrome, a project added through the ui, and four real codex gpt-6.1-sol turns. no mocks, replay data, fixtures, or direct database writes.

  • on github/main (ce9e016406), two completed turns produced 7 and 8 items. the client http shell returned 15. confirmed the old count query walks the turn-item covering index.
  • stopped main, copied its isolated app-created database, and started the pr. migration 077 backfilled 7 and 8 exactly. the same conversation rendered and the http shell still returned 15.
  • continued the same codex session through the composer. shell websocket counts advanced from 15 to 21 as real items streamed. stored counts matched raw items during the turn and after completion, with no upsert inflation.
  • forked from the first response and continued through codex. the fork showed 5 own items and 13 visible items including inherited history, preserved after reload.
  • used "edit from here" and "revert and keep changes" on the source's third turn. provider rollback completed. the shell excluded the rolled-back run's 6 items, returning 15 again, while the stored rows remained exact. the fork stayed at 5 own / 13 visible items after reconnect.

blacksmith passed 69 focused migration/projection/shell tests. vp run check:changed 7195b699547b538e49f758e314dde5c8c5d907cf also passed format, lint, knip, graphql, affected typechecks and 61 tests. latest applicable github checks pass. no source changes needed.

short runtime transcript

main: two real codex turns before migration

pr: the same conversation after migration 077

pr: real codex turn submitted, streamed and completed

Not verified

native mobile and desktop clients, other providers, and remote/relay/tunnel connections were not exercised. large-history speedup and cold-cache latency remain unverified: this small real dataset proves integration and count correctness, not production-scale performance. delete/move triggers passed focused tests; destructive runtime deletion and projection repair were not induced.

@Pyseph

Pyseph commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

Main moved under this PR and it now conflicts. I merged main into the branch (no rebase), as on #22507.

Two files conflicted, both only because of migration numbering. Main added 077 (RepairBooleanSettledOverride), 078 (DropOrchestrationEventCorrelationIndex) and 079 (DelegatedRecoveryIndexes) after this branch took 077. I kept all three upstream migrations as they are and moved this PR's migration to 080:

  • Migrations.ts: kept 077-079 from main, registered [80, "TurnItemCounts", Migration0080] after them.
  • reconcileV2PreviewMigration.test.ts: kept main's 077-079 history rows and added [80, "TurnItemCounts"] to both expected histories.
  • 077_TurnItemCounts.ts and its test are renamed to 080_TurnItemCounts.ts / .test.ts (test describe name updated). The SQL, triggers and backfill are unchanged, and so is the ProjectionStore change.

After the merge the diff against main is the same six files the PR had before. Merge commit: 6710e36.

Checks (Node 26.12.1, Windows): the 080_TurnItemCounts, Migrations, reconcileV2PreviewMigration, 064 and 066 migration tests and the ProjectionStore and ProjectionMaintenance tests pass (7 files, 72 tests); tsc --noEmit in apps/server, lint and format on the six changed files are clean.

…-counts

# Conflicts:
#	apps/server/src/persistence/Migrations.ts
#	apps/server/src/persistence/reconcileV2PreviewMigration.test.ts
@Pyseph

Pyseph commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Note

Written by Claude Opus 5.5 on behalf of Pyseph

Main moved under this PR again, so I merged it into the branch (no rebase) in fed6cd7bd9.

Two files conflicted, both only because of migration numbering. Main's 080_ScheduledTaskThreadMode took the number this PR had, so this PR's migration is now 081:

  • Migrations.ts: kept main's 080 and registered [81, "TurnItemCounts", Migration0081] after it.
  • reconcileV2PreviewMigration.test.ts: kept main's 080 and added [81, "TurnItemCounts"] to both expected histories.
  • 080_TurnItemCounts.ts and its test are renamed to 081_TurnItemCounts.ts and .test.ts, with the test's name updated. The SQL, triggers and backfill are unchanged, and so is the ProjectionStore change.

The diff against main is still the same six files.

Checks on Node 26.12.1, Windows: 081_TurnItemCounts, Migrations, reconcileV2PreviewMigration, ProjectionStore and ProjectionMaintenance tests pass (5 files, 71 tests). The server typecheck is clean, and the pre-commit hook (fmt, lint, knip) passes.

@t3dotgg

t3dotgg commented Nov 12, 2026

Copy link
Copy Markdown
Member

Note

🤖 Claude Fable 5.2 responding on behalf of Theo

Superseded by #35167, merged as 3e03072.

Your trigger-maintained item counts are in that PR with your authorship, and the squash commit carries a Co-authored-by line for you. It was chosen over the other open design (#34666) because it stores one fact, stays exact for every writer, and costs less per write (about +7 to +14 µs per new turn item against +26 to +32 µs, measured on the same data).

Verified on a real server with 1,813 threads and 153,546 turn items: the two migrations run once, the stored counts match a fresh recount after every kind of write, and the sidebar matches main row for row.

@juliusmarminge

Copy link
Copy Markdown
Member

Thanks for this. Main has the change since #35167.

Main contains the identical count table, backfill and triggers as migration 85, both shell count-query replacements, migration tests and documentation update. Compared your full diff; main also extends coverage for rewrites, moves, rollback, late runs and projection rebuilds.

Closing as superseded.

carlosfelgarcia added a commit to carlosfelgarcia/t3code that referenced this pull request Nov 12, 2026
* fix(web): wrap interruption footers as one sentence (pingdotgg#34649)

* feat(web): switch the UI language from Settings, with Spanish and Chinese (pingdotgg#31313)

* feat(web): add Brazilian Portuguese translation (pingdotgg#33161)

* feat(web): add French translation (pingdotgg#33162)

* feat(web): add German translation (pingdotgg#33163)

* feat(web): add Japanese translation (pingdotgg#33164)

* feat(web): add Korean translation (pingdotgg#33165)

* feat(web): add Russian translation (pingdotgg#33166)

* feat(mobile): switch the settings language (pingdotgg#33169)

* fix(web): dismissing the pull request checkout toast stops the handoff (pingdotgg#34509)

* fix(cursor): unified usage plans show one meter (pingdotgg#34506)

* fix(web): editing a queued message keeps its thread mention chips (pingdotgg#30889)

* fix(desktop): browser snapshots work after relay reconnects (pingdotgg#24829)

* fix(server): skip Claude interrupts after session teardown (pingdotgg#25159)

* fix(desktop): a maximized window reopens on the display it was last used on (pingdotgg#25833)

* fix(provider-core): bun-global updates only offer versions bun will install (pingdotgg#30641)

* fix(cli): t3 thread finds the project from inside its git worktrees (pingdotgg#30802)

* fix(dev): import seed snapshots with peer preview migrations (pingdotgg#25058)

* fix(desktop): AppImage updates no longer leave old runtimes and mounts running (pingdotgg#29672)

* fix(cli): t3 triage points at the prompt when the agent fails to start (pingdotgg#28192)

* fix(web): formatted link labels wrap inside table cells (pingdotgg#27781)

* fix(web): Mod+B toggles bold at a collapsed cursor when the sidebar toggle is remapped (pingdotgg#29445)

* fix(web): update Retry stops re-sending servers already on the target version (pingdotgg#32924)

* fix(web): switching a cold Claude thread to Codex no longer compacts first (pingdotgg#25986)

* fix(web): code blocks always show their own highlighted source (pingdotgg#34527)

Co-authored-by: maria-rcks <[email protected]>

* fix(acp): only approved execute requests let the agent open client terminals (pingdotgg#34526)

Co-authored-by: maria-rcks <[email protected]>

* fix(pi): long tool calls no longer share a session approval with different calls (pingdotgg#34528)

Co-authored-by: maria-rcks <[email protected]>

* fix(cli): thread, project, and connect commands skip a server that is gone (pingdotgg#34529)

Co-authored-by: maria-rcks <[email protected]>

* fix(server): file metadata lookups skip the server's own state files (pingdotgg#34530)

Co-authored-by: maria-rcks <[email protected]>

* fix(acp-registry): ACP Registry installs only change the mode of a contained command (pingdotgg#34531)

Co-authored-by: maria-rcks <[email protected]>

* fix(server): MCP tokens still expire after the clock steps back (pingdotgg#34532)

Co-authored-by: maria-rcks <[email protected]>

* fix(server): ChatGPT sign-in keeps listening after a stray callback request (pingdotgg#34533)

Co-authored-by: maria-rcks <[email protected]>

* fix(mobile): show and let users skip compaction before sending to stale Claude threads (pingdotgg#34482)

* fix(web): Cmd+A in the rendered Markdown preview selects only the file (pingdotgg#30738)

* fix(web): don't offer VS Code on iPad, iPhone and Android browsers (pingdotgg#27557)

* fix(web): a link to a thread on a linked machine no longer opens a blank pane (pingdotgg#34657)

* fix(server): self-update moves the t3 command to the new runtime (pingdotgg#14875)

Co-authored-by: Julius Marminge <[email protected]>

* fix(server): t3_thread_launch says when its project does not exist (pingdotgg#29109)

* fix(mobile): iOS web previews keep their flick momentum (pingdotgg#27671)

* feat(github): unvouched PRs get an open PR limit, a conflict window, and a 72 hour close notice (pingdotgg#34555)

* fix(web): pasted CRLF text keeps its blank lines and caret in the composer (pingdotgg#27280)

* fix(server): a cancelled queued Claude continuation no longer drops later wakes (pingdotgg#30114)

* fix(web): app keybindings on Mod+B, Mod+I and Mod+E win over composer formatting (pingdotgg#34493)

* fix(web): thread shortcuts work with the narrow sidebar closed (pingdotgg#23568)

* fix(web): keep background tasks visible during follow-up turns (pingdotgg#24336)

* fix(mobile): the Link a machine sheet scrolls on Android (pingdotgg#34659)

* feat(web): resolved review conversations fold into avatars on their diff line (pingdotgg#34644)

* fix(web): mouse back/forward over the right panel no longer moves the main chat (pingdotgg#30882)

* fix(github): the PR limits sweep retries a failed read (pingdotgg#34671)

* fix(web): collapsed PR comments no longer show raw HTML (pingdotgg#32283)

* fix(server): t3_thread_list counts threads waiting on background work as live (pingdotgg#34674)

* fix(mobile): screen readers hear when the open thread needs you or finishes (pingdotgg#34431)


* fix(server): providers keep their saved status until the first check finishes (pingdotgg#34678)

* fix(mobile): choosing a project for a draft whose project is gone keeps the draft (pingdotgg#26800)

* fix(contracts): side chats open after an abandoned worktree setup (pingdotgg#34686)

* fix(web): interruption footer label sits on the reason's baseline (pingdotgg#34685)

* fix(opencode): project-defined models appear in that project's picker (pingdotgg#24585)

* fix(server): t3 theme updates a dev server running in the default home (pingdotgg#34700)

* fix(server): preserve delegated results across wake turns (pingdotgg#34568)

* fix(cli): thread --wait returns once background work the agent waits on has ended (pingdotgg#34696)

* fix(cursor): hide duplicate pooled usage limits (pingdotgg#34421)

* fix(web): keep git action loading rows at idle height (pingdotgg#34727)

* fix(cursor): steer the live run without reconnecting (pingdotgg#28980)

Co-authored-by: Yash Singh <[email protected]>

* fix(web): file breadcrumbs keep backslashes in POSIX folder names (pingdotgg#34724)

* fix(server): Pi usage and session import read the instance's home (pingdotgg#34726)

* fix(server): t3_thread_list says when its project does not exist (pingdotgg#29187)

* fix(web): improve Word document previews (pingdotgg#34722)


* fix(web): voice settings and dictation match the rest of the app (pingdotgg#33140)

* feat(web): reply to an assistant response from its hover actions (pingdotgg#33124)

Co-authored-by: maria-rcks <[email protected]>

* fix(server): title requests about referenced threads accurately (pingdotgg#34723)

* fix(web): cancelled PR checks show a gray stop sign instead of the failed X (pingdotgg#34734)


* fix(cursor): recover restarted threads with older runs (pingdotgg#24540)

Co-authored-by: Yash Singh <[email protected]>

* fix(desktop): stalled update downloads time out and say why (pingdotgg#26244)

* fix(server): Tailscale Serve forwards to the address a specific --host binds (pingdotgg#34741)

* fix(tailscale): serve setup no longer times out on a long success summary (pingdotgg#34743)

* fix(server): Rescan finds tools installed after T3 Code started (pingdotgg#23610)

* fix(server): advertise the tailnet name when sshd listens only on the tailnet address (pingdotgg#34745)

* fix(web): preview address bar waits for the IME to finish before navigating (pingdotgg#34750)

* fix(tailscale): Tailscale HTTPS is advertised only when it reaches this T3 server (pingdotgg#34744)

* fix(server,web,mobile): messages from a linked environment name the thread that sent them (pingdotgg#34721)

Co-authored-by: Happy Campr <[email protected]>
Co-authored-by: Julius Marminge <[email protected]>

* fix(shared): links to bracketed filenames keep their folder labels (pingdotgg#34759)

* fix(server): a Claude resume rejected before the prompt keeps the native session (pingdotgg#34762)

* fix(server): Codex MCP servers that fail to start show a notice in the thread (pingdotgg#34771)

* fix(server): block incompatible migration history in preflight (pingdotgg#34773)

Co-authored-by: Julius Marminge <[email protected]>

* fix(server): a reset credit's limits refresh when the first read after it fails (pingdotgg#34780)

* fix(forgejo): HTTP-only fj logins are no longer reported unauthenticated (pingdotgg#34777)

* fix(server): a new worktree thread's agent starts on its renamed branch (pingdotgg#34781)

* fix(server): ACP retries a config option whose write failed for a reason other than refusal (pingdotgg#34782)

* chore: denounce wSedlacek (pingdotgg#34789)


* fix(cursor): resume moved threads from their original session store (pingdotgg#34794)

* docs: CONTRIBUTING.md is shorter and says we only take bug fixes (pingdotgg#34797)


* fix(server): remote delegate_task runs on the driver it names (pingdotgg#34790)

* fix(server): schedule_task updates apply freshSession (pingdotgg#34801)

* fix(web): Backspace right after a list shortcut keeps the typed marker (pingdotgg#34802)

* fix(contracts): Space shortcuts reach clients instead of reverting to defaults (pingdotgg#34799)

* fix(web): questions without options no longer mention a selected option (pingdotgg#34806)

* fix(server): threads launched in the project folder record its branch (pingdotgg#34812)

* fix(server): tell the thread when its worktree branch keeps the temporary name (pingdotgg#34813)

* fix(server): fresh-session schedules start while an old session has background work (pingdotgg#34811)

* fix(web): Ctrl/Cmd+Enter sends new threads when the send shortcut needs it (pingdotgg#34810)

* fix(shared): typing after a skill chip no longer reparses the prompt as math (pingdotgg#34816)

* fix(provider-acp): wait_for_exit answers when a background child holds the output pipes (pingdotgg#34825)

* fix(server): Claude sets a /goal that also mentions a skill (pingdotgg#34818)

* fix(server): resumed Claude sessions wait for their MCP servers (pingdotgg#34822)

* fix(server): re-import no longer marks a continued transcript imported without its new messages (pingdotgg#34809)

* fix(server): file links relative to a gitignored git worktree open the file (pingdotgg#34831)

* fix(server): restart recovery wakes delegated children waiting on background work (pingdotgg#34833)

* fix(opencode): a Stop OpenCode 2 never answers offers Force stop (pingdotgg#34840)

* fix(server): side chat fork context recovers history from the parent thread (pingdotgg#34845)

* fix(cursor): agent shell commands stream their output while they run (pingdotgg#34843)

* fix(web): Escape and tool keys work as soon as preview annotation starts (pingdotgg#34796)

* fix(server): Claude subagent results drop Claude Code's tools-used note (pingdotgg#34821)

* fix(server): context handoff names omitted items instead of a read from the thread's start (pingdotgg#34847)

* fix(server): a slow baseline checkpoint no longer holds every prompt for 30 seconds (pingdotgg#34849)

* fix(server): Codex subagent rows show the child's current command (pingdotgg#34862)

* fix(web): review comments in question answers reach the agent with their text (pingdotgg#34855)

* fix(server): T3 Connect says whether an unresolved address exists in public DNS (pingdotgg#34866)

* fix(source-control): a query or fragment after .git keeps the repository identity (pingdotgg#34857)

* fix(client-runtime): provider toggles no longer wait for another provider's update (pingdotgg#34858)

* fix(desktop): Linux desktop builds run the packaged-server self-check (pingdotgg#34863)

* fix(server): subagent threads get short ids agents can quote back (pingdotgg#34877)

* fix(web): context row under the composer hides chat text scrolling behind it (pingdotgg#34846)

* fix(web): sidebar rows drop a branch and worktree that were deleted (pingdotgg#34878)

* fix(server): a fork made after Edit from here no longer shows the rewound turns (pingdotgg#34823)

* fix(server): a pull request watch started after a pending self-settle survives the turn end (pingdotgg#34884)

* fix(server): thread reads list only open linked PRs and show their watch state (pingdotgg#34895)

* fix(server): finished delegated Codex children no longer pile up in Codex Recents (pingdotgg#34829)

* fix(acp): ask forms with a free-text companion field show one step per question (pingdotgg#34867)

* fix(server): deleting a source thread keeps the pages its live fork still shows (pingdotgg#34879)

* fix(web): html render images open with the rest of their page in the viewer (pingdotgg#34883)

* fix(provider-core): one failed status check no longer marks a ready provider unavailable (pingdotgg#34885)

* fix(server): Codex goals wait for a delegated task instead of re-prompting (pingdotgg#34898)

* fix(web): Incognito browser visits stay out of project history (pingdotgg#34859)

* fix(server): favicon lookups for a missing project folder are cached (pingdotgg#34905)

* fix(provider-core): Codex turns refused by a managed access policy say so instead of 'retry' (pingdotgg#34871)

* fix(server): Claude forked skills record the model they run on (pingdotgg#34848)

* fix(deps): resolve path-to-regexp 6.3.0 under @vercel/routing-utils (pingdotgg#34914)

* fix(server): new worktrees survive git printing over 1 MB (pingdotgg#34889)

* fix(server): status of a new repository no longer waits on huge untracked files (pingdotgg#34916)

* fix(web): a sidebar click no longer gets lost when the release reports no buttons (pingdotgg#34929)

* fix(web): a stashed prompt ending in a skill or file chip restores as a chip (pingdotgg#28352)

* fix(web): clicking the timeline's empty padding keeps following a streaming reply (pingdotgg#34899)

* fix(server): browser setup command names the running t3 executable, not another t3 on PATH (pingdotgg#34936)

* fix(desktop): app opens after an update while the old server shuts down (pingdotgg#34932)

* fix(server): standalone Codex is checked against the native release channel (pingdotgg#34910)

* fix(provider-muse): an unfinished Muse install says how to finish setup (pingdotgg#34927)

* fix(ssh): a failed remote t3 download says what failed and how to install it (pingdotgg#34928)

* fix(clients): Claude question option previews are shown under their option (pingdotgg#34784)

* fix(server): a failed delegated task keeps its child's final report (pingdotgg#34915)

* fix(server): handoff budget estimates stored history in tokens, not bytes (pingdotgg#34926)

* fix(desktop): a failed update-track save keeps offering the current track's updates (pingdotgg#34917)

* fix(server): custom Claude models named like a Claude Code alias reach the API unchanged (pingdotgg#34938)

* fix(server): finished Claude delegates release their process (pingdotgg#34934)

* fix(mobile): iPhone Settings search keeps its query after switching tabs (pingdotgg#34893)

* fix(mobile): Android review sheet scrolls to Submit review (pingdotgg#34887)

* fix(server): boot service log is emptied in place once it passes 10 MiB (pingdotgg#34886)

* fix(server): a missed fixed-time slot shows as failed on its scheduled task (pingdotgg#34815)

* fix(server): Stop interrupts a provider turn that starts while it lands (pingdotgg#34912)

* feat(web,mobile): Add project lists only GitHub until you turn other hosts on (pingdotgg#34978)


* fix(opencode): updating restarts the background service on the new version (pingdotgg#34606)

Continues pingdotgg#31152.

Co-authored-by: Miley <[email protected]>
Co-authored-by: maria-rcks <[email protected]>

* fix(web): CSV/TSV and large-text previews say "1 row", "1 column" and "1 line" (pingdotgg#34992)

* fix(desktop): browser panel can approve local HTTPS certificates (pingdotgg#24425)

Co-authored-by: Theo Browne <[email protected]>

* perf(server): sending to a very long thread reads about 5x less of its history (pingdotgg#35130)


* fix(cursor): user-invoked skills hidden from the model reach the Cursor prompt (pingdotgg#34999)

* fix(server): thread find skips empty replies hidden beside an HTML render (pingdotgg#34991)

* fix(server): Codex sign-in hint names the instance's CODEX_HOME (pingdotgg#35004)

* fix(server): project identity follows gh repo set-default (pingdotgg#35005)

* fix(shared): html_render pages from OpenCode 2 Code Mode show and are cleaned up (pingdotgg#35022)

* fix(web): overlong content search queries explain the 256-character limit (pingdotgg#35020)

* fix(server): Claude replies stream paragraph by paragraph again (pingdotgg#35037)

* fix(server): a run whose recovery state can't be read fails instead of staying starting (pingdotgg#35013)

* fix(web): No project threads offer no Initialize Git, and their linked PRs show and act in the thread (pingdotgg#34788)

Co-authored-by: Julius Marminge <[email protected]>

* fix(server): thread setting changes no longer end a Claude session's background work (pingdotgg#35029)

* fix(server): Tailscale Serve no longer takes a live server's route and repairs one left on a dead port (pingdotgg#35042)

* fix(server): delegate_task wait returns its task handle before Node fetch's 300 s timeout (pingdotgg#35032)

* fix(server): a damaged state database fails startup with its path and how to recover (pingdotgg#35057)

* fix(desktop): a login shell slower than 5s at launch still yields its PATH (pingdotgg#35033)

* fix(opencode): a slow OpenCode 2 server start no longer leaves the model list empty (pingdotgg#35049)

* fix(server): one unresponsive provider no longer stalls every thread's effects (pingdotgg#35027)

* fix(desktop): SnapShot shortcut rebinds after the desktop portal restarts (pingdotgg#35048)

* fix(server): desktop browser tabs on System appearance follow the system color scheme (pingdotgg#35038)

* fix(server): a project whose origin URL contains a space gets a repository identity (pingdotgg#35080)

* fix(desktop): installing an update closes SSH port forwards before relaunch (pingdotgg#35018)

* fix(web): Files tree keeps expanded folders across remounts (pingdotgg#35067)

* fix(ssh): an ssh config alias keeps following its Port after it changes (pingdotgg#35063)

* fix(server): fork PRs into gh's upstream base use an owner-qualified head (pingdotgg#35055)

* fix(web): file names with a backslash no longer split into folders in the Changes card (pingdotgg#35075)

* fix(server): automatic pulls and pull request refresh let slow checkouts finish (pingdotgg#35014)

* fix(server): Codex turns use the configured reasoning summary instead of forcing detailed (pingdotgg#35089)

* fix(provider-core): Vite+ system_first shims update the install they actually run (pingdotgg#35086)

* fix(web): diff tab keeps its scroll position across thread switches (pingdotgg#35090)

* test(web): command palette tests clear a leaked last-used project (pingdotgg#35107)

* fix(opencode): OpenCode 2 threads see T3 Code's MCP tools on their first turn (pingdotgg#35084)

* fix(server): a finished turn refreshes only its own project's PR listings (pingdotgg#35070)

* fix(desktop): exits that skip quit are recorded in the trace and logs (pingdotgg#35097)

* fix(clients): say "Starting Claude" until the provider actually starts (pingdotgg#35008)

* fix(mobile): long thread titles in the @ picker keep their Thread marker (pingdotgg#35062)

* fix(web): every settings nav group has a name for screen readers (pingdotgg#35101)

* fix(web): an invalid provider setting is refused at its field instead of taking the provider offline (pingdotgg#35100)

* fix(web): PR comment hover excerpts no longer end in a replacement character (pingdotgg#35111)

* fix(mobile): Android composer keeps its cursor after a drag-scroll (pingdotgg#35092)

* fix(client-runtime): Diagnostics Resource History keeps updating while open (pingdotgg#35116)

* fix(web): a failed send leaves the timeline when a new draft was typed (pingdotgg#35102)

* fix(web): a save in one tab no longer erases what another tab saved (pingdotgg#35110)

* fix(server): projects read their own Git repository when the server inherited GIT_DIR (pingdotgg#35119)

* fix(web): file links the agent cited from another project open that project's file (pingdotgg#35036)

* fix(client): a message the host never answers fails after 60 seconds instead of spinning forever (pingdotgg#35076)

* fix(server): a new worktree no longer fails when its generated folder is left over from an earlier one (pingdotgg#35121)

* fix(server): a file ticked Viewed before loading a push shows Changed (pingdotgg#35114)

* fix(server): selected-file commits during a cherry-pick or revert are refused (pingdotgg#35120)

* fix(web): chat text selection stays continuous while scrolling (pingdotgg#35074)

* fix(server): committing a large selection of files no longer fails with spawn E2BIG (pingdotgg#35128)

* fix(server): Claude threads resume the session /clear started (pingdotgg#35054)

* perf(mobile): each environment sends about 85% less data at launch (pingdotgg#35072)


* perf(server): oversized transcript exports fail fast and thread opens skip unused handoff bodies (pingdotgg#34547)


* fix(web): icon-only chat header controls show their name on hover (pingdotgg#35045)

* fix(web): panel resize handle no longer covers the chat scrollbar (pingdotgg#35043)

* fix(web): browser settings changed in project scope no longer overwrite the global default (pingdotgg#35143)

* fix(server): Commit refuses while a merge still has conflict markers (pingdotgg#35132)

* fix(server): a pass that changes several watched pull requests wakes their thread once (pingdotgg#35109)

* fix(server): a slow file read in the search watcher no longer freezes the server (pingdotgg#35059)

* fix(shared): composer # suggestions sort by update instant, not timestamp text (pingdotgg#35137)

* fix(client-runtime): relative Markdown images in a remote thread no longer show the desktop's file (pingdotgg#35031)

* docs: the README now shows the app and gets you installed fast (pingdotgg#35170)


* fix(web): Esc in the keybindings search clears it without closing Settings (pingdotgg#35161)

* fix(web): file editor carets and selections follow code font changes (pingdotgg#35144)

* fix(server): schedule_task no longer tells agents bindToCurrentThread always defaults to true (pingdotgg#34950)

Co-authored-by: Julius Marminge <[email protected]>

* fix(web): an untouched sidebar thread rename keeps a title that arrived while it was open (pingdotgg#35174)

* fix(server): usage model details count the real unpriced tokens (pingdotgg#35179)

* perf(server): thread list reads no longer scan a long thread's runs and items (pingdotgg#35167)

Replaces pingdotgg#34747, pingdotgg#31828, pingdotgg#34666 and pingdotgg#27975.

Co-authored-by: Bogdan <[email protected]>
Co-authored-by: Michael Zhou <[email protected]>
Co-authored-by: Pyseph <[email protected]>
Co-authored-by: Braulio Oliveira <[email protected]>

* fix(server): Kiro, fx and Antigravity find a ~/ Binary path (pingdotgg#35171)

* feat(web): drop folders on the sidebar to add them as projects (pingdotgg#35202)


* fix(server): Edit from here recreates a worktree folder that lost its checkout (pingdotgg#35194)

* fix(server): a task on a linked environment stays under its parent in trimmed shell snapshots (pingdotgg#34870)

Fixes pingdotgg#30320.

Co-authored-by: Theo Browne <[email protected]>

* fix(web): terminal Ctrl+Shift+C copies on non-Latin keyboard layouts (pingdotgg#35210)

* perf(server): sending to a thread with thousands of finished subagents reads about half as much (pingdotgg#35178)

Refs pingdotgg#29468.


* fix(mobile): the thread list no longer reshuffles once per environment on startup (pingdotgg#34596)


* fix(web): a failed page in the floating browser preview shows the error instead of a blank panel (pingdotgg#35066)

* feat(web): screen reader window title leads with the thread's status and name (pingdotgg#34697)


* test(server): wire budget measures what clients fetch today, and the PR comment shows every row (pingdotgg#35225)


* fix(github): PR templates in a lowercase pull_request_template/ directory are found (pingdotgg#35212)

* perf(server): sending to a long compacted thread waits about 3x less on its history read (pingdotgg#35180)

Replaces pingdotgg#34641. Refs pingdotgg#29468.

Co-authored-by: Braulio Oliveira <[email protected]>
Co-authored-by: Theo Browne <[email protected]>

* fix(acp): new Copilot threads run the model the composer shows (pingdotgg#35199)

* perf(server): long threads open 2 to 6x faster from a cold cache (pingdotgg#35286)


* ci(release): a repo variable pauses scheduled nightly releases (pingdotgg#35287)


* fix(server): file search no longer crashes the server, and a failed Edit from here keeps your files (pingdotgg#35291)


* perf(client): threads load while the socket connects, with fewer round trips (pingdotgg#35071)

The prepare-time shell load follows the idea and structure of pingdotgg#27413.

Co-authored-by: ahalekelly <[email protected]>

* perf(server): Load earlier turns takes about half the time on a running long thread (pingdotgg#35224)


---------

Co-authored-by: Yash Singh <[email protected]>
Co-authored-by: maria <[email protected]>
Co-authored-by: Julius Marminge <[email protected]>
Co-authored-by: maria-rcks <[email protected]>
Co-authored-by: Jonas B. <[email protected]>
Co-authored-by: Saikrishna Ambeti <[email protected]>
Co-authored-by: shivam <[email protected]>
Co-authored-by: Pouya Rezvani <[email protected]>
Co-authored-by: Jaimin <[email protected]>
Co-authored-by: Etan Heyman <[email protected]>
Co-authored-by: Happy Campr <[email protected]>
Co-authored-by: Tanav Poswal <[email protected]>
Co-authored-by: Theo Browne <[email protected]>
Co-authored-by: Miley <[email protected]>
Co-authored-by: Theo Browne <[email protected]>
Co-authored-by: Phon <[email protected]>
Co-authored-by: Bogdan <[email protected]>
Co-authored-by: Michael Zhou <[email protected]>
Co-authored-by: Pyseph <[email protected]>
Co-authored-by: Braulio Oliveira <[email protected]>
Co-authored-by: ahalekelly <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched Author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants