chore: combine relay #1917, #1923, #1881 (merge commit, do not squash)

Merged
KH
16d ago
+4696-170

One PR so the three reviewed, individually green relay PRs can be merged at once.

MERGE WITH A MERGE COMMIT (not squash/rebase) so #1917/#1923/#1881 close as merged. Their exact head commits are merged here with git merge --no-ff; a merge commit makes them reachable from main, which marks the originals merged.

Included heads (merged in this order)

  • #1917 54c441210ca3cdd07ac66530819bec300902f077 (fix/1915-agent-register-pressure-retry): the broker retries Relaycast d1_pressure on agent.register, agent.deregister, delivery.ack and non-task action results with bounded backoff and a 25-second budget. Persistent registration pressure becomes a named retryable spawn error, and late successful registrations are deregistered.
  • #1923 2aa0afb1adff8b8454a738abbc764489ba0b1654 (fix/1919-fleet-release-persisted-route): workspace-scoped commands such as fleet release prefer the validated persisted Relaycast route over an ambient RELAY_BASE_URL when --base-url is omitted. An explicit conflicting --base-url still fails closed.
  • #1881 5e51d9a95f7bf0361ee83669518cfc13af224c6b (feat/agent37-async-preparation-client): fleet spawn --sandbox uses Cloud's durable async-v1 preparation, polling by exact sandbox identity and never replaying ensure. A terminal Cloud record is reported with its typed cause, plus whether any sandbox was left running. Older Cloud deployments still work, including their typed 5xx errors.

Review status

  • #1917: Linux-verified.
  • #1923: GO.
  • #1881: GO-WITH-CONDITIONS. All conditions are fixed at 5e51d9a95. Two P3 test nits (a comment wording and a stricter sbx_ UUID pattern) are queued for a follow-up and acknowledged on the threads.

Deployment

cloud #4137 is separate and must be deployed via the FULL path; do not fast-path. Deploying Cloud before relay is the recommended order. Merging relay first is also safe: the #1881 client handles a Cloud without async-v1.

RelayFlow PR proof

This combined PR touches two RelayFlow cases: 1919-fleet-release-persisted-route (#1923) and 1763-zero-config-sandbox (#1881). The single-case PR-proof contract (scripts/pr-proof/prepare.mjs, exactly one declared case per PR) therefore cannot apply here, and no proof markers are declared. Each case's proof passed on its own PR: 1919-fleet-release-persisted-route on #1923 and 1763-zero-config-sandbox on #1881. The case files are byte-identical here (see the per-PR zero-diff proof below).

Conflict resolution

The only conflict was CHANGELOG.md [Unreleased]. A follow-up commit (d895cc508) moved #1917's two entries out of the released [13.1.5] heading into [Unreleased - Minor], so [13.1.5] and everything older is identical to main. It now has a single heading, and every entry from all three PRs is kept unreworded. The heading is [Unreleased - Minor], not Patch, because #1881 adds public API (preparationMode, onPreparationProgress, sandboxAbsent, preparationFailure); the repo rule makes the pending level monotonic. #1917's two entries sit under the released [13.1.5] heading exactly as on its branch; they were not moved.

Proof that nothing else changed

  • For each PR, git diff <pr-head> HEAD -- <that PR's files except CHANGELOG.md> is empty: #1917 (4 files), #1923 (9 files), #1881 (7 files) all show 0 lines.
  • git diff --name-only origin/main HEAD lists 21 files, exactly the union of the three PRs' file lists.

Local checks

  • npm run typecheck (packages/cli and its dependencies) and tsc --noEmit for packages/cloud and packages/sdk: pass.
  • vitest on fleet-sandbox, fleet, sdk-client, relaycast-groups, integration-subscribe, fleet-lifecycle-integration and fleet-spawn-confirmation: 7 files, 407 tests passed.
  • Prettier check on all changed files: clean.
  • Broker cargo +1.97.0 test -p agent-relay-broker --lib node_control::: 117 passed, 0 failed.

🤖 Generated with Claude Code


[!NOTE]
Medium Risk
Touches fleet broker reconnect/retry semantics and Cloud sandbox provisioning paths used by fleet spawn; mis-handling could duplicate sandboxes or mis-route workspace commands, but changes are bounded with extensive tests.

Overview
Combines three fleet reliability fixes: broker control-plane retries, workspace route resolution, and async Cloud sandbox preparation.

Relaycast d1_pressure on the broker (node_control.rs): Fleet node control now retries transient d1_pressure on the live WebSocket with exponential backoff capped at 25 seconds (five attempts). Covered paths include agent.register, acknowledged agent.deregister, delivery.ack, and non-task action.result frames; exhausted non-task results are retained and replayed after reconnect. Persistent registration pressure surfaces to spawn callers as a spawn_retryable placement error when registration failed before mutation; late successes after the caller gave up trigger a compensating deregister.

Workspace-scoped CLI routing (sdk-client, integration/fleet): Commands without --base-url use the persisted Relaycast route and route-scoped API key instead of ambient RELAY_BASE_URL. Local broker session URLs move to fallbackBaseUrl so they do not override persisted routing; an explicit --base-url that conflicts with the persisted route still fails closed.

fleet spawn --sandbox (unpinned / Agent37): Provisioning uses Cloud async-v1 preparation with onPreparationProgress phase logging, prints the generated sbx_ identity before Cloud work (resume via --sandbox-id), and reports terminal preparation failures via typed CloudFleetSandboxProvisionError fields (sandboxAbsent, preparationFailure) without redundant cleanup when Cloud confirms no sandbox is running.

Reviewed by Cursor Bugbot for commit d895cc5082ed393a5bee2dc04578f63304f8aa59. Bugbot is set up for automated code reviews on this repo. Configure here.