Skip to content

Generate cloud dispatches on the entire-api cell - #2721

Open
Soph wants to merge 4 commits into
mainfrom
soph/dispatch-off-bff
Open

Soph wants to merge 4 commits into
mainfrom
soph/dispatch-off-bff

Conversation

@Soph

@Soph Soph commented Oct 9, 2026 •

Copy link
Copy Markdown
Collaborator

https://entire.io/gh/entireio/cli/trails/1535

What

entire dispatch (cloud mode) now generates on an entire-api cell instead of the BFF's POST /api/v1/dispatches/generate.

Why

The BFF route only resolved the repos and read checkpoints from one jurisdiction's cell, picked by ?jurisdiction= or the caller's home. entire-api serves the same generation at POST /me/dispatches, so the CLI can dial that cell itself, the same way activity and recap do.

Changes

  • runServer (dispatch/mode_cloud.go) builds one CellClientFactory per run and dials the --jurisdiction cell, or the home cell without the flag. The client is built after the local window and origin checks, since building it already dials.
  • The cell route is async: POST /me/dispatches answers 202 with a generating run, and CloudClient (dispatch/cloud.go) polls GET /me/dispatches/{id} every 2s until it is complete or failed. A 3-minute budget outlasts the cell's 2-minute stale threshold. A failed run surfaces its error message.
  • Wire types follow the cell's camelCase shape and drop BFF-only fields nothing rendered (branches sentinel, warnings, totals).
  • Removed the jurisdiction echo check, since the client picks the cell itself, and the dispatch-local HTTPS guard, since the cell factory already refuses a plain-HTTP data host before sending the login JWT.
  • The dispatch wizard reads the home jurisdiction from the same factory through a new CellClientFactory.HomeJurisdiction().
  • docs/development/api-routing.md documents cloud dispatch routing. upstream-host-resolution.md no longer lists dispatch as a BFF caller.

Behavior changes

  • The cell persists runs, so CLI dispatches now appear in the user's dispatch history on the web.
  • A window with no checkpoints fails with the cell's 404 (no checkpoints in window) instead of generating.

Tests

  • Cloud client tests cover polling to completion, a failed run, an unknown status, and the poll stopping when the context ends.
  • Run tests stub the new newDispatchCellClient seam. TestServerMode_RejectsPlainHTTPBaseURL runs the real cell routing.
  • mise run check passes. Not yet exercised against a live cell.

Note

Medium Risk
Changes the production dispatch API contract and adds async polling/timeouts; routing and auth now depend on cell catalog resolution rather than the gateway selector.

Overview
Cloud dispatch no longer hits the BFF’s one-shot POST /api/v1/dispatches/generate with a ?jurisdiction= query. It dials the entire-api cell (home or --jurisdiction) via CellClientFactory, posts to /api/v1/me/dispatches, and polls GET /me/dispatches/{id} until the run is complete or failed (202 + generating → terminal status).

CloudClient is rebuilt on shared api.Client instead of a custom HTTP stack; wire JSON is camelCase and the request drops generate / gateway-only fields. Jurisdiction selection is client-side cell routing only—there is no response jurisdiction stamp or checkDispatchJurisdiction guard anymore. Repo-not-found errors still get a home jurisdiction label via new HomeJurisdiction() on the cell factory; the dispatch wizard uses the same factory for defaults.

Docs now describe dispatch under entire-api cell routing and stop listing it on the BFF data-API path.

Reviewed by Cursor Bugbot for commit 8ee316e. Configure here.

entire dispatch posted to the BFF's one-shot POST /api/v1/dispatches/generate,
with ?jurisdiction= telling the BFF which cell to read from. It now dials that
cell itself: one CellClientFactory per run, aimed at the --jurisdiction cell
or the caller's home cell.

The cell's route is asynchronous. POST /me/dispatches answers 202 with a run
still generating, so the client polls GET /me/dispatches/{id} every two
seconds until the run is complete or failed, bounded by a three-minute budget
that outlasts the cell's own two-minute stale threshold. A failed run surfaces
its error message. The wire types follow the cell's camelCase shape.

Because the client dials the requested cell directly, the jurisdiction echo
check is gone, and so is the dispatch-local HTTPS guard: the cell factory
already refuses a plain-HTTP data host before sending the login JWT. The cell
client is built after the local window and origin checks, since building it
already dials. The dispatch wizard reads the home jurisdiction from the same
factory through a new CellClientFactory.HomeJurisdiction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4H1JY883E64PZ7HHDAN39SJ
Copilot AI balanced review requested due to automatic review settings October 9, 2026 19:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The initial POST remains unbounded, allowing a stalled cell response to hang the CLI indefinitely.

1 open finding
What changed in this PR

Routes cloud dispatch generation directly through the selected entire-api cell and polls asynchronous runs to completion.

Changes:

  • Replaces the BFF dispatch endpoint with cell-aware routing and camelCase payloads.
  • Adds asynchronous dispatch polling, failure handling, and updated tests.
  • Aligns wizard defaults and routing documentation with cell-based dispatches.
File Description
docs/​development/​api-routing.md Documents dispatch cell routing.
docs/​architecture/​upstream-host-resolution.md Removes dispatch from BFF routing.
cmd/​entire/​cli/​auth/​cell_data_api.go Exposes the factory’s home jurisdiction.
cmd/​entire/​cli/​dispatch/​cloud.go Implements the new API contract and polling.
cmd/​entire/​cli/​dispatch/​cloud_test.go Tests asynchronous cloud dispatch behavior.
cmd/​entire/​cli/​dispatch/​mode_cloud.go Routes dispatches through a cell client.
cmd/​entire/​cli/​dispatch/​mode_cloud_test.go Updates server-mode routing tests.
cmd/​entire/​cli/​dispatch/​mode_local.go Removes obsolete data-API seam.
cmd/​entire/​cli/​dispatch/​repo_slug.go Updates server terminology.
cmd/​entire/​cli/​dispatch/​dispatch.go Clarifies jurisdiction semantics.
cmd/​entire/​cli/​dispatch/​dispatch_test.go Updates authentication stubbing.
cmd/​entire/​cli/​dispatch/​consts_test.go Updates the test endpoint.
cmd/​entire/​cli/​dispatch_wizard.go Updates home-cell wording.
cmd/​entire/​cli/​dispatch_wizard_scope.go Resolves wizard defaults through the cell factory.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cmd/entire/cli/dispatch/cloud.go
@Soph
Soph marked this pull request as ready for review October 9, 2026 19:38
@Soph
Soph requested a review from a team as a code owner October 9, 2026 19:38
Soph and others added 3 commits October 9, 2026 21:47
The three-minute budget started in waitForDispatch, after POST /me/dispatches
had returned. api.Client sets no timeout, so a cell that accepted the request
but never answered left entire dispatch blocked for good. CreateDispatch now
starts the budget before the POST, and it covers create and polling together.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4H38VR9NRVE8QZP8MH0V6QW
A deadline that expired while a status GET was in flight surfaced as a raw
transport error instead of the still-generating message, which also made
TestCloudClient_CreateDispatch_StopsPollingWhenContextEnds timing-dependent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4H6YGAH4ZYMNF1TK17VNAQ9
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M4H7F95JQ7D8VKKED5HF064V
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants