gh shim: wait for Plexus's full reply window before reporting a bot write's outcome unknown
On 2026-10-30 a bot comment edit landed about 15 s after the shim sent it. The shim gave the whole governed exchange 20 s, part of it spent before sending, so it reported "outcome unknown" at 14.6 s. A check right after still saw the old text, which led to a duplicate post.
Change:
- Reply wait: once a write is enqueued, the shim waits up to 160 s for Plexus's reply. That covers Plexus's 120 s receipt lease, one final 30 s GitHub call, and 10 s of margin, as PLEX confirmed. SDK 0.32.7 ignores
send's timeout for reservations, so reservation admission, enqueue eligibility and the post-send reply now have separate bounds. A real post-send timeout keeps the existingoutcome_unknowntext, and that outcome is never retried. - Pre-send retry: one 4 s retry when Plexus is unreachable before anything is sent: warming, reloading or target unavailable, for the captured binding read, the reservation and the shim's binding-version check. A missing binding, a policy refusal and a binding mismatch never retry. Nothing after a possible enqueue enters this loop.
- Overall ceiling: 210 s per governed exchange. A new dispatch needs at least 175 s left; otherwise it refuses as not run, using the existing approved timeout line. No new wording.
- Cancel, drain and scope end: they still end the wait promptly, with their existing terminal frames. Long waits hold no admission or database lock.
Tests:
- A reply after the old budget succeeds with exactly one dispatch.
- A reply after the full 160 s is
outcome_unknownwith no resend. - The outage retry is bounded and shared between the binding read and the reservation, and real refusals never retry.
- No enqueue happens after the preflight deadline.
- A late known refusal declines to dispatch.
- Cancellation and scope end are prompt.
Verification: 12-core Linux targeted gates plus the strict Windows compile. Two Linux sandbox canary tests report Landlock as not enforced because the build servers' kernel lacks Landlock. GitHub CI is the check for those.
Conflict: this touches gh_shim_relay/mod.rs alongside #1178 (snapshot race). Whichever merges second gets a hand merge.
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes the GitHub shim reporting bot writes as "outcome unknown" when Plexus replied slower than the old 20s budget, which led to duplicate posts. This branch also folds in the refusal-explanation work from #1181.
- A sent write now waits up to 160s for Plexus's reply, covering the 120s receipt lease, a final 30s GitHub call, and 10s of margin.
- One bounded 4s pre-send retry applies only to typed unreachable errors; real refusals, binding mismatches, and uncertain writes never retry.
- The governed exchange ceiling is 210s, and dispatches with under 175s remaining are refused as not run.
- Cancellation, drain, and scope end still terminate the wait promptly with their existing terminal frames.
- Plexus and relay refusals now get operator-approved explanations describing what reached GitHub and how to rerun; the head-shell
not_governedrefusal mentions theGH_SHIM_BYPASS=operatorrerun path.