Skip to content

fix(rpc): record connection edges before Windows named-pipe idle exit - #1662

Open
code-yeongyu wants to merge 11 commits into
mainfrom
fix/windows-rpc-named-pipe-lifecycle
Open

code-yeongyu wants to merge 11 commits into
mainfrom
fix/windows-rpc-named-pipe-lifecycle

Conversation

@code-yeongyu

@code-yeongyu code-yeongyu commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Summary

Windows named-pipe RPC hosts no longer drop the public endpoint between ensureHost() readiness and the first real client, and the remaining turn-active lifecycle waiter no longer uses a nested 15s clock inside a 60s test.

Root causes (product)

  1. Authenticated connection edges (including short readiness probes) can fall entirely between idle ticks. The supervisor now records attach/detach and turn start/settle immediately so the idle window measures continuous inactivity.
  2. Post-readiness lock release and state writes could outlast a transient host's idle window on a loaded Windows runner, so the named pipe was gone before ensureHost() returned (connect ENOENT). The authenticated readiness connection now stays attached through the endpoint lock's commit and close.

Residual CI failure (test waiter, not ENOENT)

On head 3fbd2e673, run 34823696518 attempts 1–2 passed. Attempt 3 (job 103917291025) failed:

does not exit while a turn is active even with no connections; exits after the turn settlesTimed out waiting for RPC record at JsonlPeer.waitFor (default 15s). 30 passed / 1 failed / 3 skipped.

That stack is the record waiter, not connect ENOENT. The test never reached the no-connection idle assertion. Same SHA passed on attempts 1, 2, and 4, so this is a nested 15s budget vs loaded-runner session/prompt/agent_start latency, not a third product idle-race.

Fix (test-only): arm JsonlPeer.waitFor before scanning buffered records; mark sibling waiter timeouts handled; include seen {type,id,command} on timeout; bind open/prompt/agent_start waits to the case's existing 60s test budget; restore the mock API key for the held-model turn. No product idle-window change, no retries, no skips.

Head

231546b4a on origin/main 5fb5d638d (includes the waiter fix f04ecdc1a).

Proof still required on this head

  • Three consecutive green RPC named pipes (Windows) executions on 231546b4a (earlier-head streaks do not count).
  • Combined lifecycle/ensure/transport/daemon suites on the macOS proof host (pending; not claimed here).

Refs #1656

Plan: .omo/plans/omo-dependency-diet.md

@code-yeongyu

Copy link
Copy Markdown
Owner Author

Handoff caveat: main advanced again to 5d8c339 (PR #1665) after the requested rebase onto 7924335 and the three successful CI executions on head 4b7ba6b. GitHub now reports this PR CONFLICTING / DIRTY. All recorded acceptance results apply to 4b7ba6b against 7924335; they do not claim compatibility with the subsequently advanced main. No merge was performed.

Authenticated readiness probes can open and close between supervisor ticks. Record attachment and first detachment immediately so the idle window measures continuous inactivity rather than sampled connection counts. Extract the proxy for deterministic real-socket coverage of reconnect, exact expiry, and rejected authentication.

Verification: forced-ordering RED and mutation reproduce connect ENOENT; macOS lifecycle 33/33 on three runs; related RPC suites 40/40; static checks, build, RPC CLI QA and tool-loop QA pass. Broader mock-loop text-recovery QA has the same nine failures on base.

Ultraworked with [omo](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>

Plan: .omo/plans/omo-dependency-diet.md
@code-yeongyu
code-yeongyu force-pushed the fix/windows-rpc-named-pipe-lifecycle branch 4 times, most recently from 813696a to 50ef3f0 Compare September 14, 2026 04:00
Force post-readiness ensure work past the host idle window so the lifecycle contract fails deterministically before the production fix.\n\nPlan: .omo/plans/omo-dependency-diet.md
Keep the successful authenticated readiness connection attached until ensureHost is ready to return, so post-probe filesystem work cannot consume the transient host's idle window before the real client attaches.\n\nPlan: .omo/plans/omo-dependency-diet.md
Preserve the current Unreleased changelog entry while integrating the latest mainline release and webfetch changes.\n\nPlan: .omo/plans/omo-dependency-diet.md
Drive the real ownership-safe lock release and record readiness ownership on both sides, while retaining the existing premature inner teardown as the deterministic RED.\n\nPlan: .omo/plans/omo-dependency-diet.md
Transfer the successful readiness lease to ensureHost so it survives the ownership lock COMMIT and close, then release it in failure-safe final cleanup at the actual return boundary.\n\nPlan: .omo/plans/omo-dependency-diet.md
Preserve the RPC readiness handoff note while integrating the latest native grep and CI changes.\n\nPlan: .omo/plans/omo-dependency-diet.md
Preserve the RPC readiness handoff note while synchronizing the final verification head.\n\nPlan: .omo/plans/omo-dependency-diet.md
Preserve the RPC readiness handoff while keeping #1690's bundled-worker
supervisor-entry guard.

Plan: .omo/plans/omo-dependency-diet.md
JsonlPeer.waitFor defaulted to 15s and scanned before arming. The
turn-active lifecycle case already declared a 60s test timeout, so the
nested clock was timing luck on a loaded Windows runner (CI run
34823696518 attempt 3). Arm the waiter first, mark sibling timeouts
handled, and use the test budget for open/prompt/agent_start.

Plan: .omo/plans/omo-dependency-diet.md
Keep this PR's readiness/idle-clock and turn-active waiter changes
together with main's subsequent RPC and bundle work.

Plan: .omo/plans/omo-dependency-diet.md

# Conflicts:
#	packages/coding-agent/CHANGELOG.md
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.

1 participant