Skip to content

perf(web): defer composer draft serialization - #9695

Merged
t3dotgg merged 2 commits into
mainfrom
t3code/perf-web-draft-persistence
Sep 4, 2026
Merged

perf(web): defer composer draft serialization#9695
t3dotgg merged 2 commits into
mainfrom
t3code/perf-web-draft-persistence

Conversation

@t3dotgg

@t3dotgg t3dotgg commented Sep 4, 2026

Copy link
Copy Markdown
Member

Typing serializes every saved web draft, including image bytes, before the storage debounce runs.

Capture the immutable state and defer the draft walk and JSON serialization until the write flushes. Keep hydration, migrations, attachment verification, and final flushes. Clear canceled state references.

This continues the web portion of #9049 by @StiensWout. His Git authorship and the existing co-author trailer are preserved. The mobile storage migration remains separate. The original PR is unchanged.

The real store test verifies that 20 prompt updates cause no saved-attachment reads or JSON serialization before one flush. The final prompt, image data, and assistant citations restore correctly. All 107 focused tests, web typecheck, and targeted lint pass. No browser or device was used. The original PR's browser recording is not new verification.

Part of #9661.

Created with GPT-6 Astra (preview) in Codex.


Note

Medium Risk
Changes when and how composer drafts are written to localStorage; behavior depends on flush/rehydrate paths staying correct, but migrations and unload flush are preserved.

Overview
Composer draft persistence no longer walks drafts or runs JSON.stringify on every keystroke. Zustand partialize now only captures the live store snapshot; the custom persist storage runs partializeComposerDraftStoreState and stringifies inside createDeferredStorage when the 300ms debounce fires or on beforeunload flush.

createDebouncedStorage is replaced by createDeferredStorage, which debounces typed values and applies a injected serialize at write time. removeItem cancels the debouncer and reset() so canceled writes cannot flush stale snapshots.

Tests call the exported partializeComposerDraftStoreState directly, exercise real store rehydrate with fake timers, and assert rapid typing does not read heavy attachment data or stringify until one flush.

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

Note

Defer composer draft serialization to reduce writes during rapid typing

  • Introduces a deferred storage wrapper (createDeferredStorage) that serializes and writes to base storage only when the debounce fires, not on every draft update
  • Rapid prompt updates with large image attachments no longer trigger repeated attachment traversal or JSON serialization per keystroke
  • Exports partializeComposerDraftStoreState so tests call the partializer directly instead of reaching into persistence middleware options
  • Behavioral Change: pending writes that are canceled by removeItem or superseded by a new value skip serialization entirely; flush serializes and writes synchronously
📊 Macroscope summarized 17e2c91. 2 files reviewed, 1 issue evaluated, 1 issue filtered, 0 comments posted

🗂️ Filtered Issues

apps/web/src/composerDraftStore.ts — 0 comments posted, 1 evaluated, 1 filtered
  • line 103: composerPersistStorage.getItem calls JSON.parse without handling malformed localStorage. The previous createJSONStorage path intentionally treated malformed composer storage as empty (and the existing test covers that case); now a truncated/corrupt t3code:composer-drafts:v1 value throws during persist hydration rather than falling back to an empty draft store, preventing drafts from hydrating until the user manually clears site storage. [ Out of scope (triage) ]

StiensWout and others added 2 commits September 4, 2026 07:38
Import the web portion of commit 5a157c0.
Keep its author and co-author credit. Mobile storage changes remain in the source PR.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

Provider Metric Main baseline This PR Impact PR ceiling
Codex Total thread wire 13.7 KiB 13.6 KiB −177 B (−1.3%) 15.1 KiB
Codex Thread snapshot wire 7.0 KiB 7.0 KiB −2 B (−0.0%) 7.3 KiB
Codex Live turn WebSocket wire 6.7 KiB 6.5 KiB −175 B (−2.5%) 7.8 KiB
Codex Live turn WebSocket decoded 58.5 KiB 57.0 KiB −1.5 KiB (−2.5%) 66.4 KiB
Codex Live turn messages 10 9 −1 (−10.0%) 21
Claude Total thread wire 13.5 KiB 13.6 KiB +77 B (+0.6%) 15.1 KiB
Claude Thread snapshot wire 7.0 KiB 7.0 KiB −2 B (−0.0%) 7.3 KiB
Claude Live turn WebSocket wire 6.5 KiB 6.6 KiB +79 B (+1.2%) 7.8 KiB
Claude Live turn WebSocket decoded 57.8 KiB 57.9 KiB +88 B (+0.1%) 66.4 KiB
Claude Live turn messages 8 10 +2 (+25.0%) 21

Baseline: 2460649 · PR result: 17e2c91 · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 113.8 KiB
  • Claude decoded thread snapshot: 114.5 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@t3dotgg t3dotgg mentioned this pull request Sep 4, 2026
