0e9b57d310
Follow-up to the per-file budget in the previous commit, which closed the scaling axis it measured and left three others open. * A per-file ceiling still lets the cost grow with the PROFILE count: a multiplexed gateway serves N profiles from one process and each has its own state.db, so `_READ_POOL_MAX` bounded each file while the process total went unbounded — the per-instance bug one level out. `_READ_POOL_PROCESS_MAX` (three files' worth) now bounds the process, and a miss reclaims an idle connection from ANY path before degrading: a profile quiet for an hour must not hold descriptors the profile being served right now needs. * Hermes's SQLite descriptors are only ever a share of the fd table. In #98573 the ~20 state.db handles were not the whole 256 — they were the share that pushed httpx sockets and terminal subprocess pipes over, and the EMFILE surfaced in tools/terminal_tool.py rather than here. New read connections are now refused when the process is within `_FD_HEADROOM_RESERVE` of its soft RLIMIT_NOFILE, measured from /proc/self/fd or /dev/fd and cached briefly. The guard fails OPEN where it cannot measure (Windows has neither the fd directory nor RLIMIT_NOFILE, and a CRT limit in the thousands) and CLOSED on evidence — including a probe that could not get a descriptor of its own. `_read_open_denied_fd_headroom` makes it diagnosable from a running process. * Writer connections cannot be rationed the way read connections can: a SessionDB without one cannot write. Their only real bound is not opening redundant handles, so a process that accumulates more than `_HANDLES_PER_PATH_WARN` handles on one file now says so once, and the next duplicate is visible before it is an incident instead of inferred from an lsof after one. `_READ_POOL_MAX` itself is deliberately unchanged at 8. Retuning that constant is #98585's subject; with a process ceiling above it and the headroom guard in front of it, the value is no longer the binding constraint. Refs #98573 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>