flower
/
All briefs
complete draft note flower

Wire auto-dispatch-on-planned: flagged briefs reaching planned enqueue to the orchestrator coordination queue for auto-dispatch

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.

#32 done fresh flower · flower/126-auto-dispatch-wiring
agent: codex
You are being dispatched from flower Brief #126: Wire auto-dispatch-on-planned: flagged briefs reaching planned enqueue to the orchestrator coordination queue for auto-dispatch

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

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: flower/126-auto-dispatch-wiring
- worktree: not specified
- kind: fresh

Current brief spec:
(no spec yet)

This is a direct request, not a fully-specced plan. If it's clear, resolve it. If you hit a blocking ambiguity, call brief_ask (or brief_append) with your questions and flip the brief to `refining` before proceeding — don't guess.

Recent/key trace events:
[1] participant_joined flower-orchestrator: (no body)
[2] note_added flower-orchestrator: Operator-requested (2026-07-03). Follow-up sibling to Brief #96 (which relocated + KEPT the auto-dispatch toggle enabled in the /briefs detail UI). This brief makes the toggle ACTUALLY DO SOMETHING: an operator flags `auto_dispatch_on_planned` on a brief; when that brief reaches `planned`, it should get auto-dispatched by the project orchestrator without a human hand-dispatch.

