# Proof audit, pass 1 — mobile orphan-draft recovery

PR [#26800](https://git.cafe/pingdotgg/t3code/pull/26800), branch `fix/issue-26785`, reviewed head [7efa017](https://git.cafe/pingdotgg/t3code/commit/7efa01755fe32d2b36b89086e5be63305524a9b5), against main at merge-base [fe219c4](https://git.cafe/pingdotgg/t3code/commit/fe219c4de18f5ee37c28cbd3914a5569b1579156).

This is a capture specification derived from the five-file diff and its callers, not acceptance of the PR body's fixture claims. No screenshots or recordings were supplied or generated. No app, server, emulator, or lease was started. No checkout edits, pushes, or forge comments were made. Source reads were pinned to the reviewed commit where needed. This is a proof audit, not a general merge-readiness review.

## Findings first

1. **Required proof is absent.** The body describes older runs but embeds no capture. Its earlier before/after commit identifiers do not substitute for evidence tied to this base and head. All required rows below are MISSING.
2. **Destination screenshots alone cannot establish recovery.** F1, F2, F3, F4, F5, and F8 assert behavior across navigation and need recordings. A static frame of text could be a different draft or text typed after selection. Record the saved source, picker choice, destination, and the specified back/reopen actions continuously. Supplement videos with read-only local draft snapshots for identity and unchanged unrelated drafts; pixels cannot establish a draft id or absence of hidden duplication.
3. **Two destinations and three payload shapes matter.** A normal project and scratch have different hero/workspace controls. Text-only, text plus inline file/image content, and image-only with empty text exercise visibly different recovered content. The diff preserves an identity, not just a text string.
4. **Tablet is not mandatory for this change.** The changed logic has no platform, width, or tablet branch. The existing screen/host does have Android/iOS styling and adaptive split-view behavior; those are unchanged and must not be described as nonexistent. Pixel Tablet and iOS are optional smoke coverage, not prerequisites for this Android behavioral proof.
5. **The Add new project boundary remains.** The recovery picker passes no recovery id to AddProject. That flow opens its own draft. This is existing behavior and the PR body acknowledges the limit; do not claim this PR recovers an orphan into a newly created project through that UI. Adding a target through the server CLI while the picker stays open is a different operation.

No new implementation defect is asserted by this proof audit. Missing evidence is the verdict's basis.

## Reviewed render and call paths

| Changed unit | Every direct caller / output | Branches, data shapes, and interactions relevant to proof |
| --- | --- | --- |
| `NewTaskDraftScreen` | Only `NewTaskDraftRouteScreen`; that wrapper is selected by `ThreadRouteScreen` for `route.params.draft`. | Props: optional initial environment/project, branch, worktreePath, cloning; optional draftId and incomingShareId. A matching unopenable route id becomes `missing` or `pickProject`; mismatched/absent ids produce neither. `pickProject` passes the same id in replace(NewTaskProject); `missing` passes no id. An unavailable requested initial project uses the older return-to-picker path. The replace waits one animation frame after the prevent-remove guard clears, so navigation needs a recording. A late initial project cancels that older fallback. |
| `NewTaskDraftScreen`: top-level render | No selected project => null, keeping the prior surface; selected project with no selected model => fallback editor and saved-on-device notice; otherwise ThreadScreenBinding. | Normal-project hero versus scratch hero; project label truncated to one line/max 250px; environment label and connection tone/error; unavailable-share notice; clone banner only for a known non-done clone; workspace controls only for non-scratch; local/worktree icon, branch/current checkout/start-from-origin/PR label; git-known/non-git disables controls; first empty branch load says Loading branches. Hero hidden when available height <180; keyboard can reduce that height. These layouts are unchanged; F1/F5/F8 cover the recovery destinations, U10-U13 inventory the rest. |
| `NewTaskDraftScreen`: interaction/data gates | Composer text, attachments, settings come from the selected draft key. | Project chip opens picker; environment/branch controls open their routes; hardware cycle-host only when >1 environment; attachment/media/file/paste/remove; model/settings/workspace changes; clone cancel/retry/remove and error dialogs; reconnect; send/queue. Share transfer, context import, submitting lock interactions. Send gates include missing project/draft/model, empty trimmed text AND no attachments, clone, share ready/import, operate permission, upload/config failure, missing worktree branch, unavailable model, attachment cap, excessive context, cross-machine thread context, and outbox-save failure. Offline/uploading queues. Send promotes route and clears content. Those unchanged operations are not required agent turns for this PR. |
| `NewTaskRouteScreen` | Only Stack's `NewTaskProject` screen, paths `/new` and `/new/project`. | New draftId normalizes string or first string[] entry, like incomingShareId. Undefined id + draft Thread immediately below => existing setProject/goBack path. Present id bypasses that predecessor fast path, retargets on choice, then selects Thread with the id. With no predecessor and no id, select Thread with a fresh draft. Back only leaves the picker; it does not retarget. Project-row selection and successful scratch creation both call selectProject. |
| `NewTaskRouteScreen`: picker render | NewTaskHeader, ScreenContent, scroll view. | Ordinary title Choose project; incoming-share title Start a task and 0/1/many attachment subtitle (single image/file; multiple all-image versus files). Add action iff ready environment. Filter scratch-only scopes out; search trims/case-folds names/paths. Zero list scopes => empty-state panel; nonempty list but zero visible scopes => No matching projects; otherwise mapped rows. One project => workspace path; >1 in a grouped scope => N workspaces. Long title/path truncation; favicon/icon/fallback passed through. Scratch entry appears with a capable connected environment and no reserved share destination: No project row for nonempty list, Start without a project button for empty list. Existing Android/iOS padding/card/row branches and safe-area bottom inset. No changed width/theme conditional. |
| `NewTaskRouteScreen`: empty/error/time branches | deriveProjectEmptyState | Ordered: loading saved connections (spinner); no connections; available/offline/error/unsupported without snapshot (Environment unavailable or Client not supported, custom/fallback error); first connecting environment without snapshot/error (spinner); otherwise No projects found. Reserved share destination loaded disables project rows and auto-resumes; absent destination releases reservation on choice, failing with a dialog. Scratch open has in-flight double-tap guard, interrupted/failure dialog paths. Add project, Add environment, search, back, list scroll are existing interactions. |
| `NewTaskFlowProvider` | Only RootStackLayout, wrapping the navigation/layout children. Consumers: DraftScreen, RouteScreen, environment/branch context pickers, ThreadSettingsSheet, CommandPalette. | Props active, flowKey, routeDraftId. Root selects last draft Thread, normalizes draft id string/string[], and tracks whether a later Thread covers it. Inactive/default flow and active=false do not create drafts. Per-route stored state survives covering routes and is pruned when removed. Context's changed field unopenableRouteDraft is null unless an explicit route id resolves missing/pickProject; only DraftScreen reads it, comparing its own id to avoid redirecting covered drafts. Provider itself adds no visual element. |
| `new-task-flow-state.resolveRouteDraft` | Provider's render-time resolution and readFlow continuation resolution; focused unit tests. | No route id or already-bound flow => none; drafts not hydrated => pending; invalid prefix or absent project stamp => missing; matching environmentId+projectId exists => open that same draft; project absent but stamped environment still loading => pending; absent and settled => new pickProject with same id. A project's id in a different environment does not match. Pending suppresses selectedProject so it cannot temporarily use another environment. The unchanged loading helper waits for connection registry/cache/first connecting/synchronizing or empty connected shell; errors, unknown/offline/failed/reconnecting states settle. |
| Provider's unchanged derived data | Selected-project fallback, selected draft/model/workspace/environment controls. | Bound project versus first-project fallback; scratch versus normal; 0/1/many environments; draft/project/sticky/fallback model and provider options; plan-toggle support; empty/nonempty prompt/attachments; branch pending/known/git/non-git; local/worktree; online/offline; runtime/interaction modes. Existing retarget helper preserves key/content/settings/createdAt, clears project-specific workspaceSelection, and clears upload stamps when moving attachments to a different environment. New picker branch reuses that helper. |
| `new-task-flow-state.test.ts` | Test-only; no UI/render path. | Missing draft and project-gone are now separate expectations. This proves the resolver distinction, not native navigation or rendered composer content. Tests were inspected, not rerun for this pass. |

**Entry-point closure:** Unsent list actions are shared by Home, ThreadNavigationSidebar and AdaptiveWorkspaceLayout and supply `draftId`. Deep links/restored navigation can also name a draft. PR Ask, triage, prompt links and AddProject-with-prompt may supply already-created draft ids. New-thread actions from Home/project/branch actions, command palette, hardware shortcut, unavailable-thread redirect, and incoming shares can start without an id; they converge on ThreadRouteScreen or the project picker. Every producer ultimately reaches the direct callers above; no separate web/desktop implementation, contract/RPC schema, provider adapter, scheduled-task path or MCP service was changed. Existing entry producers do not need a separate recording when their identical destination props are covered.

## Real-app setup shared by required rows

Use the real Android Pixel 9 Expo dev client, portrait, one fixed native viewport and font scale 1.0. Record actual OS, pixel resolution, density/logical viewport, font scale, app variant, bundle commit and server commit in the capture manifest; do not assume the PR body's 1080x2424 metadata is the current device. Do not emulate desktop 1440px or browser 390px. Use Settings > Appearance > Light / Dark explicitly, the same theme family, rather than System mode changing unexpectedly. Do not expose pairing credentials in recordings/logs uploaded publicly.

Run the lead/capturer's fresh isolated server with T3CODE_DEV_SEED=0. Create test-only alpha and beta workspace directories under the lead's scratch area and add both projects through `t3 project add <absolute-workspace> --title alpha|beta --base-dir <isolated-T3-home>`, or the equivalent typed project mutation RPC. CLI's add output supplies project ids. Always point the CLI at that isolated T3 home; never the live install. Remove beta with `t3 project remove <beta-id-or-path> --base-dir <isolated-T3-home>` after leaving the draft. No --force is needed for a project with only local unsent drafts. The server has project metadata; drafts are local to this mobile installation and cannot be seeded by server project RPC alone.

Create drafts through the native UI, enter synthetic identifiable text, add attachments with the native picker, then Back to save in Unsent. Await the actual project removal/shell update before opening the orphan. Keep alpha and beta separate grouping scopes for core rows (separate identities/paths); otherwise the picker may show a grouped workspaces count instead of two rows. Use a selectable model without starting a paid provider turn; Send need not be pressed.

Capture fresh equivalent fixture runs on merge-base and head; do not reuse an already-retargeted draft as an orphan. Retarget is only on selection; preserve and compare local draft id, project stamp, createdAt, text, attachment identities/local bytes, and second-draft content in a read-only snapshot. WorkspaceSelection is intentionally reset on retarget and must not be asserted identical. Uploaded ids can change on a cross-environment move. Keep transcripts and raw evidence in a new timestamped run directory, never overwrite the last run.

## Required matrix

Ids F1-F4 and F8 reuse familiar labels solely for handoff; definitions here were independently derived. F5 and F6 close payload/empty-picker gaps. `D+L` means Pixel 9 portrait x dark and light. A still is sufficient only for the stated stable layout assertion, never for the preceding navigation.

| Row | Fixture / exact data | Diff relationship and expected visible result | Real-app seed / route / action | Required capture | Status |
| --- | --- | --- | --- | --- | --- |
| F1 | Text-only orphan: beta draft `26785 keep this draft`, zero attachments; alpha remains ready with selectable model. | Affected core: pickProject => choose alpha => original text in alpha composer, not an empty composer. Same draft after back/reopen, one Unsent row for it, no new content-bearing duplicate. | Shared setup; enter text in beta, Back, remove beta, open that Unsent row, choose alpha, Back, reopen same row. Manifest/snapshot proves id and retargeted stamp. | **recording**, D+L on base AND head; include source/Unsent, picker, destination, back/reopen. Extract labelled before/after destination stills from recordings. | REQUIRED — MISSING |
| F2 | Same orphan plus healthy alpha draft `26785 untouched second draft`; distinct ids. | Affected reverse path: picker Back does not change orphan stamp/content or second draft; reopening still asks for project; choosing alpha later recovers orphan. | UI-create both before removing beta. Open orphan, Back from picker, show Unsent and healthy draft unchanged, reopen orphan, choose alpha. Read-only snapshots before/after cancel establish no restamp; pixels alone do not. | **recording**, head D+L. Can continue into F1 choice, but every F2 checkpoint must be visible. | REQUIRED — MISSING |
| F3 | Healthy beta draft `26785 healthy draft`; beta and alpha both present. | Shared changed guard regression: direct open remains beta; project-chip picker cancel returns to beta with text; choosing alpha via chip keeps same text/id. | UI-create healthy beta draft, reopen from Unsent, tap project chip, Back, tap chip again, choose alpha. No recovery draftId on this ordinary picker. | **recording**, head D+L; includes direct open, cancel and switch. | REQUIRED — MISSING |
| F4 | Route naming valid-format nonexistent id `new-task:proof-26800-missing`; alpha exists, another healthy draft saved. | Shared missing branch regression: redirects to picker without retaining nonexistent id; choosing alpha yields fresh empty composer; healthy draft unaffected. Invalid-prefix id collapses to same visible missing branch. | Native app link `t3code-dev://new/draft?draftId=new-task%3Aproof-26800-missing` (use installed variant's scheme); choose alpha. This app link uses restoreDraftLinkState; it is a real-app route, not a harness. | **recording**, head D+L; start at link dispatch and show picker/empty destination. Read-only snapshot confirms no resurrection of missing id. | REQUIRED — MISSING |
| F5 | Rich orphan: 5-8 lines of unique synthetic text, one image with visible content, one small file with long name and inline reference; target alpha renamed to a long display name/path. | Affected payload/layout: retarget preserves multiline text, image preview, inline file chip/context; chosen project label truncates correctly. File content is represented by an inline chip, not a separate preview tile. | Add synthetic media/file to emulator storage, choose them through actual native picker in beta, type text, save/leave; remove beta; recover to long-name alpha. Existing workspace selection may be set in beta; alpha should resolve its own defaults. | **recording**, head D+L; show original payload, picker, destination. If text scrolls, record scrolling to show beginning/end and file/image; no unrelated UI typing after choice. | REQUIRED — MISSING |
| F6 | Orphan preserved, zero normal project scopes, connected environment ready; scratch support available. | Affected fallback context, unchanged JSX: picker says No projects found, Add new project and Start without a project; draft text must not appear spuriously as a fresh editor behind it. | Save beta draft, remove every normal test project through isolated CLI, reopen orphan. Do not remove environment (that can clear local drafts). | **destination still**, head D+L, asserting this settled picker layout only. Any claim that adding/selecting/recovering then works needs a recording. Can extract from an F8 run using the empty-list scratch entry. | REQUIRED — MISSING |
| F8 | Image-only orphan: text empty, one image; scratch-capable environment. | Affected second destination + empty-text/nonzero-attachment: choosing No project opens scratch hero What should we work on?, No project control, no project workspace controls; image survives with same draft id. Original text is intentionally empty. | In beta attach one image without typing; save, remove beta, open orphan. Choose No project when alpha remains, or Start without a project from F6. Both call startScratch/selectProject; one selection entry is enough for minimum behavioral proof, F6 still covers other layout. Back/reopen verifies saved content. | **recording**, head D+L; visible source image, choice, scratch destination, back/reopen. Manifest names which scratch entry was used. | REQUIRED — MISSING |

Minimum required set: six recording rows (F1, F2, F3, F4, F5, F8) x two themes on head = **12 head recordings**, plus F6 x two themes = **2 destination stills** (extractable from F8 if using empty picker), plus **2 base F1 recordings** and labelled base/head destination frames extracted from them. A continuous recording may cover multiple rows if all fixture identities and checkpoints are explicitly indexed; row coverage and theme coverage must remain explicit. F1 before recordings must demonstrate empty composer on base, not just start on an empty composer.

## Other distinct render families, reachability and exclusions

These rows inventory existing branches instead of multiplying unrelated controls into the recovery capture set. They have **no required capture** for this scoped change. If used to make additional claims, use the indicated evidence type. A labelled harness capture is never counted as a real native integration run.

| Row | Visually distinct branch / data | Seeding or limitation | Evidence if claimed | Status |
| --- | --- | --- | --- | --- |
| U1 | No route id / fresh composer, 0 text and 0 attachments. | Native new-thread action or `/new` picker then alpha. Healthy switch F3 and missing destination F4 already cover its shared selection branches. | Recording for creation/navigation; settled empty editor alone can use still. | EXCLUDED — unchanged, regression destination covered F4 |
| U2 | Bound flow or a second Thread covering a draft; provider active=false or own-id mismatch. | Open one healthy draft, then another detail via supported UI; back. If native UI cannot leave both draft routes stacked, use a labelled navigation harness with two draft Thread routes; no production route invented. | Recording and per-route read-only identities. | EXCLUDED — unchanged per-route binding/guard |
| U3 | Draft hydration / stamped environment first connection pending: no selected project, no wrong-environment editor. | Cold launch existing draft link; deterministic capture needs delayed draft hydration or shell delivery. A fresh already-warm single server cannot guarantee this timing; use a labelled controlled readiness harness if needed. | **Recording**, not a spinner still; drive pending -> open and pending -> settled absent. | EXCLUDED — pending rule unchanged, resolver tests already cover it |
| U4 | Zero scopes while saved connections load (spinner), or first connection loads (different spinner text). | Cold connection-registry load or new pairing. Deterministically holding those states needs labelled readiness harness/delayed network fixture; otherwise best-effort real cold launch only. | **Recording** for loading/resolution; no inferred success from a still. | EXCLUDED — unchanged |
| U5 | Zero scopes, no saved connections, Add environment. | Fresh mobile app profile with no saved connections, open `/new`. Not the orphan fixture; do not delete a recovery fixture's environment. | Destination still; recording if Add environment is exercised. | EXCLUDED — unchanged |
| U6 | Zero scopes: offline/error/unsupported without snapshot, custom/long error versus fallback error; no ready environment. | Separate empty-cache profile paired to unavailable server, rejected auth, or deliberately unsupported server. Unsupported/custom error exact shapes may require labelled catalog-state harness; cannot manufacture with project CLI alone. | Destination still; recording for disconnect/retry transition. | EXCLUDED — unchanged |
| U7 | Search with no match, or a filtered subset; No project row can remain even with no visible project rows. | Nonempty normal scopes; type nonmatching search or partial name/path; clear. | Destination still for settled layouts; **recording** for filter/clear behavior. | EXCLUDED — search/layout unchanged |
| U8 | Grouped scope >1 workspace vs singleton path; long names, paths, favicon/icon/fallback; many rows/scroll. | Seed matching repository identities across workspaces/environments and enable grouping in Settings. Unrelated repos for singleton. Seed 8+ projects for overflow. | Destination still for each layout; **recording** for scroll or grouped target selection. | EXCLUDED — count/grouping unchanged; long label sampled F5 |
| U9 | Incoming-share title/subtitle: text-only/zero attachments, 1 image, 1 file, >1 all images, >1 with file; unavailable-share notice; reserved destination disables rows and resumes. | Native Android share intent with synthetic content; reserved destination obtained through actual share import. Missing share via expired/invalid share id route. There is no UI entry combining arbitrary orphan draftId with an unrelated incomingShareId; synthetic combination must be labelled route/share harness. | Stills for stable subtitles/notices; **recording** for import/reservation, failure/retry/cancel/auto-resume. | EXCLUDED — share plumbing unchanged; replacement still forwards share id |
| U10 | Selected project, no selected model: saved-on-device fallback editor. | Separate real environment with no selectable catalog/sticky model, or cached project while configuration unavailable; fresh normal dev server may supply a model so cannot promise fixture. If unavailable, labelled server-config harness; do not claim normal ThreadScreenBinding. | Destination still for fallback text; recording if claiming recovery into it. | EXCLUDED — model fallback unchanged |
| U11 | Normal composer git/non-git, local/worktree, branch loading/current/base/PR label, clone pending/running/failed/done banner, disabled controls. | Native branch/worktree/clone UI and controlled git/non-git projects; failures via test repository. Holding first refs/clone pending deterministically may need labelled query/clone harness. | Stills for settled controls/banners; **recording** for clone actions, load, checkout, or mode change. | EXCLUDED — unchanged, normal/scratch control distinction covered F1/F8 |
| U12 | Offline/error connection tones, reconnect; uploading/failed attachments; importing share/context; submitting; permission-disabled send and provider-unavailable/validation dialogs. | Isolated server/network/permission fixtures, synthetic attachment pick/import. Submitting/failed outbox requires controlled response. Do not start a paid agent turn merely to inventory it. | **Recording** for every asynchronous/interacting claim; settled error/disabled layout alone can be a still. | EXCLUDED — all send/lock/error logic unchanged |
| U13 | Keyboard tall/short viewport (hero height <180), theme tokens, safe-area insets, Android/iOS cards/icons/dismiss modes, split columns/tablet host. | Native keyboard/rotation/device and Settings > Appearance; tablet/iOS optional separate device. Long names sampled F5. Theme is inherited, no new theme branch. | Stills for settled alternate layout; **recording** for keyboard/resize navigation. | EXCLUDED beyond Pixel 9 D+L — no changed responsive/platform path |
| U14 | Cross-environment recovery, target offline vs connected grouped scope. | Two isolated server environments, draft on A, remove project but keep environment, choose target on B. Use small image/file; helper keeps local bytes and clears old upload ids. Removing environment can delete drafts and is not this fixture. | **Recording** plus read-only before/after draft/upload metadata. | OPTIONAL EXTENSION — existing helper already handles this; no new connection-mode branch |
| U15 | Scratch creation failure/interrupted response, or missing incoming-share reservation release failure. | Controlled RPC/network failure; exact interruption and reservation failure may need labelled command harness. No synchronous project CLI creates these client operation states. | **Recording** of choice -> dialog/stay -> retry; still cannot prove recovery. | EXCLUDED — unchanged command/error handling |
| U16 | Recovery picker Add new project / Add environment; cancel back to picker. | Actual header plus/empty-state Add new project, create local project, or navigate Connections. New project opens separate draft with existing current behavior; cancel AddProject can return to recovery picker. | **Recording** for any navigation claim. | KNOWN BOUNDARY — unchanged, not accepted as recovery proof |
| U17 | Public picker route `/new?draftId=...` directly, string[] ids, invalid id, stale id removed while picker stays mounted. | Real app deep link can supply scalar id; repeated query params may parse to array (confirm parsed state), or labelled navigator harness. Artificially deleting/restamping a local draft while picker waits needs controlled local state, not server project RPC. Public direct picker can bypass resolver's hydration gate; this audit does not certify it. | **Recording** and state transcript if claimed; no ordinary-recovery equivalence assumed. | OPTIONAL ROBUSTNESS — not covered by F4's draft-screen link |

**Remaining evidence limits:** A video can show content, chosen project, cancel/back behavior, and visible duplicates. Draft id equality, retarget stamp, unrelated-draft immutability, local attachment bytes and absence of hidden duplicates require the accompanying read-only synthetic-state transcript. Unit tests cannot replace the native recordings, and old captures must not be silently attributed to this head. No fixture above authorizes edits to the app, to live state, or to the PR.

## Source anchors

All links point at the reviewed head:

- [Draft fallback and replace](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/features/threads/NewTaskDraftScreen.tsx#L277), [render families](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/features/threads/NewTaskDraftScreen.tsx#L689).
- [Picker selection and scratch](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/features/threads/NewTaskRouteScreen.tsx#L221), [picker render](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/features/threads/NewTaskRouteScreen.tsx#L321).
- [Provider draft resolution](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/features/threads/new-task-flow-provider.tsx#L248), [resolver](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/features/threads/new-task-flow-state.ts#L74), [tests](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/features/threads/new-task-flow-state.test.ts#L61).
- [Root provider and route registration](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/Stack.tsx#L500), [DraftScreen caller](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/features/threads/NewTaskDraftRouteScreen.tsx#L197).
- [Unsent entry](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/features/home/usePendingTaskListActions.ts#L20), [draft retarget helper](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/state/use-composer-drafts.ts#L1878), [draft-link restore](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/lib/appLinking.ts#L29).
- [Project CLI add/remove](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/server/src/cli/project.ts#L457), [file picker / inline references](https://git.cafe/pingdotgg/t3code/blob/7efa01755fe32d2b36b89086e5be63305524a9b5/apps/mobile/src/state/use-composer-attachment-actions.ts#L22).

FRICTION: none

VERDICT: INSUFFICIENT F1, F2, F3, F4, F5, F6, F8: no captures yet
