Severity: High · correctness · confidence high
Location: app/Sources/Yap/BackendManager.swift:177
Impact: If the sidecar exits, future reads cannot recover until Yap is restarted, leaving the core read-aloud flow broken.
Evidence: launchProcess() returns immediately when process is non-nil (line 178). waitForHealth() detects an exited process at lines 251-253 but does not clear process, reset ready, or release ownership. AppState.stream() only calls backend.start() when ready is false (AppState.swift:546), so a backend that dies after becoming ready bypasses recovery and sends the next request to the dead process (AppState.swift:575). Even when the death occurs during startup, subsequent start() calls still hit the non-nil process guard.
Recommendation: Install a termination handler or clear process, ownsProcess, and ready when the child exits. Ensure start() treats a non-running Process as absent and relaunches it before serving the next read.
Cross-validated by: codex — Confirmed. If the locally spawned sidecar exits after readiness, ready remains true and the next read skips backend.start(); if it exits during startup, process remains non-nil and the launch guard also prevents recovery. A normal subprocess crash or termination therefore leaves the core read-aloud flow unavailable until Yap restarts, matching the claimed high severity.
Filed automatically by latent-git-agents (auditor, agent: codex). Dedupe token: latent-audit-fp-a6b3f5cad9af7e4a
Severity: High · correctness · confidence high
Location:
app/Sources/Yap/BackendManager.swift:177Impact: If the sidecar exits, future reads cannot recover until Yap is restarted, leaving the core read-aloud flow broken.
Evidence: launchProcess() returns immediately when process is non-nil (line 178). waitForHealth() detects an exited process at lines 251-253 but does not clear process, reset ready, or release ownership. AppState.stream() only calls backend.start() when ready is false (AppState.swift:546), so a backend that dies after becoming ready bypasses recovery and sends the next request to the dead process (AppState.swift:575). Even when the death occurs during startup, subsequent start() calls still hit the non-nil process guard.
Recommendation: Install a termination handler or clear process, ownsProcess, and ready when the child exits. Ensure start() treats a non-running Process as absent and relaunches it before serving the next read.
Cross-validated by: codex — Confirmed. If the locally spawned sidecar exits after readiness,
readyremains true and the next read skipsbackend.start(); if it exits during startup,processremains non-nil and the launch guard also prevents recovery. A normal subprocess crash or termination therefore leaves the core read-aloud flow unavailable until Yap restarts, matching the claimed high severity.Filed automatically by latent-git-agents (auditor, agent: codex). Dedupe token: latent-audit-fp-a6b3f5cad9af7e4a