Wait for Myra to become routable before drafting new agents - #698
Merged
TheGreatAxios merged 6 commits intoSep 10, 2026
Merged
Conversation
TheGreatAxios
force-pushed
the
cl-7543-wait-for-myra-to-become-routable-before-drafting-new-agents
branch
from
September 9, 2026 23:47
b0d05f9 to
f16b13d
Compare
A freshly provisioned run's sidecar takes several seconds to boot and register with the hub, so the opening drafting mail can land in that gap and fail with a plain 'agent is unreachable' error. Cover the bounded wait-and-retry behavior the one-shot send must gain, the typed rejection when the wait expires without the address ever becoming routable, and the draft route mapping that typed failure to the canonical 422 drafting_failed envelope. A non-unreachable send error must still reject as-is with no retry. OneShotRunUnreachableError is defined here inert so this commit typechecks standalone; the implementation change wires the send path to reject with it.
A freshly provisioned run's sidecar takes several seconds to boot and register with the hub, so the opening drafting mail could land in that gap, fail with a plain 'agent is unreachable' error, and escape the draft route's typed-failure map as an HTTP 500. The one-shot send now goes through the same bounded deliverWhenRoutable helper the webhook launch path uses: send once, poll the hub's live routing table until the address is routable, then send exactly once more. Residual unreachability rejects with OneShotRunUnreachableError wrapping the cause, which the draft route maps to the canonical 422 drafting_failed envelope; every other send failure still rejects as-is. The run's settle/undeploy still runs exactly once on every exit path.
The webhook launch deps and the planner one-shot runner deps each inlined the same lambda reading the sidecar routing table. Hoist it to one named local in createHub and pin the shared wiring with a source scan in the style of the crypto-provider cache wiring test, so a regression replacing either path with a constant predicate fails.
The reply timer can settle and tear down the run while the routable wait is still polling; a send failure arriving after that is a phantom for an already-gone run and is now dropped instead of reported. An unreachable-shaped cause is now distinguishable from any other send failure: it settles as planning-run-send-unreachable and reports under agent-directory.one-shot.send-unreachable, so a wait that expired is greppable in the error log without new telemetry plumbing. Also correct the OneShotRunUnreachableError wording — the address may well have become routable mid-poll with the retried send failing, so 'never became routable' overclaimed — fix the isRoutable JSDoc to describe send-once, poll, retry-once accurately, rename tests that promised coverage they did not deliver, pin that the runner consults isRoutable with the launched run's address, pin that the reply timer beats the wait and that no send follows the teardown, and yield the poll loop to timers with real sleeps so timer-dependent tests are not starved.
The bounded retry and the typed 422 drafting failure both hinge on the vendor session service throwing an error whose message contains 'agent is unreachable' and on the substring classifier sniffing exactly that. A source-pinning scan fails loudly if either side drifts; the vendor file itself is never touched.
The contract scan previously accepted any mention of 'agent is unreachable' anywhere in the vendored session service, including its doc comments — a drift of the thrown message alone would have left the pin green while the classifier stopped matching real vendor failures. Match the throw expression itself instead.
TheGreatAxios
force-pushed
the
cl-7543-wait-for-myra-to-become-routable-before-drafting-new-agents
branch
from
September 10, 2026 00:44
0db68d7 to
d6ab1ba
Compare
TheGreatAxios
deleted the
cl-7543-wait-for-myra-to-become-routable-before-drafting-new-agents
branch
September 10, 2026 05:16
3 tasks
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 #696
Linear: CL-7543
Problem
Creating a new agent could fail with a generic "Something went wrong" + reference ID: the one-shot drafting path provisions a temporary Myra run and sends its first drafting message immediately, but the run's sidecar may not be registered with the hub yet. The send dies with a plain "agent is unreachable" error that matches none of the draft route's typed drafting failures, escapes as an unhandled throw, and surfaces to the user as an HTTP 500 — before the agent-definition create request is ever made.
Fix
deliverWhenRoutablehelper from@corbits/workflows— the same pattern the webhook launch path uses: send once, poll the hub's live routing table until the address is routable (250 ms poll, 20 s deadline), then send exactly once more.OneShotRunUnreachableErrorwrapping the cause, which the draft route maps to the canonical 422drafting_failedenvelope with the standard user-facing message — never a bare 500.isRoutablefrom the same routing-table source the webhook launch path uses.Test plan
bun test packages/agent-directory: 259 passing, including new cases for retry-once-after-routable (exactly 2 sends, single undeploy), never-routable expiry (typed rejection, single settle), mid-wait flip after several polls, non-unreachable errors rejecting untouched, and the 422 route mapping.bun run typecheck,bun run lint,bun run check:structuralall exit 0; full pre-push gate (format, lint, typecheck, unit matrix) green locally with Postgres up viadocker compose -f docker-compose.test.yml.