You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
The engine refuses its own codex app-server socket at mode 0755: codex binds under the inherited umask and chmods afterwards, and the engine verifies at first sight #136
Part of #67 — found by the v1.0 exit run #135 (20260828T074856Z, codex lane refused at engine start; claude lane 9/9 green).
What happened
The codex-lane engine exited 2 before binding its control socket:
AppServerError: /tmp/gpt-voicecoding-501/codex-app-server.sock is reachable by other accounts (mode 0755); refusing to use it
adapters/codex_app_server/process.py:260 attach → :217 verify_private_socket
That socket is the engine's own spawned codex app-server (process.py:_spawn, line ~457), not the shared daemon.
Root cause — measured, not inferred (advisor, 2026-08-28)
codex 0.150.1 creates its listen socket under the inherited umask (0755 with the default 022) and chmods it to 0600 afterwards. Five spawns polled at 1 ms: four first seen at 0600, one first seen at 0755 and 0600 a moment later; steady state is always 0600. The engine's _await_socket (process.py:~484) returns the instant is_socket() is true and attach verifies immediately, so under load it lands inside that window. _spawn passes no umask, so the child inherits whatever the engine has — the same bind→chmod window #116 closed for the engine's own listeners (private_socket.py:9-26: the mode comes from the umask at creation time), left open for the one listener the engine does not bind itself.
Fix
subprocess.Popen(..., umask=0o077) in _spawn — Python ≥ 3.9 sets it in the child between fork and exec. The socket is then born 0600 and the verify guard stays exactly as it is; no retry loop, no sleep, no relaxation of verify_private_socket. Derive the value from PRIVATE_SOCKET_MODE (0o777 & ~PRIVATE_SOCKET_MODE), the way private_socket.py:82 does — no second constant.
Test: spawn a tiny Python child through the same _spawn path (or a fake executable the tests already use) that binds a socket and reports its mode at creation; assert 0600. Also a test that the codex adapter's spawn passes the umask argument — the fake runner fixture in tests/conftest.py applies if a real process is not wanted.
Legacy
legacy@1d32845:bridge/codex.py:290-300 spawns the same app-server with no umask and had no privacy guard at all — the guard is v1's (#47/#116). New, not ported.
Also seen on the run, not this ticket's
The codex discovery degradation line "the Codex CLI is '0.150.1' and the running app-server is '0.149.1' — a Session started by this CLI will not join that daemon" appeared, as it did 93 times on the green run of record 20260827T100454Z (CLI 0.150.0) where #105 measured such a Session does join. The wording asserts what a measurement contradicted; low priority, recorded on #67.
Routing
Workflow: tdd
Executor: codex
Model: gpt-5.6-sol
Effort: high
Review: claude claude-opus-5 medium
Reasons: New runtime behaviour a mode-at-creation test pins (tdd); adapter-local, nothing downstream couples to it (non-core); approach fixed on the ticket, one line (routine); model and effort per Simon's 2026-08-28 override; serial chain head.
Done when
ruff/pytest green; PR with provenance; ticket open for the advisor to land. Then #135 re-runs in full (a code change after a run means a re-run).
Activity
197b1d8#135Simon-AI-coding commentedon Aug 28, 2026
/crew crewtask/5
Simon-AI-coding commentedon Aug 28, 2026
/crew crewtask/6
Keep spawned Codex sockets private from bind (#136)