# Proof audit, pass 1: sidebar server-update Retry

Reviewed [#32924](https://git.cafe/pingdotgg/t3code/pull/32924) ([GitHub mirror](https://github.com/pingdotgg/t3code/pull/32924)), branch [fix/issue-32896](https://git.cafe/pingdotgg/t3code/tree/fix/issue-32896), head [a72fee8d81](https://github.com/pingdotgg/t3code/commit/a72fee8d8192494592c1b046db4348765b5bc45c), against main [bcee0f5d28](https://github.com/pingdotgg/t3code/commit/bcee0f5d2872ba193c66ed9ba979bbe424f89ff9). Both remote refs matched the local refs when inspected on 2026-11-10. This is a read-only, pre-capture proof audit, not a full correctness or merge-readiness review.

## Findings

1. **Blocking evidence gap: the claim “No render path changes; only which servers Retry sends” is false as a description of observable behavior.** No JSX was edited, but the new branch calls `settleUpdateRunMachine(..., {serverUpdated: true})`. That changes `result`, `failure`, and `server`, and calls `closeFinishedUpdateRun`. The same click now reaches different existing render branches: a failed row becomes done; its error line disappears; failure counts change; Retry can become Dismiss; or the entire capsule and its open popover unmount. The PR description itself says the capsule closes. A red logic test proves the filtering and settlement, but cannot prove that visible transition. Before/after **recordings** are needed for R1–R4 below. Stills alone cannot establish the action, transient states, or disappearance.

2. **The provider-failure branch must not be mistaken for success.** With `providerFailure !== null`, the newly settled current server has `server: null` but still has `result: "failed"`; its visible failure becomes the provider error. If it is the only remaining failure, both Retry affordances disappear and Dismiss remains. A recording of only the capsule closing misses this affected branch.

3. **Scope limit: an actually updated server whose client config is stale still takes the old retry path.** The new decision reads `configValueAtom`, not an independent live version probe. With config at N−1 and target N, it calls the updater. This is relevant to [#32896](https://git.cafe/pingdotgg/t3code/issues/32896), whose report asserts stale configuration after reconnect. Source inspection also shows config-stream snapshots normally refresh the projection, so this audit does not assume that diagnosis reproduces on this head. C2 needs a controlled reconnect/runtime observation before claiming the whole reported sequence is fixed; a seeded current-config recording proves the narrower branch only.

## Source and render inventory

The two changed files are [updateEverythingRun.tsx](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/sidebar/updateEverythingRun.tsx#L66) and its [logic test](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/sidebar/updateEverythingRun.test.ts#L79). The changed production module exports state/actions, not a React component. Its toast JSX is unchanged. The render audit therefore follows its consumers rather than pretending there is a changed standalone card.

- **Retry's only production caller** is `SidebarUpdateCapsule.runAction`. It is reachable from the capsule's inline Retry and from the popover's Retry button. No separate command-palette, keybinding, native-mobile, scheduled-task, or MCP caller of this function was found. [Caller and both buttons](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/sidebar/SidebarUpdateCapsule.tsx#L79).
- **Capsule's only production caller** is `SidebarUpdateControl`, reached through `SidebarUpdatePill` → `SidebarUtilityMenu` → `SidebarChromeFooter` → `ThreadSidebar` in `AppSidebarLayout`. The footer exists on the normal chat route and utility routes; the latter replace Settings/PR/Usage controls with Back and give the capsule different horizontal space. [Parent boundary](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/sidebar/SidebarUpdatePill.tsx#L403), [footer composition](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/sidebar/SidebarChrome.tsx#L258).
- **Capsule props/data:** `run` has optional `trackSwitch`, `localVersion`, `phase`, nullable `restartAt`, and `machines[]`. Each machine has `environmentId`, `label`, `updatesProviders`, nullable `server` target, nullable `handedOffVersion`, `startedAt`, nullable `result`, nullable `failure`, and nullable `providerFailure`. A target's config `serverVersion` drives the changed branch; its capability/platform/install fields do not change capsule layout. `local` is null, waiting, or downloading with null/numeric percent. `icon` occupies the action slot when there is no action. Optional `onRestart` adds the desktop “This app / Restart to update” row when `localVersion` is null. [Props and rows](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/sidebar/SidebarUpdateCapsule.tsx#L58).
- **Status precedence:** explicit done/failed result; otherwise handed-off restarting; otherwise provider phase + provider work; otherwise server running (`resuming` → restarting, all other running stages → downloading); otherwise waiting. These are all six row labels. Done/failed/waiting omit elapsed text; active rows show it. `failure !== null` adds a wrapping line independently of status. Long labels truncate; statuses do not shrink. [Status resolver](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/sidebar/updateEverything.logic.ts#L401).
- **Capsule summary precedence:** countdown with a deadline → Restart in Ns / Later; installing → Restarting / icon; oldest active row aged at least 3m → its name / warning elapsed / icon; any active or waiting row → done of total / icon; then local download with optional floored percent; then failures with singular-name or plural-count label and destructive styling. Retry is offered only when not a track switch and some failed row still has a server target; otherwise Dismiss. No failure → done of total / icon. Zero, one, and multiple machines/failures are accounted for below. The empty all-done set also satisfies the closure predicate. [Summary branches](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/sidebar/updateEverything.logic.ts#L419).
- **Popover branches:** local-version row wins over optional restart row; otherwise no local row. A settled run (`!hasActiveMachine && localVersion === null`) with a failure shows a footer with Dismiss, plus Retry only if the summary action is Retry. Waiting is excluded from `hasActiveMachine` here, though it keeps the summary in progress, so waiting+failure can show Dismiss without Retry. Buttons and trigger have hover/focus states. Open/close, keyboard activation, Retry, Dismiss, Later, and optional local restart are the interactions. The local row's status is countdown, restarting, downloading with/without percent, or “restarts after the servers.” [Popover branches](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/sidebar/SidebarUpdateCapsule.tsx#L129).
- **Time/theme/width/platform:** the clock ticks each 1s in countdown, 30s for active rows, and not at all for settled/waiting-only runs. Elapsed text has <1m, minutes, and hours/minutes formats. CSS theme tokens change colors; there is no theme-specific retry logic. The capsule is h-8, flexing and truncating its summary to preserve its action. The popover is nominally 256px with viewport/available-width constraints. Sidebar width is resizable (default 256px; minimum at least 208px and potentially wider for branding). At ≤767px the web sidebar becomes a sheet, closed until opened. Collapsed desktop offcanvas also hides the footer. Web and Electron share this capsule. Native React Native mobile does not import it. [Capsule layout/clock](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/sidebar/SidebarUpdateCapsule.tsx#L25), [responsive sidebar](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/ui/sidebar.tsx#L285).
- **Parent after closure:** web returns nothing if there are no other update offers; otherwise it returns the normal update button. Desktop always retains its ordinary update control. Parent icon variants (checking, downloading, downloaded, available, everything, idle), release notes, update confirmation, provider-check loading, denial/disabled state, and reduced-motion animation are unchanged surrounding branches, not separate required capture cross-products for this retry change. [Parent and icon logic](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/sidebar/SidebarUpdatePill.tsx#L82).
- **Other observer:** About settings consumes the same run and disables Update track and, when shown, Review while a run exists. Closure re-enables them on desktop; web does not display these bridge-dependent controls. [Settings observer](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/settings/SettingsPanels.tsx#L332).
- **Other changed helper caller:** `followHandedOffServers` now calls the extracted `runsVersion` helper, with exactly the previous predicate. `appInit` invokes it indirectly through `startDesktopUpdateLaunchNotice` only in Electron. Restored restarting rows, a 32-minute failure timeout, saved-result toasts, and not-applied notices are unchanged controls (C14), not new retry behavior. [Restoration](https://github.com/pingdotgg/t3code/blob/a72fee8d8192494592c1b046db4348765b5bc45c/apps/web/src/components/sidebar/updateEverythingRun.tsx#L272).

## Fixture matrix

Notation: **T** = target version; **A** = failed machine with `server != null`, config reporting T, and no provider failure; **B** = failed machine with a target newer than its reported config; **P** = failed provider-only machine with `server: null`. Unless stated otherwise: phase servers, localVersion/restartAt null, trackSwitch absent, no handed-off version. Initial server failure: “Remote updates must select a newer server version.” Use demo labels, not personal account data. Rows with the same branch and only different version strings collapse into the indicated fixture rather than requiring another visual capture.

**Status meaning:** MISSING = required capture absent; MAPPED = source-derived control, no extra capture demanded for this diff; HARNESS = valid prop/state combination with no stable user-flow seed established. None of these statuses claims browser verification. Every interactive or timed row is marked **recording** even when it is an unchanged control.

| ID / named fixture | Data and visible combination | Diff affects? | Capture requirement / status | Real-app seed or explicit harness |
|---|---|---|---|---|
| R1 — sole current server | One A. Failed name/error + Retry → no run; open popover unmounts. No guaranteed visible done frame. | Yes: settles and closes. | **recording; MISSING; M1**. Reset once to exercise inline Retry and once for popover Retry. | S1 below, one real connected config at T. Prefer isolated boot-service host for exact baseline rejection; bare dev works with disclosed different backend refusal. |
| R2 — current plus still-behind | A + B, long A name and wrapping failure. “2 failed” → A done without error + B waiting/downloading/restarting while request runs → B failed (“B failed”, Retry) or success and closure. | Yes: done row, count, error removal, updater subset. | **recording; MISSING; M2**. Require retained done row and failed B endpoint; do not require a transient frame the live backend never paints. | S2 below, two real dev connections for failure endpoint. An updater whose completion is held for active stages is **labelled harness**, not live-RPC proof. Null config B is the same visual class, C1. |
| R3 — current server, provider failure survives | One A except `providerFailure: "Provider installation failed: demo diagnostic"`. Retry → still failed, error becomes provider diagnostic, target cleared, inline action becomes Dismiss, popover Retry gone and Dismiss retained. Dismiss → close. | Yes: different error and action; intentionally not success. | **recording; MISSING; M3**. Include Retry then Dismiss, with popup and capsule endpoint visible. | S3 below. Actual live config + exported setter, no mocked config or updater needed. |
| R4 — success retained beside independent failure | A + P. “2 failed”/Retry → A done + P failed; single-name failure summary, Dismiss only; Dismiss removes settled rows and closes. | Yes: done remains visible although no server retries remain. | **recording; MISSING; M4**. | S4 below with two actual environment IDs. P needs no server update. This also covers a successful current row retained beside a nonretryable failure. |
| R5 — local app keeps a done run | A + `localVersion: T`, phase servers, local waiting. Retry → 1 of 1 updated / icon, local row “restarts after the servers,” done row; capsule cannot auto-close while localVersion exists. | Yes if this state is reached. | **recording; HARNESS; optional H1**. Stable interaction window not established in normal coordinator flow. | Exported setter can display this in the full app; label state-seeded/harness. Coordinator normally downloads, counts down, then clears localVersion; do not claim a natural reproducible Retry window. |
| P1 — closure with another offer | R1, but a separate eligible provider/server update remains. | Parent changes from capsule to regular update button, not total footer disappearance. | **recording; MAPPED; optional**. R1 required observation is capsule absence, not absence of all update UI. | Seed another real provider update through its normal configuration/check path, or label mocked provider catalog as harness. |
| P2 — Electron closure / settings observer | R1 in Electron, then normal update control remains; About Update track/Review re-enable where otherwise allowed. | Yes, same run-null transition. | **recording; MAPPED; optional desktop parity**. Web can prove shared branch, not native bridge behavior. | Isolated desktop dev app with a remote environment. `/settings/about`; bridge and permission/policy prerequisites must be real. |
| P3 — downloaded local restart affordance | R1–R4 with localVersion null and desktop action install + real bridge. Popup adds “This app / Restart to update.” | Row itself unchanged; capsule removal also removes it. | **recording; MAPPED; optional**. | Real desktop with downloaded app update. In a web-only harness inject onRestart/bridge and label it. Actual restart is not needed to prove Retry. |
| C1 — config not loaded | Failed B with config null; updater still called, failure/Retry retained or normal update completion. | Unchanged fallback. | **recording; MAPPED**; logic control, not another mandatory visual pair. | Never-connected entry/custom config query fixture or harness returning null. Do not equate disconnected with null: cached config can remain present. |
| C2 — host updated, config stale | Host actually T, but client still reports N−1; failed target T. Retry sends again and can return same-version rejection. | New fast path is not taken. | **recording; MAPPED; scope unresolved**. Required before claiming the original stale-config sequence is fixed. | Most faithful: isolated boot-service host, update/reconnect while retaining the window, inspect live config at Retry. A transport harness withholding/replaying old config snapshots is deterministic but must be labelled. Editing a cached disk snapshot alone may be overwritten by the live stream. |
| C3 — track switch | Failed server target with `trackSwitch: true`; Dismiss, never Retry; dismiss run and return through About planner. | Unchanged guard; new function not user-reachable here. | **recording; MAPPED**. | About → Update track partial failure, or setter with trackSwitch true for a state fixture. Do not call retry directly and present it as a user flow. |
| C4 — providers active | result null, updatesProviders true, phase providers; updating providers + elapsed, done-of-total summary, no Retry. | Unchanged status branch. | **recording; MAPPED**. | Normal update run with provider update, or state-seeded full-app fixture. |
| C5 — waiting, including waiting + failure | result null; no running server state, not provider work. “waiting” with no elapsed; progress summary. Waiting + failed row can show popover Dismiss but no Retry. | Unchanged status/summary precedence. | **recording; MAPPED**. | Brief normal handoff gap or setter. For a stable frame use a labelled held-updater harness; idle server state alone gives waiting. |
| C6 — downloading / installing server | result null, server target present; update state running stage downloading or installing. Both render “downloading” + elapsed, no action. | Unchanged; R2 can traverse it. | **recording; MAPPED**; collapse the two identical row renderings. | Real server update progress. Stable deterministic stage: labelled harness driving raw serverUpdateStateAtom with a held completion. |
| C7 — restarting | result null and handedOffVersion present, or running stage resuming. “restarting” + elapsed. | Unchanged; R2 may traverse it. | **recording; MAPPED**. | Real handoff/reconnect, restored desktop run, or labelled state fixture. |
| C8 — slow active machine / elapsed formats | Oldest active row aged ≥3m; warning ring, machine name and elapsed instead of counts. <1m, minute, hour/minute row strings are formatting variants; elapsed has no independent loading state. | Unchanged threshold/timer. | **recording; MAPPED**. | Backdate startedAt in a state seed; allow the actual 30s clock tick to show threshold behavior. A controlled clock is harness evidence, labelled as such. No need to wait 32m for this PR. |
| C9 — local download, unknown percent | No active machine; localVersion set, desktop state downloading, percent null. “Downloading”; local popup says downloading, no action. | Unchanged higher-priority summary. | **recording; MAPPED**. | Real desktop download with unknown progress, or labelled desktop-state harness. On web caller always passes local null without a localVersion. |
| C10 — local download, known percent | As C9, percent e.g. 42.9. Summary “Downloading 42%”; local row “downloading 42%.” | Unchanged. | **recording; MAPPED**. | Real desktop progress or labelled state harness. |
| C11 — restart countdown | phase countdown, restartAt in future. “Restart in Ns” / Later; local row repeats seconds; click Later cancels restart decision. | Unchanged phase override. | **recording; MAPPED**. | Normal desktop coordinated update; exported waitForUpdateRestart(5000) can drive the real decision timer in a fixture. |
| C12 — installing app | phase installing. “Restarting…” / icon; local row restarting if localVersion present. | Unchanged phase override. | **recording; MAPPED**. | Real accepted desktop install or labelled phase/state fixture; avoid pretending web has a real desktop restart. |
| C13 — hidden / no run / empty / done boundary | run null: no capsule; web no-offer absent, desktop ordinary control. Collapsed sidebar or closed mobile sheet: footer not visible. Empty raw run can show 0 of 0 if injected directly; normal settlement of empty/all-done servers+no-local closes it. | Closure boundary affected via R1; empty raw state unchanged. | **recording for toggling/settlement; MAPPED**. An inert no-run frame alone may be a still. | S1 closure; real sidebar toggle. Empty raw run is **harness-only**, not normal completion proof. |
| C14 — desktop restored handoff + notices | Saved handed-off entries restart; config satisfying T settles, otherwise timeout failure after 32m; saved result/toast description may be absent or multi-line; not-applied notice is separate. | Helper extraction only; predicate unchanged. | **recording; MAPPED**. No new visual pair required. | Controlled localStorage saved result key in isolated desktop plus reload/config stream; timed harness for timeout. Existing launch-notice tests cover running/timeout state, not a recording. |

No exhaustive product of counts × themes × widths × every unchanged phase is justified for a single changed Retry branch. R1–R4 span all affected output classes and both Retry entry points. Newer-than-target versions and version strings that the existing mismatch helper regards as equivalent use the R1/R2/R3 visual classes; older nightly builds use B/C1. This predicate means “not behind according to resolveVersionMismatch,” not strict string equality. Missing/blank version in a non-null malformed config also matches that helper, but is not a normal typed server-config fixture.

## Minimum capture set

Each item is a matched **before main / after head** recording pair with the same initial run and disclosure of seed method. Total: four pairs (eight recordings), which may be chapters of two labelled composite videos. Reset state between the two actions in M1. Record the initial failure, the actual click, the resulting row/action changes, and capsule/popover disappearance or persistence; reopen/close the popup as needed to show both views. Keep the footer and nearby context in frame, not just a cropped status word. Record outcomes rather than relying on a fixed delay. Do not fabricate an intermediate done frame on R1: the run can close in the same update.

| Capture | Viewport × theme × fixture | Required visible proof |
|---|---|---|
| M1 | 1440×900 × dark × R1; normal chat route, expanded 256px sidebar | Inline Retry and, after reset, popup Retry. Before remains failed/retryable after rejection; after closes capsule and open popup. |
| M2 | 1280×800 × light × R2; normal chat route, drag sidebar to its actual minimum (at least 208px) | Long name truncation and wrapping diagnostic, plural→singular failure count, current row done/error removed, behind row still failed with Retry. If real progress paints, retain it; otherwise active phases remain labelled harness controls. |
| M3 | 390×844 × dark × R3; web mobile sheet opened | Retry→provider diagnostic + Dismiss, popup Retry absent, then Dismiss closes. This is responsive web, not native-mobile verification. |
| M4 | 1440×900 × light × R4; utility route `/usage`, expanded sidebar | Retained done row beside provider-only failure; Retry→Dismiss; explicit dismissal. Capture Back/footer context. About's settings observer is a separate optional desktop check (P2); do not capture a capsule obscured by a settings modal. |

Use built-in light/dark themes via `/settings/appearance`. No theme-specific code changed; pairwise theme coverage is enough. No Windows/macOS/Linux fork exists in this Retry code, so an OS cross-product is not a minimum visual requirement. The Windows desktop ↔ macOS background-service history remains a separate end-to-end scope check (C2).

## Concrete seeding in the real web dev app

**This audit did not start servers or run the driver.** The following is a source-checked recipe for the capturer. Run it against isolated worktree dev state, never the live installation. Use the primary task's dev server or let its owner start one. A subagent should not start its own server. Start source dev with `T3CODE_BUNDLED_DEV=0 vp run dev` so browser-console module imports resolve to the same unbundled module instances as the app. Default bundled dev is unsuitable for assuming those direct imports share the live atom registry. Read actual origin/ports from dev-runner output, pair normally, and navigate to `/`. Do not set VITE_HTTP_URL or VITE_WS_URL.

The existing `window.t3dev` only exposes replay methods, **not update-run fixture hooks**. The run atom is private, but `setUpdateEverythingRun` and `settleUpdateRunMachine` are exported. `serverEnvironment.configValueAtom` is a derived read-only atom; **do not attempt `appAtomRegistry.set(configValueAtom(...), ...)`**. For the affected branch, no config mocking is needed: keep a real connected server at whatever version it already reports and store that exact version as the failed run's target.

Paste this into the dev app's browser console (or evaluate in its shared Browser panel). It installs a temporary driver only in that page; it does not write source files, provider data, or server config. Its forced initial failure must be disclosed as **state-seeded real-app evidence**, not a naturally reproduced failed update.

```js
const { appAtomRegistry: registry } = await import('/src/rpc/atomRegistry.ts');
const { serverEnvironment } = await import('/src/state/server.ts');
const { primaryEnvironmentIdAtom } = await import('/src/state/primaryEnvironment.ts');
const { environmentCatalog } = await import('/src/connection/catalog.ts');
const { setUpdateEverythingRun, settleUpdateRunMachine } =
  await import('/src/components/sidebar/updateEverythingRun.tsx');
const rejection = 'Remote updates must select a newer server version.';
const providerError = 'Provider installation failed: demo diagnostic';
const ids = [...registry.get(environmentCatalog.catalogValueAtom).entries.keys()];
const primaryId = registry.get(primaryEnvironmentIdAtom);
const readConfig = id => registry.get(serverEnvironment.configValueAtom(id));
const machine = (id, label, extra = {}) => {
  const config = readConfig(id);
  if (!config) throw new Error('Wait for a real connected config before seeding');
  return {
    environmentId: id, label, updatesProviders: false,
    server: { environmentId: id, serverLabel: label,
      selfUpdate: config.environment.capabilities.serverSelfUpdate ?? null,
      targetVersion: config.environment.serverVersion },
    handedOffVersion: null, startedAt: Date.now(),
    result: 'failed', failure: rejection, providerFailure: null, ...extra,
  };
};
const seed = (name, a = primaryId, b = ids.find(id => id !== a)) => {
  const current = machine(a, 'Demo current server with a deliberately long label');
  let machines = [current];
  if (name === 'R2') {
    if (!b) throw new Error('Connect a second isolated bare dev server first');
    const config = readConfig(b);
    if (!config || config.environment.capabilities.serverSelfUpdate != null)
      throw new Error('This safe failure fixture requires a bare dev server without self-update');
    const behind = machine(b, 'Demo behind server');
    // A valid newer target; this bare dev backend refuses before installing anything.
    const match = config.environment.serverVersion.match(/^(\d+)\.(\d+)\.(\d+)/);
    if (!match) throw new Error('Use a semver dev server');
    machines.push({ ...behind, server: { ...behind.server,
      targetVersion: `${match[1]}.${match[2]}.${Number(match[3]) + 1}` } });
  } else if (name === 'R3') {
    machines = [{ ...current, updatesProviders: true, providerFailure: providerError }];
  } else if (name === 'R4') {
    if (!b) throw new Error('Connect a second isolated server first');
    machines.push(machine(b, 'Demo provider-only failure', {
      server: null, updatesProviders: true,
      failure: providerError, providerFailure: providerError,
    }));
  } else if (name !== 'R1' && name !== 'R5') throw new Error('Unknown fixture');
  setUpdateEverythingRun(() => ({ phase: 'servers', restartAt: null,
    localVersion: name === 'R5' ? current.server.targetVersion : null, machines }));
};
window.proof32924 = {
  ids, primaryId, seed,
  inspect: () => {
    let result;
    setUpdateEverythingRun(run => { result = run; return run; });
    return result;
  },
  settle: settleUpdateRunMachine,
  clear: () => setUpdateEverythingRun(() => null),
};
// Choose one, then hide the console and record an actual UI Retry click:
window.proof32924.seed('R1');
```

S1 = `seed('R1')`; S2 = `seed('R2')`; S3 = `seed('R3')`; S4 = `seed('R4')`. `inspect()` verifies target, result, failure and providerFailure before recording; also inspect `readConfig(id).environment.serverVersion` to document that target and reported version actually match. After capture: `window.proof32924.clear(); delete window.proof32924;` and reload the isolated page to release its temporary console bindings.

For S2/S4, connect the second isolated dev instance through `/settings/connections`, using its own pairing flow. Its source checkout's package version supplies serverVersion; the server does not expose a dev setting for arbitrarily overriding that descriptor. Two bare dev servers on the same version are sufficient for this state fixture because S2 stores a newer target only for B. This does not require installing or changing a real background service. Let the primary task owner run the second server from a separate sibling checkout with its own `.t3` state and tracked process, then stop it after capture.

**Baseline disclosure:** on bare dev, self-update is unsupported. Main will send the update and replace the seeded same-version error with the genuine “Remote updates require the T3 Code background service…” refusal; the capsule still remains failed/retryable. Head skips that call for A and settles it. Do not label that video as a reproduction of the launcher's exact rejection. For a faithful baseline with the exact rejection, use a controlled isolated boot-service environment already running an actual published T with its runtime available, seed the same failed target T, and click Retry through the real updater. Main hits the launcher's same/newer-version guard; head makes no call for A. No `service install` against the developer's existing installation is needed or appropriate merely to stage visual proof.

**Fidelity ranking:** a naturally occurring failed update followed by a current config and real click is strongest but depends on an unreliable failure/reconnect race. The most faithful deterministic capture for this branch is the full app with a seeded failed run, a real live config at T, and the real UI callback/RPC against an isolated boot-service host. The full app against bare dev is a useful disclosed alternative for visible behavior. A component harness with mocked config/held updater is last: label it **HARNESS**, identify the substitutions, and do not use it to claim live reconnect/version freshness. A screenshot of the new unit test or a rendered replica of the card is not any of these.

## Verification completed and limits

Read complete diff, both runtime implementations, render consumers, status/summary/closure logic, update callback, real config projection/snapshot handling, server-version source, launcher rejection, route/footer/width behavior, existing tests, PR description, linked issue, reviews/comments, and revision-bound check status. At inspection the forge reported 27 successful and 6 pending contexts on the reviewed head; this is not a check-wait audit. Prior approvals were attached to an earlier commit and are not visual evidence.

A scratch-only source-extracted logic harness executed the actual relevant functions from main and head with an in-memory registry/config and a controlled failed updater. **10/10 fixtures passed:** R1 closure, R2 mixed settlement, R3 provider failure, R4 retained done + provider-only failure, R5 local retention, null config retry, stale config retry, newer version settlement, stable-core/prerelease equivalence, older-nightly retry. For R1, main called current and remained failed/Retry; head called nobody and closed. For R2, main called both; head called only behind and retained done/failed. For R3/R4, main retained Retry; head had Dismiss. This is logic validation with mocked dependencies, not a rendered capture, not an existing-suite run, and not a network reproduction. Command: `node /tmp/lead-32924-r1/proof-audit-1/check-matrix.mjs`. Source test suites and repo-wide checks were not rerun in this read-only matrix pass.

No captures existed or were produced in this pass. No repository edits, pushes, PR/issue comments, app-state mutation, or dev-server starts were performed. All written files are under the requested scratch directory. No process remains running from this audit. The required next evidence is M1–M4, with honest seeding labels; controls need no speculative capture expansion.

AI-assisted; verified with the tests and tools listed above.

FRICTION: none

VERDICT: INSUFFICIENT R1–R4 before/after recordings are missing
