Summary
Complete the user-facing task approval loop across Desktop delivery and direct Edge execution. A human decision must not be reported as applied merely because Hub stored it or queued a WebSocket frame.
Verified source defects
- RunEventService.DecideTaskApproval persists run.agent.permission_decided before DeliverToDesktopDevice. A delivery error leaves the projection decided; repeating the same decision is rejected as not pending.
- The same endpoint rejects tasks without target_id. Unbound direct-HTTP tasks have an actual edge_device_id/run binding but no target_id, so their runtime approval requests cannot be decided remotely.
- Desktop only remembers successful permission controls in memory; a lost Edge HTTP response is not retry-safe because the existing one-shot receiver responds not-found after consumption.
Scope / Interfaces
- Persist immutable task/run/request decision intent with a unique identity and explicit pending/applied state. Separate that durable intent from run.agent.permission_decided runtime evidence. Identical retries reuse intent; conflicting choice/reason/target/run cannot overwrite it.
- Reuse existing Desktop agent.control and device queue. New task controls carry control_id, hubTaskId and run/request identity; Desktop confirms application through a task-scoped Hub receipt only after an explicit Edge receipt. Existing Team controls keep their compatibility path.
- Direct control is permitted only for the configured registered original device with matching health identity and explicit receiver receipt support. Keep Hub tokens out of renderer/agent context. Reuse bounded HTTP/egress and least-agency capability conventions.
- Edge accepts an optional controlId/hubTaskId on POST /v1/permissions/decide. Enforce existing run-owner gates and exact task binding before any effect; repeated identical modern controls return their application receipt without consuming the broker twice, while conflicts fail closed. No-controlId callers retain existing one-shot behavior. A cold/evicted unprovable result is not invented as success and never recreates a permission request.
- UI distinguishes the recorded human choice from Edge application; pending/failed delivery remains visible and can resend only the same immutable decision.
Invariants
Only the recorded task owner can choose; only the bound device can acknowledge. Queue acceptance is not application. Missing control service is not success. Terminal/mismatched tasks cannot gain fresh approval authority. An offline/device/HTTP failure does not discard the original choice or strand the UI in a fake-applied state. No automatic client retry loop or new general workflow framework.
Files / Ownership
- Main: hub-server/internal/model, repository, service/agent, service/agentcontrol, related handler/router/composition, migration, API owner docs and integration tests.
- Edge worker: only edge-server/internal/api permission-control receiver/helpers/tests and strictly necessary Handler fields/capability metadata. No Hub or TS writes.
- Frontend worker: app/shared Hub/types/task-approval presentation and app/desktop control bridge + focused browser/unit coverage. Main will define the wire fields before dispatch.
Acceptance
Negative Constraints / Dependencies
Build on #2352, without claiming real-login/model E2E, production deployment or process recovery. No workspace/permission bypass, credentials in Git/logs, durable automatic execution restart, root-rule rewrite, or unrelated storage cleanup. Task cancellation has a separate confirmed delivery gap and is not silently claimed fixed by this approval slice.
Summary
Complete the user-facing task approval loop across Desktop delivery and direct Edge execution. A human decision must not be reported as applied merely because Hub stored it or queued a WebSocket frame.
Verified source defects
Scope / Interfaces
Invariants
Only the recorded task owner can choose; only the bound device can acknowledge. Queue acceptance is not application. Missing control service is not success. Terminal/mismatched tasks cannot gain fresh approval authority. An offline/device/HTTP failure does not discard the original choice or strand the UI in a fake-applied state. No automatic client retry loop or new general workflow framework.
Files / Ownership
Acceptance
Negative Constraints / Dependencies
Build on #2352, without claiming real-login/model E2E, production deployment or process recovery. No workspace/permission bypass, credentials in Git/logs, durable automatic execution restart, root-rule rewrite, or unrelated storage cleanup. Task cancellation has a separate confirmed delivery gap and is not silently claimed fixed by this approval slice.