# N2 empty-state UI pairing / protected persistence / cold restart — CLOSED

Only N2 is addressed. This is fresh native capture evidence, not a new review or a claim about other matrix rows.

Baseline [044f07257c](https://git.cafe/pingdotgg/t3code/commit/044f07257c9684ae4543bd1e1ebf9c394e9e3830), corrected HEAD [fdee11371a](https://git.cafe/pingdotgg/t3code/commit/fdee11371a81e2132cf2a24e7a133e4cade7a8b7). Both working trees remained clean. Reused native bundles match the previous provenance exactly: baseline SHA256 `57a61ad969808a59b16ebcfb86aa565cdf5d97f032092421df90806680897d92`; HEAD `9838ed54702140be5fb12a482248ed04f1d85c01c0f8c74de315a916343c6a2b`.

## Fixture and method

Actual bundled Electron apps, real GNOME private keyring and private D-Bus session, Xvfb/Openbox on display :103. Same account, app identity, copied disposable keyring, disposable authenticated target at port 4788, light theme, and full 1440×1000 framebuffer at DPR 1. Actual Electron outer/content bounds were 1439×999 at (0,0) on both builds; framebuffer captures remain 1440×1000 without crop or scaling. Existing theme/width pairs were not repeated.

Each build started with its own fresh T3 home: both `connection-catalog.json` and `saved-environments.json` were verified absent before launch. Only the automatically discovered local computer appeared initially. No catalog or connection fixture was seeded. The target data was copied into this capture's disposable directory; no server used live ~/.t3. Each run needed a fresh single-use pairing link for the same target, so newly issued credentials differ by design.

The actual onboarding Add a computer button was clicked, the visible Pairing link input filled, and Pair clicked. DOM input/click automation was sent through Electron's main inspector into the real renderer; no mock, isolated component, direct registration call, or bridge setter supplied the connection. Read-only desktop bridge calls inspected the resulting catalog. Pairing itself performs the protected save; this form has no separate Save button.

Both builds then visibly showed target 4788 Connected, persisted an encrypted catalog, and reconnected after complete Electron process termination and a new launch without credential entry. The UI remains on Connect intentionally: N2 proves adding/persisting the computer, not provider or project setup.

## Continuous recordings and timestamp narration

Times below are seconds from each continuous recording's beginning. There are no cuts or speed changes. Only the secret input rectangle is blacked out during entry/submission, with one-second safety margins. The Pair button remains visible. Inspector output, raw catalogs, tokens, and logs are not uploaded.

Before / baseline recording: [base-N2-ui-add-save-restart.mp4](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/0bf2d799eca7b8a4/base-N2-ui-add-save-restart.mp4). Duration 180.8s.

After / corrected HEAD recording: [head-N2-ui-add-save-restart.mp4](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/0df2a2ee4c843713/head-N2-ui-add-save-restart.mp4). Duration 78.5s.

| Interaction | Before: baseline | After: HEAD |
|---|---:|---:|
| Cold launch: no catalog and no legacy registry; GNOME unlocked. | 0.01s | 0.00s |
| Existing onboarding reached; expand Add a computer. | 33.52s | 33.84s |
| Enter fresh disposable pairing link into visible wizard form; secret field redacted in public recording. | 106.93s | 42.40s |
| UI pairing succeeded: disposable target 4788 visibly Connected; UI persisted catalog. | 121.62s | 49.48s |
| Quit Electron completely, then cold restart same fixture without entering credentials. | 125.03s | 52.97s |
| After cold restart, target 4788 is visibly Connected without credential re-entry. | 177.49s | 71.31s |

These timestamps are action/observation marks, not controlled latency measurements. Interactive inspection and pairing issuance account for different idle durations. No performance comparison is inferred.

## Native persistence and IPC observations

On each build, the actual getConnectionCatalog IPC result had keys schemaVersion, targets, profiles, credentials, remoteDpopTokens, disabledEnvironmentIds. It contained exactly one BearerConnectionTarget, one BearerConnectionProfile pointing at the disposable target, one BearerConnectionCredential, and zero remote DPoP tokens. The local desktop computer is discovered separately. After restart, IPC still returned one target/profile/credential and the target visibly authenticated as Connected. Secrets and raw catalog objects are retained only privately.

Both on-disk files contained exactly version and encryptedCatalog, version 1, with nonempty ciphertext; no plaintext credentials field. The legacy registry remained absent. Actual selected native backend: gnome_libsecret. HEAD's encrypted file SHA256 was equal before/after restart. Baseline credential preservation is established by cold reconnect without re-entry and the persisted credential count; no baseline pre-restart hash claim is made.

## Matched before/after stills

### Added

![Before — baseline added: authenticated disposable target connected](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/36b29e6bd3b464f3/base-added.png)

![After — corrected HEAD added: authenticated disposable target connected](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/d7eac5ac68033934/head-added.png)

![added: absolute RGB difference amplified 8 times](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/fa5bbd504d6d6bae/added-Diff0-gain8.png)

![added: pixels with maximum channel difference greater than 8 of 255](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/b0dc492052e1f445/added-DiffT-gt8.png)

### Restarted

![Before — baseline restarted: authenticated disposable target connected](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/e44bb18870314573/base-restarted.png)

![After — corrected HEAD restarted: authenticated disposable target connected](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/8232745cdc606a35/head-restarted.png)

![restarted: absolute RGB difference amplified 8 times](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/b4554570607af680/restarted-Diff0-gain8.png)

![restarted: pixels with maximum channel difference greater than 8 of 255](https://gh-file-drop-api-prod-mi5fy3sowv63ufte.pinglabs.workers.dev/f/95a9f80f853edc5f/restarted-DiffT-gt8.png)

Both pairs are pixel-identical across all 1,440,000 framebuffer pixels: 0 pixels changed at any magnitude; 0 pixels >8/255; maximum channel difference 0. Diff0 is clamp(8×abs(after−before), 0, 255); DiffT is white iff max(abs RGB difference)>8/255, otherwise black. Comparison uses the original lossless full-framebuffer PNGs, not video frames.

## All visible changes

Between baseline and HEAD in the matched added and restarted states: none. In both recordings, Add a computer expands the pairing form; filling enables Pair; submission collapses the form and adds the second Connected computer row; restart removes/recreates the app window and returns to Connect with both rows Connected. The remote row is below the local row immediately after adding and above it after restart on both builds. Expanded onboarding re-centers vertically. Focus/caret/pointer and transient startup frames differ in time across independently driven recordings; they are not asserted pixel-identical. The only editorial change is the documented black secret-field rectangle during submission. No new native unlock prompt, save error, or credential-entry request appeared in this unlocked-keyring flow.

## Cleanup and private artifact paths

All captured app/recorder/target process groups exited. Private D-Bus, keyring, Openbox, Xvfb, and accessibility processes were stopped. A final /proc environment audit found zero processes using this capture's private XDG runtime/data environment. Ports 4788, 9339, 3774, and 3775 had no listeners after teardown. Temporary first-launch processes were also stopped.

Cleanup root: `/tmp/issue9239-n2`. Public allowlist: `/tmp/issue9239-n2/public`. Private fixture homes: `base-home`, `head-home`, `target`, `config`, `data`, `runtime` below that root. Drivers, raw recordings, inspector measurements, catalogs, and pairing output outside public are private and must not be uploaded. Existing `/tmp/issue9239-evidence` and `/tmp/issue9239-audit-pass2` were read/reused, not deleted.

## FRICTION

FRICTION secret-display | The wizard renders a pairing URL as plain text | Published recordings redact only the input rectangle during secret entry/submission; Pair and surrounding workflow stay visible. No tokens, raw measurements, catalogs, or logs uploaded.

FRICTION capture-geometry | Openbox reports 1439×999 app bounds for a requested 1440×1000 window | Both builds use exactly the same actual bounds; full framebuffer is 1440×1000, DPR 1, unscaled.

FRICTION harness | Initial interactive Python launch had closed stdin and left its disposable X/WM/target running | Reattached workflow with a PTY/private session, stopped the first target and all remaining private X/WM processes, verified no private environment processes remain.

FRICTION process-stop | Cold restart uses tracked process-group termination, not the app menu Quit command | Electron exits reported -5 after termination on both builds; each replacement process launched fresh and authenticated. This proves cold process restart, not graceful shutdown behavior.

FRICTION repaint | One read-only capturePage size diagnostic typo returned an inspector exception | It did not mutate app state or interrupt capture; full framebuffer screenshots and recordings were captured and independently compared.

N2 verdict: CLOSED. No implementation changes, forge writes, pushes, or watchers.
