Summary
Preserve the same execution intent across Hub direct HTTP/outbox and Desktop WS/relay, and make callback ownership explicit before enabling a route. This is the next end-to-end dispatch slice after #2349, not a storage micro-optimization.
Verified source gaps
hub-server/internal/service/dispatch/edge_request.go projects no workDir/model-parameter/tool configuration and hardcodes model to claude. dispatchsvc/agent_dispatch_edge_http.go passes no modelParams/toolWhitelist into it. Edge runcontrol requires a non-empty allowed workspace; therefore fresh direct admissions constructed by this path fail workdir_required rather than honoring the user-selected execution intent. Local project/thread differences remain an intentional transport compatibility boundary, not a standalone defect.
app/desktop/src/hooks/hubIntegrationMappers.ts does not forward Hub messages/pinned_messages, and its string-only schema accessor drops the top-level JSON object supplied as structured_output_schema. The direct Go projection forwards messages/pins and explicitly serializes the schema. This changes runtime context, not merely display metadata.
- Callback ownership needs a route gate before repairing direct dispatch. If a configured direct Edge is a Desktop-managed sidecar without Hub callback configuration, a successful direct admission would not establish Desktop run/task mapping and would have no output callback owner. This is a conditional source-level risk, not a claim that production is currently in this configuration.
Scope / Files / Ownership
- One integration PR with disjoint Hub projection and Desktop projection workers; main owns shared fixture contract, route/callback decision and acceptance.
- Hub:
hub-server/internal/service/dispatch/edge_request.go, edge_http_prep.go, affected dispatchsvc call sites and their tests.
- Desktop:
app/desktop/src/hooks/hubIntegrationMappers.ts and focused unit/browser contract tests.
- Contract: existing API owner documents and
tests/fixtures/dispatch/execution-intent.json, consumed by both Go and TypeScript tests. Fixture-only edits must select both test lanes.
- Main Edge: HTTP callback ownership validation/capability advertisement, persisted run callback owner and executor callback reporting guard; associated API/store/lifecycle tests. Main Hub: ownership-aware route preflight, real-device reservation/receipt handling and PostgreSQL integration acceptance. Edge callback worker: typed tool/permission/result events on the existing reporter FIFO.
Invariants / Interfaces
- Same logical task means the same model, reasoning/thinking, permission mode, workDir, system/append prompt, tool restrictions, messages/pins, structured schema, ephemeral/config values and delivery/Hub task identity across channels.
- Preserve intentional target/project/thread representations and capability constraints; do not weaken workspace allowlists to make direct dispatch succeed.
- An accepted route has a defined callback owner. Do not inject a Hub token into Desktop or silently enable two output reporters; make route eligibility explicit.
Callback ownership protocol
- Modern Hub HTTP requests choose
callbackOwner=edge; Desktop chooses callbackOwner=desktop. Edge persists the selected owner with pending Hub admission and returns the actual original owner on every receipt, including cross-channel replays. Requesting a different owner on replay does not reassign it.
/v1/health advertises capabilities.runCallbackOwnership and capabilities.directHubCallbacks (configuration presence only, never a credential or a live-reachability claim). Hub direct execution requires both; Desktop requires ownership support but may use a sidecar without direct callbacks. Missing capability is not optimistic compatibility: no run POST is issued to an old/unsupported Edge. Direct health identity must match the configured registered device, and the device must belong to the task Agent inviter.
- Edge-owned runs use the Edge reporter; Desktop preserves local run state but does not emit a second set of task lifecycle/output callbacks. Relay delivery ACK remains the receiver Desktop responsibility. Unknown receipt ownership is explicit uncertainty, not a guessed owner.
- Hub reserves the actual device before a run POST. An ambiguous HTTP response retains that reservation across outbox retries/restarts; it must not fall through to another executor. A Desktop-owned replay restores only the original device bridge. A late HTTP receipt preserves advanced callback status and any existing run/device binding.
- Edge-owned delivery must preserve typed tool, permission, route and result events as well as text/final callbacks. Control events must not silently disappear when the stream queue is busy. Team-context execution stays on the Desktop control path: typed streams are observations, not authority to execute a Team route decision.
Acceptance
Negative constraints
No live deployment, real-model/login request, credential distribution, automatic execution recovery, default-workspace bypass or new second retry loop. Do not call a future/conditional callback gap a verified production incident. Persistent admission work belongs to #2349.
Summary
Preserve the same execution intent across Hub direct HTTP/outbox and Desktop WS/relay, and make callback ownership explicit before enabling a route. This is the next end-to-end dispatch slice after #2349, not a storage micro-optimization.
Verified source gaps
hub-server/internal/service/dispatch/edge_request.goprojects no workDir/model-parameter/tool configuration and hardcodes model toclaude.dispatchsvc/agent_dispatch_edge_http.gopasses no modelParams/toolWhitelist into it. Edge runcontrol requires a non-empty allowed workspace; therefore fresh direct admissions constructed by this path failworkdir_requiredrather than honoring the user-selected execution intent. Local project/thread differences remain an intentional transport compatibility boundary, not a standalone defect.app/desktop/src/hooks/hubIntegrationMappers.tsdoes not forward Hub messages/pinned_messages, and its string-only schema accessor drops the top-level JSON object supplied as structured_output_schema. The direct Go projection forwards messages/pins and explicitly serializes the schema. This changes runtime context, not merely display metadata.Scope / Files / Ownership
hub-server/internal/service/dispatch/edge_request.go,edge_http_prep.go, affected dispatchsvc call sites and their tests.app/desktop/src/hooks/hubIntegrationMappers.tsand focused unit/browser contract tests.tests/fixtures/dispatch/execution-intent.json, consumed by both Go and TypeScript tests. Fixture-only edits must select both test lanes.Invariants / Interfaces
Callback ownership protocol
callbackOwner=edge; Desktop choosescallbackOwner=desktop. Edge persists the selected owner with pending Hub admission and returns the actual original owner on every receipt, including cross-channel replays. Requesting a different owner on replay does not reassign it./v1/healthadvertisescapabilities.runCallbackOwnershipandcapabilities.directHubCallbacks(configuration presence only, never a credential or a live-reachability claim). Hub direct execution requires both; Desktop requires ownership support but may use a sidecar without direct callbacks. Missing capability is not optimistic compatibility: no run POST is issued to an old/unsupported Edge. Direct health identity must match the configured registered device, and the device must belong to the task Agent inviter.Acceptance
Negative constraints
No live deployment, real-model/login request, credential distribution, automatic execution recovery, default-workspace bypass or new second retry loop. Do not call a future/conditional callback gap a verified production incident. Persistent admission work belongs to #2349.