fix: gateway-owned work fails through same-host relay#108423
Merged
Conversation
joshavant
marked this pull request as ready for review
July 15, 2026 19:21
joshavant
force-pushed
the
fix/issue-103636-gateway-owned-dispatch
branch
3 times, most recently
from
July 15, 2026 20:50
0ddea61 to
676a51f
Compare
joshavant
force-pushed
the
fix/issue-103636-gateway-owned-dispatch
branch
from
July 16, 2026 02:35
60cfa16 to
50e6919
Compare
joshavant
force-pushed
the
fix/issue-103636-gateway-owned-dispatch
branch
from
July 16, 2026 03:25
50e6919 to
377b26b
Compare
github-actions Bot
pushed a commit
to Desicool/openclaw
that referenced
this pull request
Jul 16, 2026
* fix(gateway): dispatch owned runtime work in process * fix(gateway): publish canonical approval resolutions internally * fix(gateway): seal owned approval runtime lifecycle * fix(gateway): keep instance runtime contracts acyclic * fix(gateway): remove stale runtime type imports * fix(agents): reconcile ambiguous recovery timeouts * refactor(gateway): constrain internal approval methods * fix(agents): route orphan recovery in process * fix(agents): preserve aborted restores for recovery * fix(agents): keep lifecycle waits in process * test(agents): type lifecycle runtime mock * test(agents): complete restored session fixture
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #103636
What Problem This Solves
Fixes an issue where Gateway-owned restart recovery and native approval work could fail when an operator's effective Gateway URL traversed a same-host relay. The relay correctly presented a non-loopback peer, but the internal backend client then lost the operator scope required to complete the workflow.
Why This Change Was Made
Gateway-owned work now uses least-privilege, instance-bound in-process principals instead of authenticating back into the same Gateway over WebSocket. This keeps host-interface peers remote, preserves the external authentication and device-pairing boundary, and makes internal authority independent of network topology.
The refactor also preserves request deadlines, approval client identity, canonical resolution publication, account isolation, replay/live-event deduplication, and terminal Gateway lifecycle cleanup. The plugin-facing approval adapter shape remains unchanged.
User Impact
Operators can use supported relay and proxy topologies without restart recovery or native approvals failing solely because an internal self-call returns through a host interface. External device-less host-interface clients still do not receive loopback-equivalent authority.
Evidence
98e88ab1a6b7: direct loopback succeeded while the host-interface relay failed backendsessions.createandagentcalls withmissing scope: operator.write(run_70cf95e93287).377b26b4815: the external relayed write remained denied, while startup recovery completed in-process withrecovered=1 failed=0, persisted the expected assistant marker, and opened no recovery self-WebSocket (run_c28accde9629).377b26b4815: a real persisted interrupted subagent bypassed its dead pre-restart wait, recovered and completed through the lifecycle-bound principal, produced its child and parent model turns, and opened no internal relay connection; the sole scope failure was the intentional external write probe (run_9780bb796fde).377b26b4815: all eight exec/plugin, live/replay, and resolve-after/resolve-during rows passed; every race row passed 9/9 with exactly-once delivery, callback, resolution, and finalization, and the configured relay saw no approval self-connection or scope/pairing failure (run_db7c259294b6).e1a16bab06ad: every delivery-race row passed 25/25 across three fresh Gateway processes, with exactly-once delivery/finalization and account isolation (run_b3cab0ad34ba,run_9559b7dfc1f3,run_8f8cfa1c0130).60cfa1656a34: 233 focused tests across the Gateway instance/startup runtime and subagent registry/recovery/announce-loop surfaces passed; fresh mandatory autoreview reported no actionable findings.tbx_01kxm1jqf8em1yjg5qs6hmyvvt: targetedpnpm check:changedpassed, including core/core-test typechecks, lint, boundary, database-first, and import-cycle gates;pnpm buildalso passed (run).AI-assisted: Yes (Codex).