# Proof audit, pass 1 — [#32951](https://git.cafe/pingdotgg/t3code/pull/32951)

Findings:

1. **The existing PR evidence is insufficient for visual proof.** The description contains a real-app Settings before/after text transcript for an explicit config path, an after transcript for instance-environment `CLAUDE_CONFIG_DIR`, and reported passing tests. It attaches no capture and explicitly excludes the chat banner and mobile. A quoted string establishes wording, not wrapping, clipping, or access to the complete instruction. F1–F5 below have no visual evidence in the description.
2. **Settings has two presentations and a conditional tooltip.** The normal list clamps the status to two lines; the selected editor wraps the complete detail. With a compatibility warning, both replace inline authentication detail with a compatibility label and expose the authentication message through `ProviderStatusDiagnostic`. Normal Settings text alone does not cover that interaction.
3. **The model-picker provider-icon tooltip also changes.** It prefixes the complete message with the instance name and `Unavailable.`. Conversely, the three-line model-picker setup notice is gated out for Claude, and the onboarding sign-in row shows only `Not authenticated`. Mobile consumes this message in environment details, not in its chat composer.
4. **Scope is small, but not literally a one-file diff.** The checked-out diff against the supplied `origin/main` contains the production text change and three table-driven cases in `ProviderRegistry.test.ts` (two files, 70 insertions / 2 deletions). No other production file changes. The PR's quoted runtime run predates the supplied local merge; this audit verifies render paths at the merged checkout, not runtime behavior of that merge.

