flower
/
All briefs
complete draft mcp flower

MCP: expose dispatch-request completion/cancel (close the brief_claim ↔ complete asymmetry)

canonical · plan

Spec

markdown

hand-off · dispatch

Dispatch

Auto-dispatch

when it reaches planned

Design-loop

design pass before build

This brief is complete — dispatch is closed.

#5 done fresh flower · flower/dispatch-completion-mcp
1 scratchpad
You are being dispatched from flower Brief #24: MCP: expose dispatch-request completion/cancel (close the brief_claim ↔ complete asymmetry)

Recall pointer:
- Use recall_brief with id 24 for the full folder if you need provenance.

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: flower/dispatch-completion-mcp
- worktree: not specified
- kind: fresh

Current brief spec:
## Problem
The brief **dispatch lifecycle** exposes `brief_claim` over MCP but NOT completion/cancel.
`DispatchService` has `claim()` / `complete()` / `cancel()` / `recomputeRollup()`, yet only
`claim` is an MCP tool. A dispatched brief's status is a **rollup** that stays `dispatched`
until its dispatch_requests are done/cancelled — and there is no MCP path to close them.

Hit firsthand 2026-07-01: `brief_update_status(brief 21/23 → complete)` was REJECTED with
"This brief has active dispatch requests; dispatched status is a rollup until they are done or
cancelled." The orchestrator had to drop to `DispatchService::complete()` via `tinker` to close
dispatch_requests #3/#4 before the briefs could reach `complete`. So a dispatched brief can never
reach `complete` through MCP alone.

## Fix
Add MCP tool(s) wrapping `DispatchService`, requiring `actor_ref` → auto-participant:
- **`brief_dispatch_complete(dispatch_request_id | brief_id, actor_ref)`** — the WORKER's final
  step: marks its claimed dispatch_request done and recomputes the brief rollup so the brief
  advances on its own. Bake into `AgentConventions::workingAgentBlock` as the closing action
  alongside `brief_append` (so dispatched workers self-close).
- **`brief_dispatch_cancel(dispatch_request_id, actor_ref)`** — orchestrator-facing: cancel an
  abandoned/dead dispatch (worker died) so the rollup unwedges.
- (Alternatively one `brief_dispatch_update(request, status: done|cancelled, actor_ref)`.)

## Why it matters
Without it, every dispatched brief needs out-of-band (tinker / orchestrator) intervention to reach
`complete` — defeating the self-driving, traceable dispatch loop. Workers can `claim` but can never
signal `done`, so the rollup wedges.

## Acceptance
- A worker can close its own dispatch via MCP; the brief rollup advances (dispatched →
  in_progress/complete) without tinker.
- Orchestrator can cancel a dead dispatch via MCP.
- `workingAgentBlock` updated to instruct the closing call; charter mentions it.
- Tests for rollup transitions on dispatch completion/cancel.
- `Brief: #24` trailer on commits.

## Provenance
Operator question 2026-07-01 ("do we need an mcp tool here?") after the orchestrator hit the gap
closing briefs #21/#23 post-merge (had to use DispatchService::complete via tinker).

Recent/key trace events:
[1] participant_joined flower-orchestrator: (no body)
[2] note_added flower-orchestrator: Operator question 2026-07-01: after merging dispatched briefs, the orchestrator could not mark them complete via MCP because dispatch_requests have no MCP completion path — had to drop to DispatchService::complete() in tinker.
[3] plan_proposed flower-orchestrator: ## Problem
The brief **dispatch lifecycle** exposes `brief_claim` over MCP but NOT completion/cancel.
`DispatchService` has `claim()` / `complete()` / `cancel()` / `recomputeRollup()`, yet only
`claim` is an MCP tool. A dispatched brief's status is a **rollup** that stays `dispatched`
until its dispatch_requests are done/cancelled — and there is no MCP path to close them.

Hit firsthand 2026-07-01: `brief_update_status(brief 21/23 → complete)` was REJECTED with
"This brief has active dispatch requests; dispatched status is a rollup until they are done or
cancelled." The orchestrator had to drop to `DispatchService::complete()` via `tinker` to close
dispatch_requests #3/#4 before the briefs could reach `complete`. So a dispatched brief can never
reach `complete` through MCP alone.

## Fix
Add MCP tool(s) wrapping `DispatchService`, requiring `actor_ref` → auto-participant:
- **`brief_dispatch_complete(dispatch_request_id | brief_id, actor_ref)`** — the WORKER's final
  step: marks its claimed dispatch_request done and recomputes the brief rollup so the brief
  advances on its own. Bake into `AgentConventions::workingAgentBlock` as the closing action
  alongside `brief_append` (so dispatched workers self-close).
- **`brief_dispatch_cancel(dispatch_request_id, actor_ref)`** — orchestrator-facing: cancel an
  abandoned/dead dispatch (worker died) so the rollup unwedges.
- (Alternatively one `brief_dispatch_update(request, status: done|cancelled, actor_ref)`.)

## Why it matters
Without it, every dispatched brief needs out-of-band (tinker / orchestrator) intervention to reach
`complete` — defeating the self-driving, traceable dispatch loop. Workers can `claim` but can never
signal `done`, so the rollup wedges.

## Acceptance
- A worker can close its own dispatch via MCP; the brief rollup advances (dispatched →
  in_progress/complete) without tinker.
- Orchestrator can cancel a dead dispatch via MCP.
- `workingAgentBlock` updated to instruct the closing call; charter mentions it.
- Tests for rollup transitions on dispatch completion/cancel.
- `Brief: #24` trailer on commits.

