Skip to content

fix(codex): drain app-server stdout off the session loop - #61

Merged
chihsuan merged 6 commits into
mainfrom
fix/codex-stdout-drain
May 22, 2026
Merged

fix(codex): drain app-server stdout off the session loop#61
chihsuan merged 6 commits into
mainfrom
fix/codex-stdout-drain

Conversation

@chihsuan

Copy link
Copy Markdown
Member

Context

Codex app-server runs for RSM-3734 hit stdout EAGAIN when Symphony event handling fell behind the OS pipe.

TL;DR

Drain Codex stdout in a dedicated process before event handling.

Summary

  • Add a stdout pump process that owns Codex app-server ports.
  • Feed pumped lines into existing response and turn handling.
  • Document the stdio boundary and cover callback-blocked burst draining.

Alternatives

  • Only suppress more Codex notifications; that reduces output but still leaves slow handlers on the pipe path.

Test Plan

  • make all
  • mix test test/symphony_elixir/app_server_test.exs
  • mix specs.check
  • mix compile --warnings-as-errors
  • git diff --check

chihsuan added 3 commits May 22, 2026 00:17
Summary:
- Add a stdout pump process that owns and drains the Codex app-server port.
- Forward complete protocol lines to the existing response and turn handlers.
- Document the stdio transport boundary and add a burst-drain regression test.

Rationale:
- Slow transcript, audit, or callback processing should not block the OS pipe.
- Keeping the pipe drain separate reduces Codex stdout EAGAIN failures.

Tests:
- mix test test/symphony_elixir/app_server_test.exs
- mix specs.check
- mix compile --warnings-as-errors
- git diff --check
- make all

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses Codex app-server stdout backpressure (EAGAIN) by decoupling stdout draining from the session’s event-handling loop, ensuring that slow callbacks don’t block the OS pipe and stall the app-server.

Changes:

  • Add a dedicated stdout “pump” process that owns the Codex app-server port connection and forwards complete stdout lines to the session loop.
  • Update turn/response receive loops to consume forwarded :codex_stdout_* messages instead of reading directly from the port.
  • Expand test coverage to simulate callback blocking during large stdout bursts; update related docs/spec text describing the stdio boundary.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
lib/symphony_elixir/codex/app_server.ex Introduces stdout pump process and rewires port message handling/teardown.
test/symphony_elixir/app_server_test.exs Adds burst-drain regression test and updates guide-related tests to use AppServer.run/3.
SPEC.md Documents requirement to separate stdout draining from event processing.
docs/configuration.md Adds explanation of dedicated stdout draining process for Codex app-server.
symphony.yml Changes example config sandbox runtime from srt to none.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/symphony_elixir/codex/app_server.ex Outdated
Comment on lines +3662 to +3682
:ok
end
else
:ok
end
end

defp stop_port(port, _stdout_pump) when is_port(port) do
case :erlang.port_info(port) do
:undefined ->
:ok

_ ->
try do
Port.close(port)
:ok
rescue
ArgumentError ->
:ok
end
end
Comment on lines +3721 to +3724
{^port, {:exit_status, status}} ->
maybe_send_stdout_pending_line(state)
send(owner, {:codex_stdout_exit, port, ref, status})
:ok
Comment thread symphony.yml
Comment on lines 85 to 88
sandbox_runtime:
kind: srt # none | srt (Codex-only outer SRT wrapper)
kind: none # none | srt (Codex-only outer SRT wrapper)
command: srt
enable_weaker_network_isolation: false
chihsuan added 3 commits May 22, 2026 00:44
Summary:

- Wait for terminal markers before reading the persisted row.

- Leave production lifecycle event ordering unchanged.

Rationale:

- PubSub broadcasts happen before the run-store update returns.

- CI can receive the event while the row still has only the startup marker.

Tests:

- mix test test/symphony_elixir/orchestrator_status_test.exs:3404

- MIX_TEST_PARTITION=2 mix test --cover --partitions 4

- mix format --check-formatted

- make all
@chihsuan
chihsuan merged commit 8b3b546 into main May 22, 2026
11 checks passed
@chihsuan
chihsuan deleted the fix/codex-stdout-drain branch May 25, 2026 06:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants