68b10bbbf9
iter_deleted_sqlite_sidecar_holders() returned [] on every non-Linux platform, so refuse_deleted_wal_generation() -- the pre-connect refusal that stops a second opener from minting a replacement WAL under a live writer -- was a permanent no-op on macOS. The reporter of #109641 hit exactly that: after an update/restart took the sidecars away, a fresh opener minted a new generation at the path, the still-live writer's next write raised DeletedWalGenerationError, and each event copied the whole database (16 halts / 13 minutes / 4.2 GB of captures). macOS has no /proc and never reports a " (deleted)" suffix, which is why the scan was restricted to Linux, but libproc does describe other processes' descriptors: proc_pidinfo(PROC_PIDLISTFDS) lists a process's fds and proc_pidfdinfo(PROC_PIDFDVNODEPATHINFO) returns each vnode fd's (st_dev, st_ino) plus the vnode's last pathname -- for same-user processes, without elevation. Both survive unlink, which is also why psutil.Process.open_files() cannot stand in for it (it hides unlinked descriptors, so the retired generation is structurally invisible). The judgement itself is unchanged and now shared: a descriptor counts only when it names a watched sidecar path while its identity no longer matches what that path holds, i.e. _fd_is_truly_unlinked()'s identity test (#108082), never a path suffix or a link count. Only the source of that identity differs per platform -- readlink on /proc for Linux, libproc for macOS -- and the darwin side resolves symlinks before comparing paths because libproc reports the kernel's path (/private/var/... where the caller opened /var/...). Scope is this one function: the enumeration legs, the gate (Windows still returns [] -- it cannot unlink a held sidecar) and the stale docstring reason. Enumeration failures keep the existing fail-open behaviour (logged at debug, no holders), and the new tests are marked macos_only so the existing Linux-only ones stay untouched. Cost, measured on macOS 26.4 (darwin 25.4.0) with 721 processes / 4383 vnode descriptors: ~20 ms per full enumeration, versus the Linux leg's ~11 ms / ~4.4k syscalls measured in #108910 -- the same order, paid once per open, on the platform where the guard previously did nothing at all. (cherry picked from commit f1501dfe7141e3c2521c5192857c37d7b60a922b)