Port upstream thread-performance improvements (top 10 + fixes) - #317
Merged
Conversation
Ports three upstream t3code changes: - gzip large JSON HTTP responses behind HttpResponseCompression (native node:zlib on Node, CompressionStream on Bun) with Accept-Encoding q-value parsing and Vary handling (upstream #4788, #4798) - drop all but the last resolvable context-window activity per turn from thread detail snapshots; live events untouched (upstream #4791) - preserve image view/generation item type and path while pruning base64 image bytes from activity payloads (upstream 0a9ea4bbe) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports upstream t3code #4177: - coalesce the shared shell firehose per aggregate over a 50ms/512-event window with bounded refetch concurrency, so bursts of streaming deltas collapse into one shell refetch and never serialize a new thread's thread.created behind per-event DB reads - upsert-or-remove projection reads: a refetch that returns none emits a removal (with one retry on read failure) so coalescing a delete into a later event still drops the row on clients - subscribeShell resume: cap catch-up replay at SHELL_RESUME_MAX_GAP (1000) events; beyond that (or a cursor ahead of the head) send one fresh snapshot instead of an unbounded replay, and bound the replay read to the head captured at subscribe time - completion marker rides the live buffer so events observed during snapshot/replay are delivered before the synchronized signal - OrchestrationEngine.latestSequence exposes the committed head sequence Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports upstream t3code #4705: patch @effect/platform-node and @effect/platform-bun (4.0.0-beta.78) to enable permessage-deflate on the WS server. Node keeps context takeover (shared compression window across frames); Bun uses a dedicated compressor with the shared decompressor to avoid uWebSockets' close-1006 on valid DEFLATE input (uWebSockets.js#633). Clients that do not offer the extension still get uncompressed frames. Upstreamed as Effect-TS/effect#6691 — ships natively in platform >= 4.0.0-beta.103; drop the patches on the next Effect upgrade. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The mac client re-downloaded a full snapshot frame for the shell and for every open thread on each reconnect. Adopt the resume protocol the server already speaks (upstream t3code #3719/#4163 lineage): - track lastShellSequence from shell snapshots/events and pass it as subscribeShell(afterSequence:); the server replays only missed shell events, emits removals for aggregates deleted while disconnected, and falls back to a fresh snapshot past its gap cap — which the existing snapshot reconcile path already handles - sequence-gate live shell events (replay/live overlap on resume) - resume subscribeThread with the tracked lastThreadSequence when the in-memory timeline state is still intact; fresh opens and post-eviction reopens still take the full snapshot so timeline() waiters resolve Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports two upstream t3code changes: - thread feed rows no longer eagerly build expanded-body and copy text for every work-log entry (JSON.stringify of tool data per row); rows expose canExpand plus memoized getFullDetail()/getCopyText() thunks evaluated on expand/copy only (upstream #4607) - settled threads render 10 rows per project group initially and page by 25 via a show-more row, resetting on environment/search changes, instead of materializing the whole settled set (upstream Thread List v2 paging pattern) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports upstream t3code #4727. listRefs ran a fresh set of git branch/for-each-ref/worktree subprocess batches per call, so N concurrent consumers of one repo caused N subprocess storms. Now a ref-snapshot cache keyed by git-common-dir single-flights concurrent scans, a short TTL keeps warm snapshots, and every mutating git operation invalidates the snapshot. Repository path lookups coalesce the same way, and the background upstream-fetch used for status backs off exponentially (30s to 15min per remote) instead of retrying an unreachable remote every 5s. The refresh flag stays a server-local input extension until a client needs it over the wire. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Snoozing (ports upstream t3code #4311, backend only): snooze is an overlay on the active lifecycle, not a fourth destination. thread.snooze carries an ISO wake time; clients suppress the thread until snoozedUntil passes (timer wakes emit no event) and the decider emits thread.unsnoozed(reason: "activity") when a user message arrives. Covers contracts (commands/events/shell+thread fields, threadSnooze capability), decider with lifecycle-reset extraction, projector, projection pipeline/query, migration 040, and client-runtime commands/reducer/threadSettled additions, with the upstream decider and snoozed-state test suites. replayEvents (ports upstream t3code #4791 part 2): the RPC is dead — TS clients resume via afterSequence catch-up and mac now does the same — so drop the contract, the ws.ts handler (which collected an unbounded event tail into memory), the project-event enrichment machinery only it used, and its tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Snoozing: T3Kit gains thread.snooze/thread.unsnooze commands and the snoozedUntil/snoozedAt shell fields; the sidebar context menu offers a Snooze submenu (1 hour, 3 hours, tomorrow 9 AM, a week) and Wake for snoozed threads. Snoozed threads ride the settled disclosure until the wake time passes — a passed snoozedUntil simply stops classifying as snoozed on the next evaluation, mirroring the server contract where timer wakes emit no event. replayEvents: remove the never-called client wrapper and input model; reconnect catch-up is the afterSequence resume cursor on each stream. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Snoozed threads leave the active list (home, navigation groups, scenery occupancy) via a single isThreadOutOfInbox choke point and rejoin the settled section with a moon icon and a snoozed-until hint. Long-press menu offers Wake or Snooze presets (1 hour, this evening, tomorrow 9am, next week — upstream Sidebar.snooze.ts semantics), dispatched through the client-runtime snooze/unsnooze commands with the same in-flight guard and failure alert as settle. A passed wake time reappears without any event. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ports the full top-10 list from
plans/upstream-thread-perf-catchup.md(PR #316) — the thread-performance and thread-data improvements upstream t3code landed after our fork point — plus the bonus image-path fix. All upstream refs are t3code PR numbers.Server transport
application/jsonbodies, fullAccept-Encodingq-value parsing,Varyhandling; nativenode:zlibon Node /CompressionStreamon Bun behind anHttpResponseCompressionservice. Thread/shell snapshot endpoints now compress (~10x on large threads).@effect/platform-node/-bun@ beta.78 to negotiate compression (Node keeps context takeover; Bun uses dedicated compress + shared decompress to dodge uWebSockets close-1006). Ships natively in platform ≥ beta.103 — drop the patches on the next Effect upgrade.Server data volume
context-window.updatedactivity per turn — long threads previously shipped thousands of rows clients never read.0a9ea4bbe): fixes a live bug where pruned image view/generation activities lost their type+path and chat galleries rendered blank; base64 bytes stay pruned.OrchestrationEngine.latestSequenceexposes the committed head.Mac client
afterSequenceresume for shell and thread subscriptions: reconnects replay only missed events instead of re-downloading full snapshot frames; sequence-gated replay/live overlap; fresh opens and post-eviction reopens still take the full snapshot. NewLiveBackendShellResumeTests.Mobile
canExpand+ memoizedgetFullDetail()/getCopyText()thunks instead of eagerly JSON-stringifying every entry's tool data at feed build.Git
Thread snoozing (#4311, full stack)
Snooze is an overlay on the active lifecycle:
thread.snoozecarries a wake time, clients suppress the thread untilsnoozedUntilpasses (timer wakes emit no event), and the decider wakes it on real activity. Contracts, decider/projector/persistence (migration 040), client-runtime commands + state, mac sidebar Snooze/Wake menu (presets: 1h / 3h / tomorrow 9 AM / a week), and mobile long-press menu + moon-icon row hint.Verification
pnpm run verify --allgreen: vp check, typecheck, full TS test suite, mac Swift suite (735 tests incl. new resume/snooze coverage), lint:mobile.🤖 Generated with Claude Code