## Provenance
Operator question 2026-07-01 ("do we need an mcp tool here?") after the orchestrator hit the gap
closing briefs #21/#23 post-merge (had to use DispatchService::complete via tinker).
[4] status_change flower-orchestrator: (no body)
[5] link_added flower-orchestrator: (no body)

Recommended linked context:
{
    "todos": [],
    "scratchpads": [
        {
            "id": 346,
            "solo_scratchpad_id": "1026",
            "name": "Orchestrator HANDOFF — flower build (live state)",
            "archived": false,
            "revision": 17
        }
    ]
}

Execution notes:
- Treat the brief as the source of truth.
- Keep work scoped to this dispatch request.
- Use brief_append / brief_update_status when reporting material progress.
- Add a git commit trailer `Brief: #24` to every commit for this brief so flower can exact-link commits back to the brief.

provenance · append-only

Trace

live
or paste a screenshot uploading…
  1. link added 4d ago
    agent · system:commit-trailer
  2. participant joined 4d ago
    system · system:commit-trailer
  3. status change 4d ago
    agent · flower-orchestrator
  4. dispatched 4d ago

    Dispatch request #5 marked done.

    agent · flower-orchestrator
  5. note added 4d ago

    Completed Brief #24 on branch flower/dispatch-completion-mcp. Commit eb74998 (Brief: #24) adds brief_dispatch_complete and brief_dispatch_cancel MCP tools, registers them on FlowerServer, and updates DispatchService so completion can close a claimed request by dispatch_request_id or by the actor's active request for a brief. Rollup behavior now completes the brief once no active dispatches remain and at least one dispatch succeeded; cancel-only dispatches unwind back out of dispatched. AgentConventions now tells dispatched workers to finish with brief_dispatch_complete, and daemon charter conventions mention the same closeout path. Verification: pint passed on changed files; focused dispatch/conventions tests passed (14 tests, 148 assertions); affected MCP+Briefs slices passed (112 tests, 1119 assertions); full suite with ANTHROPIC_API_KEY blank and MEILISEARCH_KEY=LARAVEL-HERD passed (377 tests, 367 passed, 10 skipped, 2663 assertions). Tracked working tree clean; untracked solo.yml left untouched.

    agent · flower-backend
  6. participant joined 4d ago
    system · flower-backend
  7. dispatched 4d ago

    Dispatch request #5 queued for flower.

    agent · flower-orchestrator
  8. status change 4d ago
    agent · flower-orchestrator
  9. link added 4d ago
    agent · flower-orchestrator
  10. status change 4d ago
    agent · flower-orchestrator
  11. plan proposed 4d ago

    ## Problem The brief **dispatch lifecycle** exposes `brief_claim` over MCP but NOT completion/cancel. `DispatchService` has `claim()` / `complete()` / `cancel()` / `recomputeRollup()`, yet only `claim` is an MCP tool. A dispatched brief's status is a **rollup** that stays `dispatched` until its dispatch_requests are done/cancelled — and there is no MCP path to close them. Hit firsthand 2026-07-01: `brief_update_status(brief 21/23 → complete)` was REJECTED with "This brief has active dispatch requests; dispatched status is a rollup until they are done or cancelled." The orchestrator had to drop to `DispatchService::complete()` via `tinker` to close dispatch_requests #3/#4 before the briefs could reach `complete`. So a dispatched brief can never reach `complete` through MCP alone. ## Fix Add MCP tool(s) wrapping `DispatchService`, requiring `actor_ref` → auto-participant: - **`brief_dispatch_complete(dispatch_request_id | brief_id, actor_ref)`** — the WORKER's final step: marks its claimed dispatch_request done and recomputes the brief rollup so the brief advances on its own. Bake into `AgentConventions::workingAgentBlock` as the closing action alongside `brief_append` (so dispatched workers self-close). - **`brief_dispatch_cancel(dispatch_request_id, actor_ref)`** — orchestrator-facing: cancel an abandoned/dead dispatch (worker died) so the rollup unwedges. - (Alternatively one `brief_dispatch_update(request, status: done|cancelled, actor_ref)`.) ## Why it matters Without it, every dispatched brief needs out-of-band (tinker / orchestrator) intervention to reach `complete` — defeating the self-driving, traceable dispatch loop. Workers can `claim` but can never signal `done`, so the rollup wedges. ## Acceptance - A worker can close its own dispatch via MCP; the brief rollup advances (dispatched → in_progress/complete) without tinker. - Orchestrator can cancel a dead dispatch via MCP. - `workingAgentBlock` updated to instruct the closing call; charter mentions it. - Tests for rollup transitions on dispatch completion/cancel. - `Brief: #24` trailer on commits. ## Provenance Operator question 2026-07-01 ("do we need an mcp tool here?") after the orchestrator hit the gap closing briefs #21/#23 post-merge (had to use DispatchService::complete via tinker).

    agent · flower-orchestrator
  12. note added 4d ago

    Operator question 2026-07-01: after merging dispatched briefs, the orchestrator could not mark them complete via MCP because dispatch_requests have no MCP completion path — had to drop to DispatchService::complete() in tinker.

    agent · flower-orchestrator
  13. participant joined 4d ago
    system · flower-orchestrator

epic · dependencies

Relationships

epic parent

depends on

No dependencies — dispatchable once planned.

agents · waves

Participants

  • flower-orchestrator participant · active
  • flower-backend participant · active
  • system:commit-trailer participant · active

trace · graph

Links

  • Commit #1172 execution
  • Scratchpad #346 execution

scope

Projects

  • flower · primary

dogfood · read-only

Agent’s-eye view

The literal recall_brief payload an agent gets — same service path as the MCP tool.