Reviewed read-only in `/home/user/wt/pr-32951`; verified HEAD matches the supplied full SHA and the base is [633438d54f](https://git.cafe/pingdotgg/t3code/commit/633438d54f17b99f73f1a09466ecbe4a6aa0d545). Implementation described in the PR is [c43cbd2dfd](https://git.cafe/pingdotgg/t3code/commit/c43cbd2dfd). No app, provider turn, test suite, screenshot, edit, push, or comment was run by this audit. The only writes are this scratch report and its requested public upload.

## Minimal fixture matrix

`U` means a successful version + initialization probe with `enabled=true`, `installed=true`, `status=error`, `auth.status=unauthenticated`, first-party account with `tokenSource=none`, no API key/email/subscription, no custom endpoint, and no `unavailableReason`. `D` is an empty synthetic fixture directory below the capture operator's timestamped scratch run; it is not an existing user's Claude home. `L` is an empty subdirectory under D with a 180-character unbroken basename (below the filesystem's component limit). Use a synthetic display name such as `Claude proof` throughout.

| ID / named fixture | Render path and visible combination | Data / branch; affected by diff? | Real-app seed and navigation | Minimum capture: viewport × theme × row | Existing PR evidence |
|---|---|---|---|---|---|
| **F1 — Settings, inline detail** | Web Settings → Providers: two-line list summary (`overflow-wrap:anywhere`) plus selected editor Status row (unclamped, wrapping). Desktop uses these same components. | U, supported/unknown/no compatibility advisory, no active provider update. Peer instances: own short path `D/short`, inherited path `D/env` with blank home path, and long own path L. Own and inherited origins produce the same layout and are collapsed here. Select the long instance to stress the complete instruction, cwd and path wrapping; peer short/env rows cover ordinary list text. **Yes.** | Add Claude instances; in Runtime set **CLAUDE_CONFIG_DIR path** to D/short or L. For inherited peer leave that field empty and add `CLAUDE_CONFIG_DIR=D/env` under Environment. Commit the fields, refresh provider status, select L. Settings' explicit home path overrides an env value. The instance env and process-inherited env are equivalent once merged. | **Before/after still pair, 1280×900 × dark × F1.** Bring the peer rows and selected long editor into view. One long-path editor stands for short-path editor too; no extra origin/theme permutation. | Own-path before/after and inherited-path after are quoted, with abbreviated paths; **no capture** of either list clamp or editor wrapping. |
| **F2 — Settings, diagnostic tooltip** | Same Settings list/editor, but compatibility warning replaces inline detail with `Limited support` / `Unsupported` / `Incompatible`; hover/focus diagnostic text exposes the complete authentication message. Tooltip has default 320px maximum width and wraps anywhere. | U + L + compatibility status `graceful`, `unsupported`, or `broken`; no update progress. These statuses share the same diagnostic renderer; choose one. **Yes**, inside the tooltip; inline compatibility label itself is unchanged. | Reuse F1, set Binary path to a real Claude CLI version classified by the environment's active compatibility policy, then refresh. Bundled fallback classifies `>=2.1.111 <2.1.280` as graceful and `<2.1.111` as unsupported. CLI initialization must still succeed and report signed out. **Not seedable by config-dir/env alone**; needs a qualifying real binary and active policy. If unavailable, report the row unseeded instead of fabricating a screenshot. Hover the list diagnostic, then selected editor Status. | **recording**, before/after, **1280×900 × dark × F2**; show diagnostic closed → open and full path. A single sequence covers both triggers. | Not described or captured; CLI compatibility state in the earlier run is unspecified. |
| **F3 — Chat, clamped banner → full tooltip** | `ChatView` → `ChatBannerLane` → `ProviderStatusBanner`: error alert titled `Claude proof is unauthenticated`; description clamps to three lines, hover reveals complete text in an above/below collision-positioned tooltip (`whitespace-pre-wrap`, wraps anywhere, max 320px). | U + L, selected instance is the signed-out instance, banner has not been dismissed. Authentication error takes priority over compatibility in this banner. **Yes.** | Seed F1 and use a draft/thread whose selected/model instance is this instance. A concrete UI seed without a turn: temporarily use C2 to make this instance ready, select its model in a new draft, then remove the endpoint override in Settings and refresh. Return to that draft: the explicit enabled/available instance candidate is retained even with error status. An existing thread/default already pointing to it also works. Keep model selection pinned to this instance rather than clicking its now-disabled picker icon. No turn needs to run. Keep the banner undismissed; hover its description. | **recording**, before/after, **1280×900 × dark × F3**; show clamp, hover, complete cwd/config-dir instruction, and usable controls. | Explicitly not checked; **no capture**. |
| **F4 — Model picker, unavailable-instance tooltip** | Composer model picker → provider sidebar → hover disabled Claude icon/wrapper. Tooltip is `<displayName>: Unavailable. <message>`; same string is its accessible label. Disabled buttons are wrapped specifically so hover still works. No line clamp inside tooltip; max 320px, wraps anywhere, preferred side left with collision handling. | U + L; enabled/available instance, no search so sidebar is shown. It remains non-selectable while errored, but its hover text is reachable. **Yes.** | Reuse F1; open composer model picker with an empty search. Hover this instance's icon; do not try to select the disabled item. Another selected provider is fine. | **recording**, before/after, **1280×900 × dark × F4**; open picker → hover unavailable icon → show complete prefixed message. | Omitted; **no capture**. |
| **F5 — Native mobile, complete environment detail** | Mobile Settings → Environments → connected environment → Providers: enabled provider row shows `unavailableReason ?? message` in selectable React Native Text, with no `numberOfLines` limit and no tooltip. Screen scrolls. | U + L, provider enabled and `unavailableReason` absent. **Yes.** Mobile chat does not render this health message. | Seed the server through F1 web Settings, pair/connect a native client to that isolated server, open its environment details and refresh providers. Mobile's detail screen does not edit the home path; server/web configuration supplies the fixture. No real turn needed. | **Before/after still pair, 390×844 logical viewport × dark × F5**, one native platform; frame the full message. If scrolling is required to demonstrate access to its end, use **recording** instead. Android/iOS share this unchanged renderer; no platform cross-product for this text-only change. | Description merely states mobile shares the field; explicitly not checked; **no capture**. |
| **C1 — Default-directory control** | Same Settings/banner/mobile renderers, with original short message: Claude Code is not authenticated. Run `claude auth login` and try again. | U, homePath blank and `CLAUDE_CONFIG_DIR` **absent**, not an empty string. **No text change.** An explicitly defined empty env value still takes the helper branch because the code tests undefined, not truthiness. | Remove instance and process config-dir overrides. Requires a genuinely signed-out default Claude home and no keychain/token credentials. On a host with a signed-in default, **cannot safely force this with an empty custom directory** (that changes branches): use a clean OS account/container. Do not log out or modify the live default. | **No separate mandatory capture.** Reuse a visible peer row in F1 if available; exact legacy-text assertion is the essential control. | Added test covers exact legacy string; no real-app default-dir transcript or capture. |
| **C2 — Custom-endpoint bypass control** | Settings identifies authenticated `Custom API endpoint`; signed-out hint is absent. A ready provider normally has no health banner (independent compatibility/upgrade notices may remain). | Same empty first-party account and own/inherited config directory, but effective `ANTHROPIC_BASE_URL` parses as HTTP(S) with nonempty hostname other than exactly `api.anthropic.com`. Returns ready/authenticated rather than entering changed branch. **No text change.** API-key/account auth and non-first-party providers also bypass signed-out detection. | Reuse empty config dir; add a synthetic non-Anthropic HTTP(S) `ANTHROPIC_BASE_URL` in instance Environment, then refresh. No real auth secret or turn is needed, but initialization must succeed. Claude user/managed `settings.json` env endpoint overrides process/instance env, so inspect those sources if this fails to select the intended branch. A malformed URL, FTP URL, or `api.anthropic.com` (any port) does not bypass. | **No separate mandatory capture** for this unchanged branch; use existing branch tests plus optional status transcript. | Existing source tests cover inherited and instance-overridden custom endpoints. PR body lists the full focused-check pass, but no endpoint-specific runtime evidence. |

Minimum visual set: **five situations, each before and after: F1 and F5 still pairs; F2, F3, F4 short recordings**. All use one theme; CSS/theme treatment did not change. Use the same synthetic paths and viewport on both sides, with the supplied base versus merged implementation. This is not a full theme/platform/provider cross-product. A narrow web Settings shot is optional extra coverage of its existing stacked layout, not an additional minimum fixture. Desktop wraps the web renderer, so F1–F4 cover its message layouts without duplicating the whole suite; do not claim a native Electron run from browser-only captures. Local, hosted, remote/relay, and tunnel clients read the same environment-scoped snapshot; the cwd/path names the server machine, not the browser/phone filesystem.

## Seed prerequisites (instructions for a later capture pass; not executed here)

Start the dev server with **`T3CODE_DEV_SEED=0`**, fresh isolated T3 state, and **without Claude auth env**. Remove `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN`, `CLAUDE_CODE_OAUTH_TOKEN` and related credential-file / FD overrides and external-provider selectors from the server's effective environment; clear inherited `ANTHROPIC_BASE_URL` for F1–F5/C1. Account for any env-file loading that could reintroduce them. Do not change global proxy config, the developer's real Claude settings, or live T3 data. Use `vp run dev` with an explicit isolated home under the capture pass's scratch run; do not set `VITE_HTTP_URL` or `VITE_WS_URL`. Keep an installed working Claude binary and normal shell/runtime PATH.

Create genuinely empty config directories inside that capture run, use synthetic paths only, and confirm the corresponding Claude initialization is signed out; `claude auth status` with that instance's environment is a useful preflight. An empty config directory alone is not proof if another credential source remains. For C2, add only the synthetic endpoint exception described in its row. A fresh database does not erase an already-existing state directory: the no-seed flag must be paired with fresh isolated state.

Own `homePath` is trimmed, home-expanded, and resolved to an absolute native path. A nonempty own path wins over env. Instance env paths get home expansion in environment merging; process-inherited relative values remain literal in `makeClaudeEnvironment`. The helper quotes cwd and configDir as JSON strings and does not generate a shell command. Production health checks pass the T3 stateDir (`<T3 home>/userdata`) as cwd; workspace probes copy the machine status message rather than recomputing it with a project's cwd. These origin/path-format variants need status-text checks, not separate visual permutations. Do not run a paid agent turn merely to create a banner.

## Caller and exclusion audit

- Production check caller: [ClaudeDriver.ts](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/server/src/provider/Drivers/ClaudeDriver.ts#L238) feeds `checkClaudeProviderStatus` its merged process/instance env and stateDir. Remaining direct callers are tests. [buildServerProvider](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/packages/provider-core/src/server/snapshotProbe.ts#L241) copies `probe.message` into the optional `ServerProvider.message`; identity stamping and workspace snapshot spread preserve it. No wire-schema change.
- F1/F2: [getProviderSummary](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/web/src/components/settings/providerStatus.ts#L67) → [ProviderInstanceCard list/editor and diagnostic](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/web/src/components/settings/ProviderInstanceCard.tsx#L946). [ProviderSettingsPanel](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/web/src/components/settings/ProviderSettingsPanel.tsx#L1040) renders both; at container width 48rem it uses a 17rem list beside the editor, below that they stack. Project scopes/read-only permissions can change availability controls but not the message renderer. Update-progress text temporarily replaces list status and is outside the changed signed-out presentation.
- F3: [ChatView selection](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/web/src/components/ChatView.tsx#L1293) → [ChatBannerLane](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/web/src/components/chat/ChatBannerLane.tsx#L44) → [ProviderStatusBanner](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/web/src/components/chat/ProviderStatusBanner.tsx#L68). `getProviderStatusMessage` prefers this message; dismissed key includes its text, and ready/disabled states suppress the normal banner. [TooltipPopup](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/web/src/components/ui/tooltip.tsx#L133) supplies shared tooltip width, wrapping and viewport collision behavior.
- F4: [ModelPickerSidebar](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/web/src/components/chat/ModelPickerSidebar.tsx#L14) → `describeUnavailableInstance` reads `entry.snapshot.message`; picker is shared by composer entry points. The other `getProviderStatusMessage` caller, [ModelPickerProviderNotices](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/web/src/components/chat/ModelPickerContent.tsx#L197), would clamp to three lines, **but is unreachable for this Claude snapshot**: `shouldOfferModelPickerSetup` requires `hasProviderSetup`, while Claude leaves `canAuthenticate=false`, `canInstall=false`. It must not become an artificial required capture.
- [WelcomePage AgentRow](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/web/src/components/onboarding/WelcomePage.tsx#L1139) can read `provider.message` only in `attention`, but an available installed signed-out Claude resolves to `signIn`, displaying the summary **headline**, not detail. Compact rows have no detail. An unavailable-driver replacement can enter attention, but it replaces the health snapshot/message. [CodexSetupSection](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/web/src/components/settings/CodexSetupSection.tsx#L120) is the other summary-helper caller; it is Codex-specific and uses the headline, not Claude's detail.
- F5: [SettingsEnvironmentDetailRouteScreen](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/mobile/src/features/settings/SettingsEnvironmentDetailRouteScreen.tsx#L371). `unavailableReason` would mask the message but is absent on this healthy-driver/signed-out branch. Mobile ThreadComposer renders a separate compatibility advisory, not this message. Device setup and provider-auth action `message` fields are different data shapes, not consumers of this status string.
- Desktop: [DesktopWindow](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/desktop/src/window/DesktopWindow.ts#L746) loads the web application. No independent Electron status-message UI exists here.
- Backend branches and helper: [ClaudeProvider production change](https://github.com/pingdotgg/t3code/blob/c43cbd2dfd/apps/server/src/provider/ClaudeProvider.ts), [ClaudeHome](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/server/src/provider/Drivers/ClaudeHome.ts#L125), [fallback compatibility policy](https://github.com/pingdotgg/t3code/blob/633438d54f17b99f73f1a09466ecbe4a6aa0d545/apps/server/src/provider/model-manifest.json#L26). Disabled/missing CLI/version failure/timeout/no-capabilities return earlier with unchanged other messages. Successful account/API-key/external-provider/custom-endpoint states bypass the changed branch. None creates a new required screenshot for this PR.

Coverage: completed code/data-flow/conditional/render-path audit and PR-description evidence audit within the 45-minute budget. No visual or runtime claim was independently verified in this pass.

FRICTION: none
VERDICT: INSUFFICIENT F1 Settings inline/clamped/long-path layout; F2 Settings compatibility diagnostic tooltip; F3 chat banner clamp and tooltip; F4 model-picker unavailable-instance tooltip; F5 native mobile environment detail
