# PR #23690 proof matrix (audit pass 1)

Head `b2948332e2`, base `60b35a1ee0`. Tests are in `apps/server/src/project/AgentSessionScanner.test.ts` at `b2948332e2`.
The 4 new FIFO tests (L1680–1851) are under `describe.skipIf(win32)` and are `it.live`. "Body RT" means the body's runtime table (ed3f965e07 vs a5920956c4; a5920956c4 has an identical PR diff, so it counts as head).

| # | Row | Affected | Proof | Status |
|---|---|---|---|---|
| 1 | Windows in-process fallback (`isWindows` → readFileString, concurrency 1) | read order only (phased instead of per-dir) | none; CI or this box are not win32 | UNVERIFIABLE here |
| 2 | Memo hit (`blockedGitFilePaths.has` → "" with no spawn) | yes (new) | Body RT strace: scans 2–5 spawn `cat` only for the normal repo. Test "completes every scan when a .git pointer file or commondir never opens" reuses one scanner across 5 scans, but with a 5 s per-scan bound a 2 s re-wait would still pass, so no test asserts it | PARTIAL: no test, runtime only |
| 3 | cat success (code 0 → stdout) | yes (new transport) | "skips linked git worktrees and reports the origin…" (L771), "offers bare-repository worktrees…" (L835), "still reads the git identity of repositories next to a blocked one" (L1709) | PROVEN |
| 4 | cat non-zero exit (missing file → "") | yes | No fixture has an existing `.git` dir without `config`, or a pointer to a missing gitdir/commondir. `plain` (L771) has no `.git` at all, so stat is None and no read happens | UNPROVEN |
| 5 | Timeout → `timedOut` → memo add | yes (new) | L1680/L1709/L1760/L1805 hit the timeout path (scans finish within the deadline). Memo add is only implied by Body RT strace | PROVEN (timeout); memo add see #2 |
| 6 | >1 MiB truncate cap (`outputMode: truncate`, then code===0?) | yes: main read the whole file. Now origin after 1 MiB is lost, and if the truncated read is non-zero the whole config becomes "" | none | UNPROVEN |
| 7 | Spawn error → `orElseSucceed("")` (e.g. no `cat` on PATH) | yes (new) | none | UNPROVEN |
| 8 | `.git` missing → NotGit (git: null) | no | L771 `plain` → `git: null` | PROVEN |
| 9 | `.git` directory → Repository | transport only | L771 `repo`, `noRemote` | PROVEN |
| 10 | Pointer → non-worktree gitdir (submodule) → Repository | transport only | L771 `submodule` → vendor origin | PROVEN |
| 11 | Pointer empty/garbage → NotGit | no | Empty: L1805 (FIFO pointer → "" → listed with no git). Garbage non-empty text (no `gitdir:` line): no test | PARTIAL: garbage UNPROVEN |
| 12 | Linked worktree, non-bare common config → Worktree (skipped) | transport and phase | L771 `worktree` absent from candidates | PROVEN |
| 13 | Linked worktree, bare common config → Repository | transport and phase | L835 `dev`/`prod` listed with origin | PROVEN |
| 14 | Linked worktree, empty commondir → Worktree | no | Only the blocked case: L1805 FIFO commondir → "" → skipped. A real empty file is not tested | PARTIAL (same branch) |
| 15 | Three phases (pointer → commondir → config) in one scan | yes (new) | L1760 mixes dir repos and pointer worktrees with commondir and a bare config; L771/L835 mix all kinds | PROVEN |
| 16 | Dedupe: two worktrees share one config path | yes (new) | L1760 (≤4 s with 3 blocked unique configs). Timing passes even without dedupe because concurrency is 16. Nothing counts spawns | PARTIAL: dedupe UNPROVEN |
| 17 | Pre-resolution: non-directory cwd (regular file) | refactored | Only missing paths are tested: "drops candidates whose directory no longer exists" (L705). A cwd that is a file is not tested | PARTIAL |
| 18 | Pre-resolution: excluded path | refactored | L723, L750, L904 | PROVEN |
| 19 | Pre-resolution: symlink into worktrees dir | refactored | L926 | PROVEN |
| 20 | Normal/worktree/bare/submodule read identically before vs after | claimed no | The L771 and L835 expectations are unchanged by the diff (only additions in the test file), so they are the same assertions on base and head. No side-by-side run is recorded | PROVEN by unchanged tests; base run not recorded |
| 21 | >1 MiB `.git/config` before/after behaviour | yes | none (see #6) | UNPROVEN |
| 22 | Timeout memo: a later scan does not wait again (timing) | yes | Body RT strace only. No test measures scan 2 < deadline | UNPROVEN (test/timing) |
| 23 | `/.well-known/t3/environment` responsive after ≥5 scans | yes | Body RT: 200 in 4 ms after 4–5 scans | PROVEN (body RT) |
| 24 | Unrelated fs **route** responsive after ≥5 scans | yes | Tests L1680/L1805 do an in-process `readFileString` after 5 scans. No HTTP fs route was exercised in Body RT | PARTIAL: route UNPROVEN |
| 25 | Process cleanup: no leftover `cat`, ps output | yes (new children) | Body RT says "No `cat` left running" (strace), but shows no ps output | UNPROVEN (needs ps transcript) |
| 26 | Windows path | n/a | not testable on Linux | UNVERIFIABLE |
| 27 | macOS TCC | n/a | A FIFO stands in (L1680–1851, Body RT). Whether SIGTERM/SIGKILL kills a `cat` blocked on TCC is not verified | UNVERIFIABLE (FIFO stand-in proven) |

Side notes:
- The memo never expires (it lasts for the service lifetime). A transiently slow file (for example a NFS hiccup over 2 s) stays "" until the server restarts. No proof row covers this; it's a behaviour change worth flagging.
- Excluded realPath: on main the key was set to "" for the resolved path. Now the candidate is skipped by `continue`. The effect looks equivalent, and L926 covers it.