STEP 0 — AUDIT FIRST (do NOT duplicate #98): grep/read what Brief #98 ("Wire auto-dispatch-on-planned via the orchestrator drain loop") actually shipped. `recall_dispatch_queue` already SURFACES `auto_dispatch_on_planned` (returns the flag + `dispatchable` set), and `config('flower.dispatch.auto_max_concurrent')` (=2) exists. Determine exactly what is and isn't wired end-to-end, and only build the missing piece. Report the audit finding on this brief before/with the implementation.

THE GAP (verify): `auto_dispatch_on_planned` (bool, migration 2026_06_30_110000, cast on Brief, written by the UI) needs a CONSUMER that actually triggers a dispatch. The intended design (per #96 + the #84 coordination-queue substrate): when a brief with the flag transitions to `planned`, ENQUEUE a coordination signal (daemon_signals / the #84 substrate) targeting the brief's project ORCHESTRATOR, so the orchestrator picks it up on its next `recall_signals` drain and dispatches it via the normal DispatchService path.

REQUIREMENTS:
1. TRIGGER: in the BriefService status-change path (status → `planned`), if `auto_dispatch_on_planned` is set AND the brief is dispatchable (unblocked, no dispatch_request already in flight), enqueue an auto-dispatch coordination signal to the project's orchestrator daemon (reuse the daemon_signals queue; add a signal kind e.g. `auto_dispatch` carrying brief_id, or reuse the closest existing kind). Idempotent — never enqueue twice for the same brief/transition, and no-op if a dispatch_request already exists.
2. CONSUMER (orchestrator drain): the orchestrator's heartbeat `recall_signals` drain must handle the new signal — claim → dispatch the brief (DispatchService / the same path brief_dispatch uses) → signal_complete (or signal_fail with reason). Respect `flower.dispatch.auto_max_concurrent` (2): if the project already has that many auto-dispatches in flight, defer (leave the signal pending / re-enqueue) rather than exceed the cap.
3. GUARD RAILS: only auto-dispatch planned + unblocked briefs with no in-flight dispatch_request; never auto-dispatch a brief needing operator approval; a brief that becomes blocked after enqueue must not dispatch.
4. Keep the orchestrator the single dispatch/merge point — auto-dispatch just SAVES the manual brief_dispatch call; the packet + worker spawn still flow through the orchestrator exactly as today.

VERIFY: a test proving flag+planned enqueues the signal (and does NOT when unflagged / blocked / already-dispatched); a test proving the orchestrator-drain handler dispatches on the signal and respects the concurrency cap. `php artisan test` green; `./vendor/bin/pint`. Backend brief → Codex. `Brief: #<this-id>` trailer. Note: touches BriefService + the coordination-queue/signal handling — coordinate that the orchestrator's live drain-loop understanding matches (the orchestrator daemon reads its heartbeat drain instructions from its charter/timer body, not code, so flag any new signal kind the orchestrator must learn to handle).
[3] status_change flower-orchestrator: (no body)

Recommended linked context:
{
    "todos": [],
    "scratchpads": []
}

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; as your final dispatched-worker step, call brief_dispatch_complete with dispatch_request_id (or brief_id) and actor_ref.
- Codex workers should verify mutating Flower tools with tool_search query `brief_append brief_dispatch_complete flower_feedback` (limit 20) when tool availability is in doubt; report raw SEE/LOAD vs NOT visible instead of silently using local fallbacks.
- Add a git commit trailer `Brief: #126` 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 2d ago
    agent · system:commit-trailer
  2. participant joined 2d ago
    system · system:commit-trailer
  3. status change 2d ago
    agent · flower-backend-126
  4. dispatched 2d ago

    Dispatch request #32 marked done.

    agent · flower-backend-126
  5. note added 2d ago

    STEP-0 audit: Brief #98 shipped the visibility/cap/conventions layer only: `recall_dispatch_queue` surfaces `auto_dispatch_on_planned` on dispatchable briefs and in-flight request briefs; `DispatchService::queue()` eager-loads the flag; `config('flower.dispatch.auto_max_concurrent')` defaults to 2; `AgentConventions` told orchestrators to poll/filter `recall_dispatch_queue`. #98 did NOT create a durable `daemon_signals` trigger when a flagged brief reaches `planned`, and did NOT provide a claimed-signal consumer that dispatches and completes/requeues the coordination signal. #126 covers those missing trigger/consumer pieces. Implemented on branch `flower/126-auto-dispatch-wiring`, commit `a48e52a` (`Brief: #126`). Added `CoordinationQueue::KIND_AUTO_DISPATCH`, `AutoDispatchService`, and `brief_auto_dispatch_signal`. `BriefService::setStatus()` now enqueues only on a real non-planned -> planned transition when `auto_dispatch_on_planned=true`, the brief is dispatchable, and a live project orchestrator daemon exists. Dispatchability reuses the same planned/unblocked/no-active-request/no-operator-approval rules as the queue. The consumer re-checks eligibility at drain time, dispatches through `DispatchService`, records `recommended.auto_dispatch` on the dispatch request, enforces `flower.dispatch.auto_max_concurrent`, requeues on cap pressure, skips stale/ineligible signals, and fails the signal if DispatchService rejects unexpectedly. Updated daemon conventions, config copy, and the brief-detail toggle notice. Tests: exact requested line `MEILISEARCH_KEY=LARAVEL-HERD ~/bin/php artisan test` ran after implementation and again after the final service fix: 697 tests, 686 passed, 10 skipped, 4681 assertions, with the expected single sandbox/network error in `Tests\Feature\SegmentSessionTest::test_real_anthropic_call_produces_a_segment_when_key_present` (`cURL error 6: Could not resolve host: api.anthropic.com`). Focused post-Pint slice `~/bin/php artisan test tests/Feature/Briefs/AutoDispatchServiceTest.php tests/Unit/AgentConventionsTest.php` passed: 7 tests, 75 assertions. Pint: `~/bin/php ./vendor/bin/pint app/Livewire/Briefs/Show.php app/Mcp/Servers/FlowerServer.php app/Mcp/Tools/BriefAutoDispatchSignalTool.php app/Services/Briefs/AutoDispatchService.php app/Services/Briefs/BriefService.php app/Services/Briefs/DispatchService.php app/Services/Daemons/CoordinationQueue.php app/Support/AgentConventions.php config/flower.php tests/Feature/Briefs/AutoDispatchServiceTest.php tests/Unit/AgentConventionsTest.php` ran; final targeted Pint on `app/Services/Briefs/AutoDispatchService.php` passed. Coordination note for the live orchestrator drain: new signal kind is `auto_dispatch`. Payload: `brief_id`, `brief_title`, `project_id`, `project_slug`, `orchestrator_daemon_id`, `orchestrator_solo_process_id`, `auto_max_concurrent`, `message`. On `recall_signals`, when kind is `auto_dispatch`: call `signal_claim(signal_id, actor_ref=<orchestrator actor_ref>)`, then call `brief_auto_dispatch_signal(signal_id=<same>, actor_ref=<same>, optional target_branch/target_worktree/agent_tool/session_id)`. That tool is the handler: it dispatches via DispatchService and completes the claimed signal. If the cap is already reached, it completes the claimed signal with `action=deferred` and requeues a replacement pending signal with the same payload; if the brief became blocked/unplanned/approval-gated/unflagged/already-dispatched, it completes with `action=skipped`; if DispatchService throws after claim, it records `signal_fail` with the error. Do not call a separate `signal_complete` after `brief_auto_dispatch_signal` succeeds; the tool has already completed or requeued/failed the signal.

    agent · flower-backend-126
  6. participant joined 2d ago
    system · flower-backend-126
  7. link added 2d ago
    agent · system:brief-autolink
  8. link added 2d ago
    agent · system:brief-autolink
  9. link added 2d ago
    agent · system:brief-autolink
  10. link added 2d ago
    agent · system:brief-autolink
  11. comment 2d ago

    Target branch flower/126-auto-dispatch-wiring is merged to the default branch; suggest marking the brief complete.

    system · system:brief-autolink
  12. participant joined 2d ago
    system · system:brief-autolink
  13. dispatched 2d ago

    Dispatch request #32 queued for flower.

    agent · flower-orchestrator
  14. status change 2d ago
    agent · flower-orchestrator
  15. status change 2d ago
    agent · flower-orchestrator
  16. note added 2d ago

    Operator-requested (2026-07-03). Follow-up sibling to Brief #96 (which relocated + KEPT the auto-dispatch toggle enabled in the /briefs detail UI). This brief makes the toggle ACTUALLY DO SOMETHING: an operator flags `auto_dispatch_on_planned` on a brief; when that brief reaches `planned`, it should get auto-dispatched by the project orchestrator without a human hand-dispatch. STEP 0 — AUDIT FIRST (do NOT duplicate #98): grep/read what Brief #98 ("Wire auto-dispatch-on-planned via the orchestrator drain loop") actually shipped. `recall_dispatch_queue` already SURFACES `auto_dispatch_on_planned` (returns the flag + `dispatchable` set), and `config('flower.dispatch.auto_max_concurrent')` (=2) exists. Determine exactly what is and isn't wired end-to-end, and only build the missing piece. Report the audit finding on this brief before/with the implementation. THE GAP (verify): `auto_dispatch_on_planned` (bool, migration 2026_06_30_110000, cast on Brief, written by the UI) needs a CONSUMER that actually triggers a dispatch. The intended design (per #96 + the #84 coordination-queue substrate): when a brief with the flag transitions to `planned`, ENQUEUE a coordination signal (daemon_signals / the #84 substrate) targeting the brief's project ORCHESTRATOR, so the orchestrator picks it up on its next `recall_signals` drain and dispatches it via the normal DispatchService path. REQUIREMENTS: 1. TRIGGER: in the BriefService status-change path (status → `planned`), if `auto_dispatch_on_planned` is set AND the brief is dispatchable (unblocked, no dispatch_request already in flight), enqueue an auto-dispatch coordination signal to the project's orchestrator daemon (reuse the daemon_signals queue; add a signal kind e.g. `auto_dispatch` carrying brief_id, or reuse the closest existing kind). Idempotent — never enqueue twice for the same brief/transition, and no-op if a dispatch_request already exists. 2. CONSUMER (orchestrator drain): the orchestrator's heartbeat `recall_signals` drain must handle the new signal — claim → dispatch the brief (DispatchService / the same path brief_dispatch uses) → signal_complete (or signal_fail with reason). Respect `flower.dispatch.auto_max_concurrent` (2): if the project already has that many auto-dispatches in flight, defer (leave the signal pending / re-enqueue) rather than exceed the cap. 3. GUARD RAILS: only auto-dispatch planned + unblocked briefs with no in-flight dispatch_request; never auto-dispatch a brief needing operator approval; a brief that becomes blocked after enqueue must not dispatch. 4. Keep the orchestrator the single dispatch/merge point — auto-dispatch just SAVES the manual brief_dispatch call; the packet + worker spawn still flow through the orchestrator exactly as today. VERIFY: a test proving flag+planned enqueues the signal (and does NOT when unflagged / blocked / already-dispatched); a test proving the orchestrator-drain handler dispatches on the signal and respects the concurrency cap. `php artisan test` green; `./vendor/bin/pint`. Backend brief → Codex. `Brief: #<this-id>` trailer. Note: touches BriefService + the coordination-queue/signal handling — coordinate that the orchestrator's live drain-loop understanding matches (the orchestrator daemon reads its heartbeat drain instructions from its charter/timer body, not code, so flag any new signal kind the orchestrator must learn to handle).

    agent · flower-orchestrator
  17. participant joined 2d ago
    system · flower-orchestrator

epic · dependencies

Relationships

epic parent

depends on

No dependencies — dispatchable once planned.

agents · waves

Participants

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

trace · graph

Links

  • Commit #1670 execution
  • Commit #1649 result
  • Commit #1643 result
  • Commit #1645 result
  • Commit #1647 result

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.