fix(web): changing projects no longer creates a draft - #9097
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 3f5a7fa. Configure here.
| const nextLogicalProjectDraftThreadKeyByLogicalProjectKey: Record<string, string> = | ||
| Object.fromEntries( | ||
| Object.entries(state.logicalProjectDraftThreadKeyByLogicalProjectKey).filter( | ||
| ([logicalKey, mappedDraftId]) => | ||
| mappedDraftId !== draftId || logicalKey === normalizedLogicalProjectKey, | ||
| ), | ||
| ); | ||
| nextLogicalProjectDraftThreadKeyByLogicalProjectKey[normalizedLogicalProjectKey] = | ||
| draftId; |
There was a problem hiding this comment.
This is the state transition the PR's fix depends on (a retargeted draft must stop resolving from its previous logical project), but no test asserts it — the existing remap tests only check branch/worktree/env-mode. A focused case would guard the regression directly:
store.setProjectDraftThreadId(projectRef, draftId, { threadId });
store.setProjectDraftThreadId(otherProjectRef, draftId);
expect(store.getDraftThreadByProjectRef(projectRef)).toBeNull();
expect(store.getDraftThreadByProjectRef(otherProjectRef)?.draftId).toBe(draftId);Posted via Macroscope — UI Consistency
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — The PR removes the unintended draft-creation path when switching projects and keeps the existing composer session, with focused coverage for project remapping and cross-environment attachments. The remaining changes are localized cleanup and model-selection handling rather than a new workflow or schema change. You can add or adjust custom eligibility rules. Learn more. |
Changing projects while a prompt is being typed should update the current draft's destination instead of creating another draft. Retarget the active draft in place and remove the old prompt/attachment transfer path.
3f5a7fa to
4dd676d
Compare
|
Codex on behalf of @extoci: addressed the review findings in 4dd676d.\n\n- Cross-environment retargets clear stale upload metadata, so hydrated files cannot reuse an upload from the old environment.\n- In-place retargets reapply sticky and destination-project defaults unless the composer selection is explicit.\n- Added focused regression coverage for stale uploads, destination remapping, and explicit-selection handling. |
## What's Changed * Add mobile composer attachment menu with video support by @juliusmarminge in pingdotgg/t3code#8843 * fix(web): restore unified activity logs and composer banners by @t3dotgg in pingdotgg/t3code#8734 * fix(web): address composer banner review follow-ups by @juliusmarminge in pingdotgg/t3code#8850 * fix(web): widen sync banners and simplify the working timer by @juliusmarminge in pingdotgg/t3code#8855 * fix(preview): improve browser recording quality by @maria-rcks in pingdotgg/t3code#8839 * fix(web): mark pull request links as external by @juliusmarminge in pingdotgg/t3code#8856 * fix(mobile): replace Callstack glass with Expo glass by @juliusmarminge in pingdotgg/t3code#8862 * fix(server): skip IDE detection in Claude probes by @yashranaway in pingdotgg/t3code#8634 * chore(macroscope): review diagnostic overrides by @t3-code[bot] in pingdotgg/t3code#8917 * fix(contracts): accept CLI event origins by @nateEc in pingdotgg/t3code#8905 * fix(web): hide invalid slash skill completions by @nateEc in pingdotgg/t3code#8904 * fix(mobile): defer draft navigation until submission completes by @juliusmarminge in pingdotgg/t3code#8914 * chore: disable CodeRabbit review status by @juliusmarminge in pingdotgg/t3code#8933 * Delete app.json by @juliusmarminge in pingdotgg/t3code#8934 * fix(web): show scrollbar for wide markdown tables by @UtkarshUsername in pingdotgg/t3code#8868 * fix(mobile): shimmer active tool rows by @juliusmarminge in pingdotgg/t3code#8932 * chore(deps): bump Electron to 43.4.1 by @StiensWout in pingdotgg/t3code#8626 * fix(chat): smooth worktree setup status by @juliusmarminge in pingdotgg/t3code#8922 * feat(mobile): add video playback with native iOS controls by @juliusmarminge in pingdotgg/t3code#8919 * fix(web): prevent chat metadata overlap by @MatthewFeroz in pingdotgg/t3code#8851 * fix(server): preserve usage cache outside walked roots by @Lucenx9 in pingdotgg/t3code#8540 * feat(mobile): add native image and PDF previews by @juliusmarminge in pingdotgg/t3code#8959 * fix(server): allow long thread IDs in HTTP routes by @nateEc in pingdotgg/t3code#8898 * fix(shared): preserve Windows shell PATH priority by @UtkarshUsername in pingdotgg/t3code#8748 * fix(web): make WSL settings searchable by @UtkarshUsername in pingdotgg/t3code#8881 * feat(web): add expand/collapse all control to the files surface by @UtkarshUsername in pingdotgg/t3code#8889 * feat(mobile): upload attachments while composing by @juliusmarminge in pingdotgg/t3code#8978 * fix(chat): keep agent activity visible between actions by @maria-rcks in pingdotgg/t3code#8984 * fix(server): isolate remote web session cookies by @Bil0000 in pingdotgg/t3code#8085 * feat(pull-requests): link GitHub references in markdown by @maria-rcks in pingdotgg/t3code#8812 * perf(server): reduce frequency of full tool call output being loaded into memory from db by @t3dotgg in pingdotgg/t3code#8988 * feat(web): add pull request list filters by @maria-rcks in pingdotgg/t3code#8809 * feat(web): search individual settings by detail by @maria-rcks in pingdotgg/t3code#8831 * feat(client): render viewed images in work logs by @maria-rcks in pingdotgg/t3code#8936 * fix(client): use package import for markdown image helpers by @juliusmarminge in pingdotgg/t3code#9010 * test: remove static presentation snapshots by @t3-code[bot] in pingdotgg/t3code#9008 * perf(server): bound snapshot activity payload memory by @t3dotgg in pingdotgg/t3code#9000 * perf(server): cut idle CPU use and stop provider event leaks by @t3dotgg in pingdotgg/t3code#8187 * perf(server): scan only appended transcript bytes for usage summaries by @StiensWout in pingdotgg/t3code#9024 * perf(server): cut chatty tool-update frames by 90% by @Adamulek123 in pingdotgg/t3code#8368 * fix(server): settle threads server-side by @t3dotgg in pingdotgg/t3code#8600 * fix(clients): dedupe skills in composer menus by @Adamulek123 in pingdotgg/t3code#8043 * fix(server): stop OpenCode child sessions by @t3dotgg in pingdotgg/t3code#9005 * perf(web): defer pull request line stats until visible by @Adamulek123 in pingdotgg/t3code#6471 * perf(server): skip full-message reads while streaming by @t3dotgg in pingdotgg/t3code#9032 * perf(client-runtime): halve server config bootstrap traffic by @Adamulek123 in pingdotgg/t3code#8367 * fix(web): align un-settle banner action by @StiensWout in pingdotgg/t3code#9033 * fix(web): block type-to-focus behind open dialogs by @Lucenx9 in pingdotgg/t3code#8139 * feat(shortcuts): copy active thread reference by @maria-rcks in pingdotgg/t3code#8994 * fix(mobile): keep thread scroll bounds current after animations by @juliusmarminge in pingdotgg/t3code#9013 * fix(server): cache project favicon resolution by @willsheldon in pingdotgg/t3code#9080 * feat(claude): add Claude Fable 5.1 model by @q1 in pingdotgg/t3code#9078 * fix(preview): restore recording and macOS rendering after Electron 43 by @StiensWout in pingdotgg/t3code#9001 * feat(desktop): add configurable quit shortcut confirmation by @juliusmarminge in pingdotgg/t3code#9076 * feat(web): open project settings from thread menus by @SunkenInTime in pingdotgg/t3code#8925 * fix(chat): reuse one row for live activity by @maria-rcks in pingdotgg/t3code#9062 * feat(models): discover Claude models from remote manifest by @juliusmarminge in pingdotgg/t3code#9084 * Revert "fix(chat): reuse one row for live activity" by @maria-rcks in pingdotgg/t3code#9096 * fix(web): sync sidebar PR state from open panel by @t3-code[bot] in pingdotgg/t3code#9092 * fix(web): changing projects no longer creates a draft by @extoci in pingdotgg/t3code#9097 * fix(web): keep theme placeholder text dimmer than entered text by @flamboh in pingdotgg/t3code#9104 * fix(web): keep the selected environment when changing projects by @t3dotgg in pingdotgg/t3code#9102 ## New Contributors * @willsheldon made their first contribution in pingdotgg/t3code#9080 * @q1 made their first contribution in pingdotgg/t3code#9078 **Full Changelog**: pingdotgg/t3code@v0.0.37...v0.0.38 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.38

Changing projects while a prompt had been typed used to create a draft and move the prompt into it. That was confusing and unnecessary, this fixes it (videos below).
Keep the existing draft and composer session. Changing projects now retargets the draft logical-project mapping in place; leaving the draft still triggers the normal persistence behavior. Remove the transfer workaround and its tests.
Before
Screen.Recording.2026-09-02.at.12.00.42.AM.mov
After
Screen.Recording.2026-09-01.at.11.59.16.PM.mov
Verification: 116 focused tests passed, plus targeted lint and web typecheck.
Built by Codex on behalf of @extoci.
Note
Medium Risk
Touches composer draft identity, project mapping, and cross-environment attachment metadata; behavior change for project switching is user-visible but removes a confusing draft-creation path rather than altering send/auth flows.
Overview
Changing the project from the draft hero headline no longer mints a new thread or sidebar draft row. The picker retargets the same
draftIdviasetLogicalProjectDraftThreadId, so typed prompt and attachments stay in the current composer session; a sidebar draft only appears if the user navigates away later.The old path—
handleNewThreadwithcarryComposerContentandmoveComposerPromptAndImages—is removed from the store anduseNewThreadHandler, along with related upload-queue tests and attachment-stay-behind toast behavior.Draft store updates for in-place retargeting: reassigning a draft clears any other logical-project key still pointing at that
draftId, and when the target project’s environment changes, file rows drop cross-environment upload metadata so attachments surface as needing reattach. Model defaults still apply via sharedhasExplicitComposerModelSelectionwhen the user hasn’t explicitly picked a model.Reviewed by Cursor Bugbot for commit 4dd676d. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Retarget open draft to selected project in place instead of creating a new draft
DraftHeroHeadlinenow callssetLogicalProjectDraftThreadIdto retarget the currently open draft to that project, preserving the prompt and session.moveComposerPromptAndImagesstore method and all related carry-content logic fromuseNewThreadHandler; new thread creation no longer moves content from the viewed draft.clearStaleFileUploadMetadataso retargeting a draft to a different environment clearsuploadedAttachmentIdanduploadEnvironmentId; affected files reportcomposerFileNeedsReattach.hasExplicitComposerModelSelectionto centralize explicit-model detection; when the current draft lacks an explicit pick, retargeting applies the project's default model.moveComposerPromptAndImagesis removed fromComposerDraftStoreState; any out-of-tree callers relying on it will break. Retargeting also removes the draft's previous logical-project mapping and clears cross-environment file upload metadata.Macroscope summarized 4dd676d.