# Proof audit fixture matrix, pass 1

PR [#32471](https://git.cafe/pingdotgg/t3code/pull/32471). Audited head [a9e98bb900](https://git.cafe/pingdotgg/t3code/commit/a9e98bb900462e8f872202cd8792a0b398c770a3), base [80e62619f5](https://git.cafe/pingdotgg/t3code/commit/80e62619f5c01d84579bcf70ea6d566712007412). Existing captures: after [ef5e92da9a](https://git.cafe/pingdotgg/t3code/commit/ef5e92da9af2370c00703da39b108e87fbb920ec), before [d313b2aff3](https://git.cafe/pingdotgg/t3code/commit/d313b2aff31991ab94c8ac80cdc38a54dd575604).

## Findings

No missing or contradicted mandatory row. No recapture is required by the merge. All existing captures remain valid for their stated historical revisions and continue to demonstrate this patch through source equivalence. This is a source-based carry-forward decision, not a claim that the application was run at the new head. Keep the original media revision labels; add this audit as the provenance bridge if the PR body is updated.

The raw five-file patch is byte-for-byte identical across the old and new revision pairs (SHA-256 c9a86ecbc6ead17bfcdd43f5b3a4dc096d8923b3f7e27e7d47989b8f212b8515). Each of the five changed files has the identical Git blob on the two after revisions, and on the two before revisions. The entire merge delta is also identical on the before and after sides. This avoids attributing unrelated main changes to the fix.

The merge changes 21 files, but changes no web or desktop source, client runtime, contracts, workspace resolver, workspace registry, WS handler, Claude scanner, project service, worktree-path recognition, Git workflow, or turn-start service/test. It changes files containing two relevant services, but not their exercised methods: ThreadManagementService only extracts the equivalent active-run status list; Orchestrator changes delegated-completion acknowledgement; ProjectionStore changes canonical run/node/subagent/message-record queries. The resolver uses the unchanged readShellSnapshot -> readShellSnapshotRows -> selectShellThreadRows path, including its exact worktreePath filter and active/archived shell split. It does not use the altered canonical-record queries. The recreation harness mocks projection services and executes the unchanged turn-start and Git code. Thus none of B1/F1/F2/F3/R1 exercises a changed render or server behavior from the merge.

The merge's native mobile insets/feed edits could change mobile captures; there are no native mobile captures in this evidence set. The 390x844 image is a resized web Chromium viewport, not native mobile. Pi model parsing, SSH tunnel handling and MCP task-read changes are outside the local Claude discovery fixtures. No native-mobile, Pi, SSH or MCP result is certified by the historical captures.

## Code-derived paths and branch inventory

No React component changes in the PR. Its production changes are:

1. [workspaceScanDirectory](https://git.cafe/pingdotgg/t3code/blob/a9e98bb900462e8f872202cd8792a0b398c770a3/apps/server/src/project/threadWorkspaceRoot.ts): sole caller is the workspace branch of server.refreshProviders. A present cwd, or an exists failure, returns cwd. A missing unmanaged cwd returns cwd. A missing managed cwd reads matching active plus archived shells, chooses the first shell with branch !== null, then returns that project's workspaceRoot. No eligible owner, absent project, or resolver failure returns cwd. A selected root need not exist. Managed recognition includes default, current and previous configured roots, symlink resolution, absolute normalized paths and exactly two path components under the managed root.
2. [ProviderRegistry.refreshWorkspaceSnapshot](https://git.cafe/pingdotgg/t3code/blob/a9e98bb900462e8f872202cd8792a0b398c770a3/apps/server/src/provider/ProviderRegistry.ts): sole production caller is the same WS branch. Only the scanner argument changes to scanCwd ?? cwd; snapshot ownership, cache, TTL and deduplication remain keyed by requested cwd. Unknown/disabled provider, fresh versus current/expired/pending snapshot, absent scanner, scan failure/recovery, concurrent requests and all returned snapshot fields remain relevant controls. Fresh also invalidates provider caches. Snapshot metadata, commands, skills and option descriptors are retained, rather than copying only skills.
3. [WS handler](https://git.cafe/pingdotgg/t3code/blob/a9e98bb900462e8f872202cd8792a0b398c770a3/apps/server/src/ws.ts): fallback is used only with both cwd and instanceId, except modelCatalogOnly returns earlier. Refresh-all/instance-only, reloadSecrets and model refresh retain their existing branches. On-demand responses filter to requested provider/cwd and can synthesize a pending machine catalog on scan failure; legacy replies return all providers. Neither reply branch changes its wire shape.

The shared refresh command in [client state](https://git.cafe/pingdotgg/t3code/blob/a9e98bb900462e8f872202cd8792a0b398c770a3/packages/client-runtime/src/state/server.ts) reaches that WS handler. Its cwd-keyed result feeds [providerSkills](https://git.cafe/pingdotgg/t3code/blob/a9e98bb900462e8f872202cd8792a0b398c770a3/packages/client-runtime/src/providerSkills.ts), resolving both skills and slash commands for the original worktree key. The same RPC applies regardless of local/remote/tunnel transport. No transport changed in the patch.

Web/desktop path: ChatView -> ChatComposer -> useProviderWorkspaceSnapshotRefresh and useComposerMenuItems -> ComposerCommandMenuLayer -> ComposerCommandMenu. ComposerCommandMenu has one production caller, ChatComposer. There is no second skill-list renderer in Settings or CommandPalette; Settings changes the slash-menu visibility flag. Typing and mount trigger refresh; pointer selection or keyboard Enter/Tab call the same selection handler; arrows change highlight, Escape dismisses, and active-row changes scroll the existing list.

Relevant web branches: trigger absent/hidden versus $ versus slash; zero results with loading text versus zero results settled; one or many rows; enabled/user-invocable filtering and case-insensitive deduplication; search match versus no match; slash visibility on/off; provider command versus slash skill versus dollar skill; description fallback (shortDescription, description, scope/hint/default); display label and source badge; active highlight; selection inserts token plus space and closes the menu. Dollar skill says Project Skill, slash skill says Project, provider command has no skill badge. The menu shows existing items even while loading. Height caps at 18rem; label caps at 45%, label/description truncate; positioning depends on anchor, font size, available height and viewport width. Light/dark uses existing theme tokens. Other item types (paths, threads, models, PRs, environments) do not consume this changed inventory.

Native path: ThreadComposer -> useComposerCommandMenu -> ComposerCommandPopover, using the same cwd-keyed shared resolver/refresh. Native has its own labels, 180px list cap, errors/loading/empty branches and tap selection; slash skills are always enabled there. Desktop wraps web. These are coverage decisions, not claims of native verification.

All workspace-capable drivers receive the resolved directory through the same registry boundary, including Codex, Claude, Cursor, Grok, OpenCode, Antigravity, Pi and Fx. Instances without a scanner retain the machine inventory. Only Claude was run against the removed worktree; the generic scanner harness verifies directory selection and preservation independently of a driver. This patch changes no provider-specific rendering or protocol.

## Matrix

D = Chromium 157/Linux web, 1440x900 CSS, DPR2, dark, 100% font scale/root16px. N = same browser, 390x844 CSS, DPR2, light; no device emulation. Runtime rows have viewport/theme N/A. UI rows depending on interaction are explicitly recording; a still alone is insufficient. For server-only state/time rows, a recording means the ordered structured RPC/service transcript, not an audiovisual claim.

Common app seed: use the linked seed-fixture.py to create a committed synthetic project with .claude/skills/finalize/SKILL.md and .claude/commands/finalize-command.md. browser-driver.js evidenceSeed uses real project.create, vcs.createWorktree and thread.create RPCs. Open its returned /<environmentId>/<threadId> route. Remove only the fixture's managed worktree with git worktree remove, retaining its branch and thread; restart its isolated dev server or force fresh:true. For a future capture, redirect all driver output paths to the new capturer's scratch directory rather than executing the historical hardcoded paths unchanged.

| Row | Named fixture and required data/action | Affected by PR | Minimum viewport x theme x medium | Seed/driver and existing evidence | Status on audited head |
|---|---|---|---|---|---|
| B1 | Missing managed worktree, active branched owner, root contains finalize skill + finalize-command; before queries $finalize, /skill:finalize and /finalize-command all settle empty | Before control for fallback | D; recording + 3 settled frames; fresh scan transcript | Common seed; capturePrimary(before), before-primary.mp4 and supplemental fresh-scan B1 video; actual-rpc-transcript before | valid as captured |
| F1 | Same missing path after; $finalize yields one Project Skill row; select it, menu closes and serialized draft is "$finalize " | Yes | D; recording + settled frame + serialization | capturePrimary(after); after-primary.mp4 00:00.7–00:04.3, after-primary-manifest.selection, absent-folder filesystem transcript | valid as captured |
| F1.N | Same populated dollar row, description truncated at narrow width, light theme | Same input branch; supplementary layout control | N; still only, not part of minimum | Common seed/route; narrow-light.png, environment.json | valid as captured |
| F2.on | Same inventory; showSkillsInSlashMenu=true; /skill:finalize yields one Project badge row | Yes | D; recording + settled frame | capturePrimary before/after; primary videos, slash-skill frame pair | valid as captured |
| F2.off | Toggle setting off through Settings -> Chat -> Advanced; /skill:finalize empties; $finalize remains available | Existing filter control | D; recording required | after-controls.mp4 (also appended in after-combined.mp4), controls manifest; no before toggle required | valid as captured |
| F3 | Same inventory; /finalize-command empty before and populated after, command description includes project scope | Yes, whole snapshot restored | D; recording + settled frame | capturePrimary before/after, command frame pair; actual snapshot command array | valid as captured |
| R1.a | Missing managed active owner resolves root, returned snapshot keeps original worktree cwd, root skill/command paths, no worktree created by scan/selection | Yes | N/A; recording as RPC/filesystem transcript | evidenceSnapshot(cwd,true), actual RPC + root-file syscall + missing-folder ls + retained branches | valid as captured |
| R1.b | Matching owner is archived; archive -> fresh scan -> unarchive yields root inventory | Yes, archived owner branch | N/A; recording as ordered RPC transcript | archive-control.json through app orchestration.dispatchCommand and evidenceSnapshot; resolver harness archived case | valid as captured |
| R1.c | Worktree exists with branch-only description differing from root; also project-root cwd | Guard, no fallback | N/A; RPC transcript | after-manifest intact snapshot, subsequent fresh real app response with worktree skill path and Branch-only fixture inventory | valid as captured |
| R1.d | Missing unmanaged path; managed but no owner; managed owner has branch=null | Guard, no fallback | N/A; RPC + labelled harness transcript | Unmanaged and ownerless real app RPCs; branchless production resolver harness; all return original cwd | valid as captured |
| R1.e | Missing project, shell lookup error, project lookup error, exists error | New resolver failure paths | N/A; labelled harness transcript | resolver-harness.mjs injects each service failure using real scratch filesystem; all retain cwd | valid as captured |
| R1.f.accept | Default/current/previous managed roots, symlink to managed root; settings failure uses default | Managed recognition input control | N/A; labelled harness transcript | resolver-harness.mjs, 5 accepted root/settings cases, branched owner -> project | valid as captured |
| R1.f.reject | Escaping symlink, relative path, non-normalized path, one/three levels below root | Managed recognition guard | N/A; labelled harness transcript | resolver-harness.mjs, rejected path cases -> original cwd | valid as captured |
| R1.g | Selected root empty or missing; disabled/agent-only skills excluded; unmatched query has no match | Fallback can legitimately yield empty | N/A; real empty-root RPC + labelled discovery/filter transcript | Actual empty-root app scan; production Claude discovery with synthetic home/project and shared visibility filtering; no UI-specific matcher claim | valid as captured |
| R1.h.cache | Complete cached snapshot, TTL expiry, forced fresh; omitted scanCwd scans cwd; descriptors/commands/skills retained under original key | Argument changes, cache semantics retained | N/A; recording as controlled-clock service transcript | registry-harness.mjs cached/expired/fresh/omitted; actual fresh vs cached checkedAt | valid as captured |
| R1.h.lifecycle | Unknown/disabled/no-scanner provider; pending then complete; scan failure then recovery; concurrent deduplication | Existing registry guards around changed scan argument | N/A; recording as ordered service transcript | registry-harness.mjs unknown/disabled/no-scanner/pending/failure/dedup, production registry with synthetic scanner; 10 registry scenarios total across h rows | valid as captured |
| R1.i | Missing root inventory -> turn-start recreates real Git worktree -> cache still root -> fresh returns branch-only inventory -> remove -> fresh returns root | Boundary and reverse-state control; recreation itself unchanged | N/A; recording as ordered Git/service/RPC transcript | recreation-harness.mjs with real Git, mocked orchestration, intentional stop after recreation and before provider; actual later cached/fresh RPCs | valid as captured |

The minimum visual capture set is D x {B1, F1, F2.on, F2.off, F3}, which the existing before/after primary recordings and controls recording cover. B1 includes the three empty before states; only the three settled query frames need pixel comparisons. All interactions require the linked recordings; stills are supporting evidence. F1.N is useful supplementary evidence, not a reason to require all viewport/theme cross-products for an unchanged renderer.

No mandatory additional rows for many-result scrolling, missing/long descriptions, other source badges, pointer-versus-keyboard selection, every theme/width, or every provider: those are unchanged rendering/search/interaction implementations. The new logic chooses an inventory source; the above rows cover its positive branch, guards, failures and visible inventory types. Loading/pending/error and descriptor preservation are accounted for by the existing structured harness evidence; the evidence makes no new visual-loading or native-error-layout claim. A general composer visual audit would require a larger matrix, but that is not this server-only patch.

## Existing captures checked

Read the PR body, complete Evidence.md, reproduce.md, seed/browser/capture/diff drivers, resolver/registry/inventory/recreation harnesses, actual RPC excerpts, archive control, manifests and filesystem transcript. Opened all three full-frame before/after/diff sheets and the narrow-light image. Downloaded and extracted per-second contact sheets from before-primary.mp4, after-primary.mp4 and after-controls.mp4, and inspected those sheets against the manifests. Their visible states agree with the claims. This pass did not launch an app, rerun tests, alter a worktree, or claim current-head runtime execution.

Existing evidence report: [Evidence.md](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/ed0031c5d2e2c330/Evidence.md). Seed and driver links remain in that report.

## Recapture decision

Required at a9e98bb900: none. Required before captures at 80e62619f5: none. The source-equivalence proof carries the existing after and before captures respectively. If an external process imposes an exact-revision runtime requirement beyond this brief, rerun the D primary pair plus after Settings control and R1.a on the new pair; do not claim that old media was captured there. No such extra requirement is inferred here.

No background process was started. Scratch files remain solely under the assigned audit directory; the PR checkout stayed clean. Disk available at start: 231 GB.

FRICTION: none

VERDICT: SUFFICIENT
