**Proof audit, pass 1 — findings**

- **Proof is insufficient:** the supplied evidence set is empty. No screenshot, recording, mobile run, or clone outcome is verified by this audit. The rows below are requirements derived from code, not observed results.
- Scope: [#32681](https://git.cafe/pingdotgg/t3code/pull/32681), branch `fix/issue-32667`, pinned head [bb7780ff](https://git.cafe/pingdotgg/t3code/commit/bb7780ffbe4372835053ccccebcce63ce8873c76) against merge-base [0a9abdda](https://git.cafe/pingdotgg/t3code/commit/0a9abddaee00ff1495e77a03dd4fafa73c3cd4cb). All repository reads used these objects, not the concurrently mutable worktree. This is a proof audit, not a general merge-readiness review.
- The supplied description names a different before revision, `25bf84ab`. Its unlinked claims cannot establish the requested pinned comparison. Capture the base above and the pinned head, and put full resolved SHAs in each run manifest. A later parser fix needs its own updated audit; do not label that working tree as this head.
- Web retains the raw pasted URL in the repository title, while its second line changes to the normalized clone URL. Mobile changes both title and second line because it passes `remoteUrl` as `repositoryTitle`. A web image cannot prove mobile behavior.
- `ghqCloneLayout` is a separate visible destination shape. Before, the page suffix becomes part of its nested path; after, it ends at the repository. It needs proof in addition to the default leaf-only destination.
- A repository summary proves the preview only. Record a real clone attempt showing the old page-URL failure and the new clone reaching transfer progress. A transient “Cloning” label alone does not establish that Git accepted the normalized URL.

**Fixture matrix**

Every row below requires a before/after **recording**, because it proves an input/Continue transition, destination browsing, keyboard behavior, or asynchronous clone outcome. Stills exported from recordings are useful for the PR's before/after images but do not replace the recordings. Record only the affected flow, not an entire setup session. All eight rows are the minimum set; no viewport × theme Cartesian product is required.

Inputs: **GH-page** = [the repository's `/tree/main` page](https://github.com/pingdotgg/t3code/tree/main); **GL-page** = [the runner repository's `/-/tree/main` page](https://gitlab.com/gitlab-org/gitlab-runner/-/tree/main); **clone control** = [the explicit `.git` clone URL](https://github.com/pingdotgg/t3code.git). Use these exact URLs, with no credentials. `B` means the existing, run-local `clone-base` directory described below. Web/desktop use CSS pixels. Mobile viewport means the named pooled device in portrait; record its actual logical viewport and screenshot pixel dimensions rather than assuming a simulator density.

| Row | Surface × viewport × theme | Fixture / required data | Diff affected? Expected before → after | Real-app seed and interaction | Evidence / status |
|---|---|---|---|---|---|
| W1 — GitHub default and clone outcome | Web, 1280 × 800, dark | GH-page; one connected authorized environment; empty base-directory setting; ghq off; fresh clone destinations | Yes. Raw URL remains title. Description: page URL → repository root URL. Default destination: `~/main` → `~/t3code`. Old attempt fails with a repository-not-found error naming `/tree/main`; new attempt reaches real Git transfer progress, named `t3code`. | Open normal app route `/`; Ctrl/Cmd+K → Add project → Git URL; show empty disabled Continue, paste, press Enter, pause on summary/default, then submit a fresh run-local destination ending in the displayed leaf. Keep the actual default visible before changing the parent for isolation. Record failure before; after, record transfer then use Cancel if still running. | **recording**, paired base/head; **MISSING** |
| W2 — GitLab through sidebar | Web, 1280 × 800, light | GL-page; ghq off; empty base-directory setting; zero projects initially, then one disposable local project for header branch | Yes. Raw title stays. Description: page URL → `https://gitlab.com/gitlab-org/gitlab-runner`. Default `~/main` → `~/gitlab-runner`. | From `/`, use sidebar empty-state Add project → Git URL, paste and Continue. Close; add the run-local local folder through the app, then repeat via sidebar header Add project. Both sidebar callbacks must reach the same result. Do not clone this large repository. | **recording**, paired base/head, including both sidebar branches; **MISSING** |
| W3 — explicit clone URL control | Web, 1280 × 800, dark | clone control; ghq off; empty base-directory setting | No intended difference. Title and description both retain the exact `.git` URL; destination remains `~/t3code`. | Palette Add project → Git URL; paste and click Continue (complements W1 Enter); show summary and destination; Back and reopen once to show the next flow is fresh. No network clone needed. | **recording**, paired base/head; **MISSING** |
| D1 — desktop ghq destination | Actual desktop client, 1280 × 800 content viewport, light | GH-page; selected isolated environment has `addProjectBaseDirectory=B`, ghq on; create `B/github.com/pingdotgg/` but no repository | Yes. Destination `B/github.com/pingdotgg/t3code/tree/main` → `B/github.com/pingdotgg/t3code`; summary description becomes repository root. The pinned leaf changes `main` → `t3code`. | Set environment defaults using `/settings/threads` → New projects → Add project starts in / Clone into host folders. Sidebar Add project → Git URL → paste/Continue. Show full destination by moving caret/selection if necessary, then browse up/down once and show the repository leaf stays pinned. Before may show a missing nested parent because the page suffix was part of the destination; preserve that real difference. | **recording**, paired base/head in Electron, not a browser labelled desktop; **MISSING** |
| M1 — native GitHub default and clone outcome | Pooled iOS iPhone SE (3rd generation), portrait 375 × 667 logical, dark | GH-page; one connected authorized isolated environment; ghq off; empty base-directory setting | Yes. Both summary lines: page URL → repository root URL. Destination `~/main` → `~/t3code`. Old clone fails; new clone reaches real transfer progress in the draft's clone banner. | New task → Add project → Git URL, or start at paired route `new/add-project`; paste in repository screen, show software keyboard, tap Continue. Show destination with keyboard present and dismissed, then use a fresh run-local parent while retaining the displayed leaf and tap Clone project. Record error before and actual progress after; cancel through UI if running. | **recording**, paired base/head on pooled native client; **MISSING** |
| M2 — native GitLab | Pooled Android Pixel 9, portrait, light; record actual viewport and screenshot dimensions | GL-page; ghq off; empty base-directory setting | Yes. Both summary lines normalize to repository root; destination `~/main` → `~/gitlab-runner`. Longer native text wraps within the summary card; URL subtitle is capped at two lines. | Paired `new/add-project` → Git URL; paste/Continue; show keyboard-up destination and keyboard-dismissed card/folder browser. Stop at confirmation; do not clone. | **recording**, paired base/head on pooled native client; **MISSING** |
| M3 — native explicit clone control | Same pooled iOS phone as M1, portrait 375 × 667 logical, dark | clone control; ghq off; empty base-directory setting | No intended difference. Both summary lines keep `.git`; destination remains `~/t3code`. | Native Git URL flow, paste/Continue; show destination, go Back and return once. This covers the native consumer independently of the web control. No clone needed. | **recording**, paired base/head; **MISSING** |
| M4 — native ghq and browsing | Same pooled Android Pixel 9 as M2, portrait, dark; record actual viewport and screenshot dimensions | GL-page; environment has base `B`, ghq on; create `B/gitlab.com/gitlab-org/` but no repository | Yes. Both summary lines normalize; destination `B/gitlab.com/gitlab-org/gitlab-runner/-/tree/main` → `B/gitlab.com/gitlab-org/gitlab-runner`. Pinned leaf changes `main` → `gitlab-runner`. | Set the same environment defaults through the paired web app before opening the native flow (or native Source control → Clones for ghq). Paste/Continue, show full path, browse up/down once, and show the normalized repository leaf remains pinned. Retain any actual before missing-parent error; no clone needed. | **recording**, paired base/head; **MISSING** |

**Render paths and branch inventory used to collapse the matrix**

The changed TSX component is the web `CommandPalette`; the remaining changes implement shared normalization and per-host parsers. Mobile rendering code is unchanged but consumes the shared function, so it is an affected visible surface. There are exactly two production callers of `normalizePastedCloneUrl`: web's URL-source repository submission and mobile's URL-source repository submission.

- **Web caller chain:** the app root mounts `CommandPalette(children)` → `CommandPaletteDialog(mode, session, openIntent, setOpen, openChildSearch, initialContext)` → `OpenCommandPaletteDialog` for command mode. File-picker and content-search modes render different components and do not call the changed helper. Web and Electron use this same root; Electron adds shell/native folder-picker behavior, not a different normalization implementation.
- **Every Add project entry into that chain:** root palette action via Ctrl/Cmd+K; sidebar header via `SidebarThreadHeader.onNewProject` when projects exist; sidebar empty-state button when there are no projects; `NoProjectsHero`; `DraftHeroHeadline`; pull-request-list empty-state CTA. The New project flow also has an Add existing project action that returns to the same source selection. These converge on the same palette flow; W1/W2 capture the root and both sidebar branches. Hero/empty-list CTAs need no duplicate normalization capture. Settings exposes environment defaults and source-control setup links, not a separate Git URL normalizer. The keyboard shortcut opens the root palette; no separate Add project normalization shortcut exists.
- **Web entry counts and source branches:** zero environment options shows Connect an environment; multiple options or no default shows an environment chooser; a single default proceeds to sources. Disconnected options are disabled; selecting a disconnected environment reports Environment unavailable. Source choices include Local folder, optional New project, Git URL, and provider-specific repositories. Git URL has no provider auth/lookup requirement. Provider entries can show Setup Required and open source-control settings. These guards are unchanged and are held at one connected environment in the minimum set.
- **Web repository step:** `query.trim()` empty disables Continue; nonempty enables it. Source `url` runs normalization synchronously, preserves trimmed `repositoryInput`, stores `repository:null`, switches to confirm, clears highlight, and seeds the destination. Other sources use an asynchronous repository lookup, with Working state and lookup-failure toast; their summary uses `repository.nameWithOwner` and `repository.url`. They do not call this normalizer and need no separate capture. The optional `repository` argument remains supplied by the provider branch; its behavior is unchanged.
- **Web summary:** `RemoteRepositorySummary(source,title,description)` has one production caller, only in confirm. URL source uses a link icon; other sources use host icons. Title falls back from resolved `nameWithOwner` to raw repository input; description falls back from resolved repository URL to `remoteUrl`. Both are single-line truncated spans in a flex container with `min-w-0`; their length changes visible text/clipping, not row count or geometry. GH-page, longer GL-page, and the explicit clone control cover the relevant shapes. No summary empty branch is reachable after submitting empty input. No theme or platform conditional exists inside this component.
- **Web destination/data branches:** environment-specific base defaults to `~/` when empty, otherwise an ensured directory path. Ghq off uses URL leaf; ghq on uses host plus repository path, falling back to leaf if that parser cannot represent the URL. `pinnedCloneDirectoryName` comes from remote/resolved repository data and influences folder filtering and browse navigation. Windows changes case sensitivity, path separators, and Ctrl/Command hints; desktop-local/WSL can expose a native picker footer. No Windows/WSL code changes; D1 covers the common desktop route, without requiring another OS matrix.
- **Web folder/result branches:** browse pending with no result shows Loading folders; read denial shows an alert; entries can be empty, include parent `..`, or list matching directories. Clone destination changes the directory-group heading to Select where to clone. Exact-existing versus absent destination chooses Clone versus Create & Clone; highlight changes Enter versus Ctrl/Command+Enter. Relative paths without an active project suppress results and disable submission; unsupported Windows paths have a validation toast. Normalization can change the initially browsed parent, especially ghq, so D1 keeps the actual missing-parent/result difference. No artificial loading/error delays or large directory-count fixtures are needed.
- **Web interactions and outcomes:** typing/pasting; Enter or Continue; directory click, parent, Tab and arrow navigation; Enter versus modifier+Enter with a highlighted directory; Back button or Backspace on an empty submenu; Escape/backdrop close; native picker where available. Submission requires source-control-write plus orchestration-operate grants, a connected environment, a nonempty destination, and no pending clone. Pending shows Cloning. Immediate RPC failure stays in the palette with a Clone failed toast; accepted start closes it and navigates to a project draft. Runtime running/failed/cancelled/done states render the clone banner or background toast; running has Cancel, failure has Retry/Remove, completion can open the project. The affected causal transition is failure-before versus transfer-started-after, recorded in W1; retry/remove and completed-clone behavior are unchanged and not claimed by the minimum proof.
- **Mobile callers and routes:** `AddProjectSourceRoute` renders `AddProjectSourceScreen`; `SourceControlRow` pushes `AddProjectRepository`, whose route forwards `environmentId` and `source` to `AddProjectRepositoryScreen`. That screen's two branches push `AddProjectDestination`, whose route forwards the destination props to `AddProjectDestinationScreen`. Native new-task/project-chooser CTAs, hardware-keyboard palette Add project, and New project's Add existing project path reach the source screen. Linking paths are `new/add-project`, `new/add-project/repository`, and `new/add-project/destination`. Prompt links are another destination caller but supply an explicit clone URL/title/name and bypass normalization; they are unchanged. Direct-linking to destination would bypass the bug and cannot prove this fix.
- **Mobile source/repository conditions:** environment list is shown for multiple environments or a disconnected selected one; unavailable environments get a dedicated empty state. Source readiness/permissions disable cloning rows, and discovery pending shows an activity indicator. Repository source comes from the route, defaulting to URL. Empty input disables Continue; submission sets loading and clears an error. URL source immediately normalizes then passes `remoteUrl`, `repositoryTitle:remoteUrl`, and `repositoryName:getCloneDirectoryName(remoteUrl)`. Provider source performs lookup and can show an ErrorBanner, then supplies resolved metadata. Only URL source is affected.
- **Mobile destination props and branches:** `environmentId`, `remoteUrl`, `repositoryTitle`, `repositoryName`, and optional `prompt`. String-array params use their first item. A truthy title shows the summary card; title wraps normally and the second line is capped at two lines. Missing title hides the card; missing environment shows EmptyEnvironmentState; missing URL disables Clone. Valid URL-source entry always supplies title/name/URL, so absent-prop harness states are outside this fix. Ghq is computed from the remote and per-environment settings; otherwise the repository name seeds the folder. Destination state is retained per host. Permission denial shows explanatory text and disables Clone. Path validation/RPC errors show ErrorBanner; navigation pending or clone submission disables Clone and shows loading. Successful submission awaits the projected project then opens a draft with clone controls; a projection delay can show a catch-up message. Optional prompt only prepares a draft and is unrelated.
- **Mobile folder branches/interactions:** current/parent/matching folders, empty list, initial browse spinner, denied access, browse error, and a missing-parent clone hint. Case-sensitive filtering is platform dependent on the selected server OS. Folder presses retain the pinned clone leaf; manual path edits use the path-input helper. Continue/keyboard Next, Clone/keyboard Done, native Back, keyboard-up and dismissed layouts, scrolling, and asynchronous clone banner are relevant interaction paths. M1/M2/M4 exercise these without adding unrelated error fixtures.
- **Width, theme, and native platform:** no changed style or new breakpoint exists. The web palette is capped at `max-w-xl` and both URL lines truncate; all minimum web captures use one full-width palette. Native shell uses Android/iOS-specific padding, gaps, icons, section typography, navigation and keyboard behavior, so both platforms are represented. M1's small iOS viewport stresses the keyboard and title wrapping; M2/M4 cover Android. Dark/light are distributed across fixtures rather than duplicated for every URL. Tablet/foldable and narrow mobile-web grids would test unchanged layout mechanics; they are not required for this URL fix. Record any clipping that prevents judging the URL/path, and use caret navigation or a separate still without changing the fixture.

**Parser combinations intentionally collapsed into the rows**

GH-page represents the host-restricted tree/blob family shared in appearance with GitCafe. GL-page represents GitLab's first `/-/` boundary, including nested groups and self-hosted instances. Forgejo/Gitea branch/tag/commit pages and Bitbucket source pages produce the same URL-source summary/destination structure, so they need focused parser tests, not one video per forge. A Bitbucket page previously cloned into a ref-named directory; normalization changes its folder and URL, but not the render structure. Plain explicit clones, shorthand, SSH/local paths, unknown-host no-match, `.git` suffix protection, recognized-host ownership, and ambiguous unknown-host routes are parser correctness cases. Keep those covered by tests; the `.git` control is the visible regression representative. Long refs/file paths, query/fragment stripping, userinfo, and custom ports also belong at the parser layer. Do not put real credentials in captures. The pasted ref is discarded; this fix clones the default branch, not the pasted branch.

**How to seed the real app**

All eight rows are reachable in the real app. None requires a labelled harness capture. If a capturer injects destination props, fakes clone state, stubs Git, or screenshots a standalone component, label it **HARNESS**; it cannot satisfy the integration or clone-outcome rows.

1. A capture driver creates a new timestamped run directory below `/tmp/lead-32681-r1/proof-audit-1/` for every base/head run. Keep its logs, manifest, video, exported stills, isolated T3 home, and clone destinations there. The requested `matrix.md` lives directly in the audit scratch root. Never write captures or scratch scripts into the reviewed worktree. Do not delete another run's evidence.
2. Build/run immutable base and head sources in separately authorized isolated checkouts. Do not checkout, reset, install, or start capture work in `/home/user/wt/pr-32681`, which another agent is editing. Never treat its working tree as the pinned head. This read-only audit did not create those checkouts or launch a server.
3. Launch the isolated development server with `T3CODE_DEV_SEED=0 vp run dev --home-dir <absolute-run-dir>/t3-home` and retain its PID/session. The explicit home is required to keep state out of both the reviewed checkout and the live install. Read actual ports/pairing URL from dev-runner. Never set `VITE_HTTP_URL` or `VITE_WS_URL`. Pair privately; exclude tokens/startup links from evidence and uploads.
4. Use one isolated connected environment with filesystem-read, source-control-write, orchestration-operate, and settings-write permission. Start with no projects for W2's empty sidebar. Add one disposable local folder through Add project → Local folder to expose its header button. No thread history or paid agent turn is necessary for this URL flow.
5. In web Settings → Threads (`/settings/threads`) → New projects, select the actual target environment and set Add project starts in and Clone into host folders. For normal rows use empty base/ghq false. For ghq rows use the run's existing `clone-base` as B and ghq true. Create only run-local parent folders, not repository folders. Both clients read these environment defaults; there is no need to edit a live database or live settings file.
6. W1/M1 initially show the actual home-based default for proof. Before submitting, change only the parent to a fresh run-local path and preserve the currently suggested leaf. Record that edit. This avoids touching real `~/main` or `~/t3code` while preserving evidence of the bad versus corrected default. If the destination already exists, make a new run; do not remove someone else's directory. The pinned before code forwards the page URL to real Git. A network/auth/DNS failure after normalization is not the required successful transfer evidence; record it as blocked, not passed. The old empty directory claim needs an explicit run-local filesystem listing if the PR continues claiming it; video alone does not show filesystem emptiness.
7. For native captures use the `device-pool` skill and an explicit `agent-device` proxy session: connect to the configured Simlock proxy, lease the named iOS/Android phone with that same session, and retain its returned target. Prepare the client with `vp run mobile:install <ios|android> --prepare` before leasing if needed, then install with `vp run mobile:install <ios|android> --session <session>` from the session directory. Never boot/drive an unleased simulator over SSH. Start the pinned checkout's Metro (`vp run dev:client` from `apps/mobile`) on a device-reachable origin, open the dev client with agent-device, and pair it to the isolated backend using the test-t3-mobile pairing helper. Keep the normal software keyboard. Record device/OS, actual viewport/pixel dimensions, theme, backend SHA, JS source SHA, and settings in the run manifest. A dev-client install from cache still needs Metro serving the pinned source.
8. Navigate through the source/repository screens, rather than seeding the already normalized destination via deep link. Routes can seed the source screen with the selected environment; input must pass through Git URL → Continue. Use UI automation through the shared Browser panel for web and agent-device for native. Wait on actual UI state/progress, not fixed delays used to manufacture a frame.
9. Upload recordings and before/after stills, link them by row/base/head in the PR evidence, and rerun this audit against those files. Stop only the server/Metro/recorder PIDs retained at spawn, cancel any running clone through UI, remove the disposable client connection, and close/release the device session. This pass started no processes, servers, or devices and modified no repository files.

**Pinned source anchors**

- [Web repository submission and destination derivation](https://github.com/pingdotgg/t3code/blob/bb7780ffbe4372835053ccccebcce63ce8873c76/apps/web/src/components/CommandPalette.tsx#L2003), [web summary props](https://github.com/pingdotgg/t3code/blob/bb7780ffbe4372835053ccccebcce63ce8873c76/apps/web/src/components/CommandPalette.tsx#L2931), [summary rendering](https://github.com/pingdotgg/t3code/blob/bb7780ffbe4372835053ccccebcce63ce8873c76/apps/web/src/components/CommandPaletteAddProject.tsx#L155).
- [Sidebar entry callback](https://github.com/pingdotgg/t3code/blob/bb7780ffbe4372835053ccccebcce63ce8873c76/apps/web/src/components/Sidebar.tsx#L1069), [sidebar header condition](https://github.com/pingdotgg/t3code/blob/bb7780ffbe4372835053ccccebcce63ce8873c76/apps/web/src/components/sidebar/SidebarThreadHeader.tsx#L100), [empty sidebar button](https://github.com/pingdotgg/t3code/blob/bb7780ffbe4372835053ccccebcce63ce8873c76/apps/web/src/components/Sidebar.tsx#L3657).
- [Mobile normalization and navigation](https://github.com/pingdotgg/t3code/blob/bb7780ffbe4372835053ccccebcce63ce8873c76/apps/mobile/src/features/projects/AddProjectScreen.tsx#L822), [mobile destination and summary](https://github.com/pingdotgg/t3code/blob/bb7780ffbe4372835053ccccebcce63ce8873c76/apps/mobile/src/features/projects/AddProjectScreen.tsx#L1360), [mobile route registrations](https://github.com/pingdotgg/t3code/blob/bb7780ffbe4372835053ccccebcce63ce8873c76/apps/mobile/src/Stack.tsx#L569).
- [Shared normalizer and destination helpers](https://github.com/pingdotgg/t3code/blob/bb7780ffbe4372835053ccccebcce63ce8873c76/packages/client-runtime/src/operations/projects.ts#L129), [registry URL rewriting](https://github.com/pingdotgg/t3code/blob/bb7780ffbe4372835053ccccebcce63ce8873c76/packages/source-control-core/src/shared/definition.ts#L765), [ghq path derivation](https://github.com/pingdotgg/t3code/blob/bb7780ffbe4372835053ccccebcce63ce8873c76/packages/shared/src/cloneUrl.ts#L75).

Coverage: complete pinned diff, both normalizer callers, relevant render/entry/outcome paths, and capture/seed plan. No tests, runtime verification, capture, PR mutation, or forge comments were performed. The supplied test/check claims were read but not independently rerun.

FRICTION: none

VERDICT: INSUFFICIENT W1, W2, W3, D1, M1, M2, M3, M4 (all recordings absent)