66 tasks
@macroscopeapp

macroscopeapp Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at 17e2c91

Macroscope's review found this PR approvable — The PR narrowly defers existing composer draft traversal and JSON serialization without changing the persisted format, debounce interval, or user-facing capabilities. Its runtime impact is isolated to local draft persistence and is covered by focused round-trip, flush, cancellation, and deferred-work tests.

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

@t3dotgg
t3dotgg merged commit dab5f6e into main Sep 4, 2026
23 checks passed
@t3dotgg
t3dotgg deleted the t3code/perf-web-draft-persistence branch September 4, 2026 14:50
Olivier-OG added a commit to Olivier-OG/t3code that referenced this pull request Sep 4, 2026
* upstream/main: (30 commits)
  perf(server): use one query for buffered provider events (pingdotgg#9706)
  perf(server): stop rebuilding terminal history per chunk (pingdotgg#9703)
  perf(marketing): serve website fonts locally (pingdotgg#9701)
  perf(web): defer diff workers until a code view opens (pingdotgg#9692)
  perf(server): avoid full patches for checkpoint summaries (pingdotgg#9694)
  perf(marketing): stop continuous homepage motion (pingdotgg#9697)
  feat(server): measure provider turn token usage (pingdotgg#9132)
  perf(web): defer composer draft serialization (pingdotgg#9695)
  perf(mobile): reuse diff rows during comment edits (pingdotgg#9693)
  perf(clients): avoid waiting to read cached relay tokens (pingdotgg#9691)
  perf(server): omit repeated OpenCode progress logs (pingdotgg#9689)
  perf(mobile): reuse chat feed rows during streaming (pingdotgg#9688)
  perf(server): stop retaining unused OpenCode tool history (pingdotgg#9684)
  perf(server): batch projector cursor writes (pingdotgg#9671)
  perf(server): cache and stream static web assets (pingdotgg#9669)
  perf(marketing): serve images at their display size (pingdotgg#9682)
  perf(mobile): skip unused legacy list work (pingdotgg#9679)
  perf(web): keep Markdown mounted during streaming (pingdotgg#9677)
  perf(mobile): bound diff syntax highlighting work (pingdotgg#9673)
  fix(web): show machine icons in the environment picker (pingdotgg#9668)
  ...
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Sep 4, 2026
## What's Changed
* fix(desktop): quit immediately on a second shortcut press by @t3dotgg in pingdotgg/t3code#9657
* fix(server): update Claude Agent SDK to 0.3.260 by @t3dotgg in pingdotgg/t3code#9135
* perf(server): stop loading message bodies for thread summaries by @t3dotgg in pingdotgg/t3code#9662
* perf(web): speed up terminal snapshots by @t3dotgg in pingdotgg/t3code#9663
* fix(web): show machine icons in the environment picker by @t3dotgg in pingdotgg/t3code#9668
* perf(mobile): bound diff syntax highlighting work by @t3dotgg in pingdotgg/t3code#9673
* perf(web): keep Markdown mounted during streaming by @t3dotgg in pingdotgg/t3code#9677
* perf(mobile): skip unused legacy list work by @t3dotgg in pingdotgg/t3code#9679
* perf(marketing): serve images at their display size by @t3dotgg in pingdotgg/t3code#9682
* perf(server): cache and stream static web assets by @t3dotgg in pingdotgg/t3code#9669
* perf(server): batch projector cursor writes by @t3dotgg in pingdotgg/t3code#9671
* perf(server): stop retaining unused OpenCode tool history by @t3dotgg in pingdotgg/t3code#9684
* perf(mobile): reuse chat feed rows during streaming by @t3dotgg in pingdotgg/t3code#9688
* perf(server): omit repeated OpenCode progress logs by @t3dotgg in pingdotgg/t3code#9689
* perf(clients): avoid waiting to read cached relay tokens by @t3dotgg in pingdotgg/t3code#9691
* perf(mobile): reuse diff rows during comment edits by @t3dotgg in pingdotgg/t3code#9693
* perf(web): defer composer draft serialization by @t3dotgg in pingdotgg/t3code#9695
* feat(server): measure provider turn token usage by @t3dotgg in pingdotgg/t3code#9132
* perf(marketing): stop continuous homepage motion by @t3dotgg in pingdotgg/t3code#9697
* perf(server): avoid full patches for checkpoint summaries by @t3dotgg in pingdotgg/t3code#9694
* perf(web): defer diff workers until a code view opens by @t3dotgg in pingdotgg/t3code#9692
* perf(marketing): serve website fonts locally by @t3dotgg in pingdotgg/t3code#9701
* perf(server): stop rebuilding terminal history per chunk by @t3dotgg in pingdotgg/t3code#9703


**Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260904.1278...v0.0.39-nightly.20260904.1279

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260904.1279
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:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants