feat(mobile): allow several new-task drafts per project - #10327
Conversation
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: unavailable · PR result: Scenario and decoded snapshot size10 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.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR changes mobile draft identity and persistence from one project slot to multiple ID-keyed drafts, adding migration, route resumption, project retargeting, attachment scoping, and recovery behavior across several production paths. The cross-cutting state and persisted-data changes have a broad runtime surface and warrant human review. Not approved because:
Review your spending limits in Billing settings. You can add or adjust custom eligibility rules. Learn more. |
New-task drafts were keyed `new-task:<environmentId>:<projectId>`, one slot per project, so starting a new task in a project always landed in whatever draft already sat there and there was no way to hold two ideas for the same repo. Web mints a draft id per draft and never had this limit; with drafts now listed in the mobile thread list the single slot became visible. Drafts are keyed `new-task:<draftId>` and carry their project in a `project` stamp (environment, project, createdAt). Legacy project-keyed entries are rewritten on load, so nothing on users' devices is lost. Each New Task entry mints a fresh draft; tapping a Draft row resumes that draft by id via a new `draftId` route param. Switching projects mid-compose retargets the same draft (text and mode choices follow, branch/worktree are cleared) instead of copy-if-empty across keys. A rejected pending task restores into its own message-keyed draft rather than merging into whatever the user is typing. Drafts list newest first by their own createdAt instead of a render-time stamp. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-ups from review on the id-keyed draft change: - composerDraftEnvironmentId read the environment out of the key, so an id-keyed new-task draft had no owner: attachment uploads never started and sign-out archival skipped the draft while cleanup deleted it. It now takes the draft and reads the project stamp, falling back to the legacy key shape only for drafts not yet migrated. - Archived signed-out drafts get the same legacy-key migration as live ones, so they surface and open after restore. - Switching environments retargets the active draft to the matched project, like switching projects does, instead of leaving the stamp on the old machine. - openDraft refuses a draft whose stamped project is not loaded rather than letting the composer fall back to the environment's first project. - The draft screen waits for draft hydration before deciding a draftId is gone, and keeps retrying while the project list is still empty, so a cold launch into a Draft row lands on it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The provider resolves selectedProject to the environment's first project before setProject ever runs, and the draft screen skips setProject when the route's project already matches. Text typed in that window had no draft to land in and was lost on cancel. Mint the draft from an effect keyed on the selected project instead of only inside setProject. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
05bff4b to
c1157a3
Compare
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
## What's Changed * fix(web): show Tux icon for WSL environments by @UtkarshUsername in pingdotgg/t3code#8511 * perf(web): speed up folder menu sorting by @AksharP5 in pingdotgg/t3code#10190 * style(web): fix inconsistencies in new settings layouts by @extoci in pingdotgg/t3code#10177 * feat(threads): persist manual active thread order by @juliusmarminge in pingdotgg/t3code#9729 * feat(mobile): arrange active threads from both thread lists by @juliusmarminge in pingdotgg/t3code#9730 * feat(web): drag threads across sections with consistent motion by @juliusmarminge in pingdotgg/t3code#9731 * feat(web): simplify sidebar drag destination cues by @juliusmarminge in pingdotgg/t3code#9750 * fix(mobile): keep pending tasks queued when a send fails in flight by @juliusmarminge in pingdotgg/t3code#10245 * feat(mobile): show new-task drafts alongside pending tasks in the thread list by @juliusmarminge in pingdotgg/t3code#10260 * feat(mobile): allow several new-task drafts per project by @juliusmarminge in pingdotgg/t3code#10327 * fix(mobile): slide settled threads out before collapsing by @StiensWout in pingdotgg/t3code#10345 **Full Changelog**: pingdotgg/t3code@v0.0.39-nightly.20260906.1303...v0.0.39-nightly.20260906.1316 Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.39-nightly.20260906.1316
Stacked on #10260 (which is stacked on #10245).
Problem
Mobile keyed new-task drafts by project (
new-task:<environmentId>:<projectId>), one slot per project. Starting a new task in a project always landed in whatever draft already sat there, so there was no way to hold two ideas for the same repo. Web mints a draft id per draft and never had this limit. With #10260 listing drafts in the thread list, the single slot became visible.Fix
Drafts are keyed
new-task:<draftId>and carry their project in aprojectstamp (environmentId,projectId,createdAt). Everything that used to read the project out of the key now reads the stamp:draftIdroute param; the screen waits for draft hydration and for the project list before deciding a draft is gone.copyComposerDraftContent*is removed.composerDraftEnvironmentIdnow takes the draft), so id-keyed drafts upload attachments and survive relay sign-out.createdAtinstead of a render-time stamp.Verification
apps/mobile:vp test runacross the draft store, list model, outbox drain/removal/editor, attachment upload queue, and thread-list suites — 239 passed.vpr typecheckpasses. Lint on touched files shows only pre-existing warnings.New tests: legacy key migration (live and archived), minting several drafts per project, retarget keeps text and clears workspace selection, environment lookup from the stamp, rejected-task restore into a stamped draft.
Before / after — starting a fresh New Task in a project that already has a draft
After — three drafts for the same project in the thread list
One migrated from a legacy project key, one already id-keyed, and one typed live and retargeted across environments. Tapping any row opens that draft.
Captured on an iPhone 17 Pro simulator with the dev client against a disposable backend; the "before" is the head of #10260 with the same seeded state. Captures were taken before the stack was rebased onto current
main(which retinted the Pending pill and reworkedcarryDraftContentTo); the rebase changed no draft behaviour shown here.Surfaces
Model: Claude Fable 5 · Harness: Claude Code in T3 Code
🤖 Generated with Claude Code