# Proof audit pass 1 — folded project settings

PR [#22828](https://git.cafe/pingdotgg/t3code/pull/22828), mirrored [#22827](https://github.com/pingdotgg/t3code/pull/22827).
Read-only audit of `/home/ubuntu/wt/issue-14991`: base [1688f96568](https://git.cafe/pingdotgg/t3code/commit/1688f965682d331da16a8c39f049592361f69c8d), HEAD [6326a82bec](https://git.cafe/pingdotgg/t3code/commit/6326a82bec42bf346ea92bdc7528d5d4713a2acc), plus in-progress uncommitted EventSink.ts, ProjectService.ts and ProjectService.test.ts retry patch. The working files were changing during inspection; pin their final revision before formal proof. No edits to repository, push, PR comment, server or browser launch, or test execution by this auditor. First command `df -h /`: 5.8 GB available, 81% used.

## Scope and branch model

Complete diff inspected: eight files, all under apps/server. Production changes are ProjectService.ts, serverSettings.ts, and the pending EventSink.ts patch. Five test files change (ProjectService, serverSettings, DeviceService, ProviderRegistry, ThreadSettlementService); the latter three adapt settings-service doubles to functional patches. No contracts, render components, CSS, desktop shell or mobile components changed.

The changed paths map project update fields scripts/model/workspace/autoPull to canonical overrides, hydrate folded project reads from those overrides, serialize functional settings edits, and perform settings writes before accepting a project-command receipt. Settings uses canonical scoped overrides directly; setup resolves scripts separately. Consequently service tests alone cannot prove MCP routing, live client settings propagation or actual worktree setup.

Folded reads deliberately differ by field: scripts inherit environment scripts when absent; model inherits environment when absent, but null explicitly means Automatic; disabled project model provider makes its override ineffective; autoPull inherits environment when absent but false is an explicit override; workspace returns only its project override or null, with actual inheritance resolved downstream (environment, then t3.json when environment null, then built-in). Do not require a null project workspace read to equal an effective runtime string. Scripts [] disables inherited actions; it is not inheritance. Clearing a setting in UI removes its scoped key; tool model null, scripts [], autoPull false are explicit values, whereas tool workspace null removes its key.

## Smallest fixture matrix

Affected means the observable result can change through this diff, including unchanged consumers. Existing evidence is limited to files inspected below; a test present in source is not a test run.

| ID | Affected path / fixture | Required assertion and smallest proof | Existing evidence / gap |
|---|---|---|---|
| A | Folded=true; real MCP tool writes one setup action and available explicit model | update response, t3_project_read and list/snapshot agree with canonical settings; Project Settings displays same action, command, role and explicit model/source; launch fresh worktree and inspect unique marker at worktree path. New thread model default should be observed without explicitly supplying a model. | before/after transcripts and screenshots support scripts/model read + Settings + setup marker; list/snapshot and new-thread model default not recorded. |
| B | UI saves distinct action/model after A; then tool updates them again | t3_project_read reflects UI values, tool subsequently replaces canonical values, next setup uses new action. This proves both directions rather than tool response echo. | Baseline UI save ran setup while tool read stayed stale. After-fix UI-to-tool direction not recorded. |
| C | Folded=true; all four fields nondefault; unrelated rename and omitted fields | omitted fields do not write settings; unrelated override (branch prefix/provider config), other project's overrides, and all four values survive. Include no override entry initially and a populated entry. | Source tests cover per-field rename and preservation; execution evidence needed. |
| D | scripts override nonempty -> [] -> UI inherit; environment scripts nonempty | [] returns/displays no actions and new setup runs no marker; remove key through Settings, then environment action returns and runs. Legacy script map cannot resurrect stale aggregate action after fold. | Source test covers []; inheritance with nonempty environment + actual setup not recorded. |
| E | model explicit -> null -> UI inherit; environment model distinct | null is project Automatic (not inherited explicit model); remove override restores environment selection. Disable selected provider at project/environment scope: effective read/Settings/new-thread default ignore disabled override consistently. | Source explicit/null test only; disabled-provider and nonnull environment branches need focused resolver/service proof; runtime/UI reset capture absent. |
| F | workspace explicit local/worktree -> tool null; environment explicit local/worktree | null removes project key, project read null, Settings/runtime inherit environment; changing environment now changes effective behavior. Test both explicit enum values without requiring screenshots for each. | Source test includes worktree and reset to environment local; execution proof needed. |
| G | workspace key absent; environment null; t3.json worktree/local then file absent | runtime/Settings use file value, then built-in fallback; project read remains null. Seed existing threaded git project so first-thread/new-project special case cannot mask defaults. | Source test resolves file worktree directly; no actual launch/file-absent evidence. |
| H | autoPull true -> false with environment true -> UI inherit | false must override true environment; deleting key restores true. Settings Source Control control, project read, and runtime consumer agree. Use isolated local git remote to avoid external pull side effects if runtime exercised. | Source true/false test; only default-false environment; no runtime/UI record. |
| I | Folded=true, stale persisted aggregate scripts/model/workspace/autoPull disagree with canonical entries, then canonical entries absent | stale aggregate-only saves remain ignored; reads match effective settings, including environment defaults. Re-save through tool activates intended values. Reopen isolated server to check durable behavior without re-folding stale fields. | Source test covers explicit canonical entries, not absent entries/restart. Existing baseline aggregate proves divergence but not compatibility after restart. |
| J | Folded=false legacy compatibility (service harness); then startup fold | raw hydrate keeps legacy fields; legacy script map array/null/absent and aggregate nonempty/empty follow existing precedence; canonical keys win fold; script null must not resurrect aggregate; once folded, reset survives reload. No new migration of old ignored writes. | Existing fold code inspected, unchanged. Regression harness sufficient; source diff does not prove these branches were run. |
| K | Functional patch under settings write lock; two edits same project, another project edit | merged persisted file retains both same-project fields plus unrelated/project-provider overrides; object patch callers still work. | New real-settings persistence unit test present; run result not independently supplied. Three doubles changed, requiring their focused suites. |
| L | Pending retry patch: first settings write fails before file change; same command retried | first call errors with no event/accepted receipt/project change; retry succeeds once; later Settings edit followed by replay must not be overwritten. Rejected/missing project cannot mutate settings. | New failure/replay source tests present; final patch and focused run evidence pending. |
| M | Pending retry boundary: settings file succeeds, SQL commit/receipt fails or process stops | distinguish file persistence from SQL transaction: callback is not a cross-store transaction. Establish retry behavior/accepted limitation; do not claim universal atomicity from L. Failure injection harness is appropriate, not screenshots. | No supplied proof for this boundary. Needed to qualify any atomicity claim; formal claim can be limited to failed settings write retry. |
| N | Read surface coverage, folded on/off: getById, workspace lookup, snapshot/list, includeDeleted | all hydrated reads honor same field semantics; read-settings failure maps predictably; update responses read current settings, not stale event payload. | Same hydrate function inspected; representative service harness assertions sufficient. Live MCP read is covered by A. |

These are branch fixtures, not fourteen independent browser sessions. Reuse one isolated fixture for A–I, vary settings in sequence and record commands/results. Use focused harness tests for J–N and disabled-provider combinations; do not grow screenshot coverage for internal error or locking branches.

## Minimum formal capture set

1. Pin baseline and final commit plus any dirty patch hash; record exact seed/settings, app origin, viewport and theme, tool requests/responses and setup-marker checks. Repeat A on final retry-patch revision. Existing after.txt identifies HEAD only and predates that patch.
2. For primary Settings before/after, use identical fixture/input and frame at **1440 wide light, 1440 wide dark, 390 wide light, 390 wide dark** (record actual heights, suggested 900/844). Each pair must expose changed Model source/selection and Actions; use extra scroll frames only if they cannot share a frame, particularly at 390. Actual Settings content differs (Automatic -> explicit, absent -> populated action), so these are applicable visual evidence states. Four matched pairs are the requested formal visual set, not coverage claimed by current files. Theme/width do not require separate backend test runs. 390 web viewport does not establish native mobile coverage.
3. One final-revision runtime transcript can cover A/B plus resets/inheritance D–I, recording persisted canonical values and actual setup-marker presence/absence. Include new thread default model and workspace behavior without explicit launch overrides that mask defaults. A separate 1440-light reset/inherited-state Settings frame is sufficient to show source/reset semantics; inspect Source Control separately if capturing autoPull. No animation changed; recording is optional unless claiming immediate propagation timing.
4. Attach focused test command/output for C–N and changed settings-service doubles, particularly retry/replay and concurrent persistence. Capture actual results after final patch; do not copy PR's historical test count as a new run. M may instead be explicitly disclosed as an unproven failure boundary with claims limited accordingly.

## Existing artifact inventory (inspected, not recaptured)

- before.txt: baseline runtime narrative names 1280x800 Chromium collaborative preview; tool saved setup/model but Settings ignored them, tool-created worktree lacked marker; UI save made setup work while tool read stayed old.
- tool-settings.png: 1280x800 light; Project Settings, Model GPT-6-Astra with Automatic label, no actions. It does not show tool calls or setup execution.
- after.txt: HEAD 6326a82bec, same isolated dev server; tool saved setup-fixed + explicit GPT-6-Astra, read matched, header reportedly updated, launched worktree marker true, canonical/legacy compatibility settings recorded, Settings matching narrative. This is a human-readable runtime transcript, not raw RPC/event logs.
- fixed-settings.png: 1280x800 light; explicit GPT-6-Astra without Automatic label, setup action and touch command. An unrelated update toast obscures part of the upper page; target rows remain visible. Baseline requested model is Sol while after requested model is Astra, so these are useful behavioral illustrations but not an identical-input pair.
- No existing 1440, 390, dark, reset/inheritance, autoPull, native mobile or desktop capture claimed. No proof of final retry-patch runtime present. No test result artifact inspected.

## Seed and real application versus harness

Use disposable .t3 state and a synthetic git fixture with a safe touch marker, available provider/model, distinct environment defaults, t3.json variant and a second project override. Existing evidence names issue-14991-fixture and isolated --home-dir; it does not document whether its database was copied from real state. Do not invent that provenance. A copied stopped-thread database via migrate-dev-db is acceptable for realistic navigation, but fixture creation and settings must be recorded; never open live ~/.t3/userdata read-write or run a server against it. Synthetic fixtures suffice for these deterministic branches and avoid publishing customer content.

Real application proof requires MCP call -> actual server service/settings persistence -> connected Settings UI -> actual prepared worktree marker. Resolver calls, in-memory layers, SQL fixture rows and fault-injection tests are harness proof, valuable for branch coverage but cannot replace the integrated chain. Existing A evidence is app-level by its transcript, with screenshots corroborating Settings only. Tool setup launch uses the same server path; no per-provider adapter changed. One available provider is enough for core integration; disabled-provider resolution belongs in harness. Desktop shares web render code, native mobile uses separate UI and remains unverified. Local vs remote/relay/tunnel transports are unchanged; no distinct transport claim is supported or necessary for this server-only regression.

## Friction

| Category | Happened | Avoided |
|---|---|---|
| Tooling / PR registration | T3 link_pull_request rejected the /pull/ URL as unrecognised; explicit host/repository/number linked successfully. | No gh fallback and no PR edits/comments. |
| Moving revision | Retry patch changed while being read; artifacts identify earlier committed head. | No claim that earlier captures validate the final patch. |
| Evidence provenance | Existing transcripts are narrative, only 1280x800 light images exist. | No invented dark/mobile/desktop coverage, seed provenance or test runs. |
| Resource / isolation | Root filesystem 81% used, 5.8 GB free. | No server, browser, dependencies, worktrees or heavyweight runs started. |

Pass 1 delivers the fixture/capture plan, not a final implementation approval. VERDICT: INSUFFICIENT — formal final-revision captures and test results pending; reset/inheritance, UI-to-tool after-fix, remaining defaults and compatibility branches lack recorded proof. Cross-store failure atomicity must be qualified or demonstrated.
