## Why you see this output

The lines come from the `redact` package's OPF progress UX (`redact/opf.go`, `redact/batch.go`, `redact/redact.go`). The key detail is **where** they're written:

```go
var opfStderr = openTTYOrDiscard()   // opens /dev/tty, falls back to io.Discard
```

`opfStderr` is wired to **`/dev/tty`**, _not_ stdout or stderr. That's deliberate for production: the post-commit hook runs with `2>/dev/null`, so writing to the controlling terminal directly lets the "scanning…/done" progress survive that redirect.

The side effect: because it goes straight to your terminal, it **bypasses `go test`'s output capture** and shows up interleaved with `PASS` lines.

The tests producing it are the strategy-package OPF tests (`manual_commit_opf_rewrite_test.go` and friends). They configure a **fake** OPF runtime via `configureFakeOPF`:

```go
redact.ConfigurePrivacyFilterWithRuntime(redact.OPFConfig{
    Enabled: true, Categories: {"private_person": true}, Command: "/tmp/test-opf",
}, rt)   // rt is an in-memory fake
```

…but unlike the `redact` package's own tests (which set `opfStderr = io.Discard`), these tests **never silence `opfStderr`**. So the progress messages leak to `/dev/tty`. The `× unavailable (/tmp/test-opf)` line is the fail-closed test exercising the "OPF binary missing → fall back to regex layers" path; `/tmp/test-opf` is a deliberately bogus command path.

## Is it doing anything expensive?

**No.** Everything you saw is cheap, in-memory work:

- The runtime is a **fake stub** — `RedactBatch` just returns precomputed spans (e.g. `findSentinelSpans`). No subprocess, no Python/`opf` binary, no model load, no network. The `0.0s` timings confirm it.
- The `pip install opf` / `unavailable` line is a _fallback_ path — it does _less_ (skips OPF, runs only regex layers over a few tiny test blobs).
- Real OPF (what users get when `redaction.openai_privacy_filter.enabled` is true) shells out to a Python process and _can_ take ~30s — that's why the real pre-push prompt warns "may take ~30s." But that real path is never hit here.

So this is **harmless cosmetic leakage**, not a performance concern.

## If you want to silence it

The clean fix is to make `configureFakeOPF` redirect `opfStderr` to `io.Discard` for the duration of the test (matching what `redact`'s own tests already do), via a small exported test helper in `redact` — there's currently no exported setter, only the unexported var.

### Summary
- **Edge case the `/dev/tty` trick still covers:** if a future caller runs OPF (`usePrivacyFilter=true`) from a context whose stderr _is_ redirected — e.g. someone adds an OPF pass back into post-commit, or a wrapper that swallows hook stderr. Today nothing does, so this is purely hypothetical.

### Confirmed Changes
- OPF no longer runs at post-commit — it lives solely in the pre-push rewrite path, whose hook is installed without a stderr redirect. 
- Switching `opfStderr` from `openTTYOrDiscard()` to `os.Stderr` would actually be a net improvement:
  - **pre-push**: still visible (stderr isn't swallowed there).
  - **tests**: the progress would go to `go test`'s captured stderr instead of bleeding straight to the terminal.

This is local to the `redact`/strategy area and unrelated to your clean working tree's prior state.
