flower
/
All briefs
complete draft note flower

Epic-lead: operator "Force epic-lead" control on /briefs (pin a brief to the epic-lead pipeline from capture)

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.

#124 done fresh flower · flower/241-force-epic-lead-toggle
agent: claude
You are being dispatched from flower Brief #241: Epic-lead: operator "Force epic-lead" control on /briefs (pin a brief to the epic-lead pipeline from capture)

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

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: flower/241-force-epic-lead-toggle
- 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: Follow-up to epic #226 (epic-lead orchestration, now COMPLETE) — operator-requested (Mike, 2026-07-04).

## Problem
Slice E (#235) shipped the per-brief opt-in flag `brief.meta.epic_lead ∈ {auto, force, never}`, and `EpicLeadPolicy` already HONORS it (`force` → always recommend a lead, `never` → never, `auto` → the child-count≥3 / phased / multi-hour heuristic; MAIN's judgment stays authoritative). BUT there is **no way to SET that flag** — the Slice E worker explicitly deferred it ("No meta-writer tool added — reading/honoring the flag is the deliverable; flag if a `brief_set_epic_lead_mode` helper is wanted"). So today the only path to an epic-lead run is *hoping the orchestrator's advisory heuristic picks it up.*

The operator wants to **deterministically pin a brief to the epic-lead pipeline from the start** — mark it once, and have it planned / discussed / dispatched as an epic-lead epic throughout its lifecycle, not left to chance.

## Deliverable (mirror the #230 auto-dispatch toggle pattern)
1. **Operator control on /briefs** to set `meta.epic_lead`, built exactly like the #230 auto-dispatch toggle (brief #230 = `AutoDispatchService::toggleFlag(Brief)` shared method + `Index::toggleAutoDispatch` row action + detail-view control + `x-ui.toggle` in the bloom row action bar, no logic drift between surfaces, gated on `planned`). Extract a shared setter (e.g. `EpicLeadModeService::setMode(Brief, mode)` or an `AutoDispatchService`-style service) so the row control and the brief-detail control can't diverge. **Design fork for refine** (see Open questions): a boolean **"Force epic-lead"** toggle (force ↔ auto) vs a 3-state segmented **Auto / Force / Never** control. Recommend boolean force as primary (matches the operator's "toggle" framing) with `never` available on brief detail.
2. **`brief_set_epic_lead_mode` MCP write tool** (app/Mcp/Tools shape; requires `actor_ref` → auto-participant; append a brief event for provenance) so agents/operator can set it programmatically — parity with `brief_dispatch`/`brief_update_status`.
3. **Visibility** — a badge on the brief row + detail (like the auto-dispatch badge) showing Force / Never when set, so a pinned brief reads as pinned at a glance. Confirm `recall_dispatch_queue`'s existing `epic_lead: {recommend, mode, reasons}` payload reflects the set mode.
4. **Lifecycle honoring** — the whole point: a force-pinned brief should be *approached* as an epic-lead epic from capture → refine → dispatch, not just at the dispatch instant. At minimum, `force` must make `EpicLeadPolicy` deterministically recommend (already true), be visible, and be settable. STRETCH / verify scope: the orchestrator's dispatch pickup should route a force-pinned brief to `flower:spawn-epic-lead` (vs a plain worker). Today the heuristic is advisory (MAIN decides) — this brief should make `force` a strong, visible directive; whether the orchestrator loop/charter should AUTO-invoke spawn-epic-lead on a force brief (vs surface it for MAIN to action) is the key scoping question below.

## Constraints / patterns
- No migration (`meta` is already JSON-cast — Slice E confirmed). Additive, backward-compatible.
- Bloom design system (`resources/views/components/ui/*`), Livewire /briefs patterns, config-as-data, `app/Mcp/Tools` shape.
- Keep `php artisan test` green; add tests for set (both surfaces + MCP tool) and honor (EpicLeadPolicy force/never → recommend/suppress) paths. Pint clean.
- References: brief #230 (toggle pattern), #235 (EpicLeadPolicy + `meta.epic_lead`), epic #226 design doc `docs/design/226-epic-lead-orchestration.md` (spawn heuristic §#57).

## Open questions (for refine / operator)
- **Control shape:** boolean "Force epic-lead" toggle, or 3-state Auto/Force/Never segmented control? (`never` is genuinely useful to suppress the heuristic on a large-but-cohesive brief.)
- **Auto-route scope:** should a `force` brief cause the orchestrator to AUTO-spawn an epic lead on pickup (fully deterministic pipeline), or make `force` a strong visible recommendation that MAIN still actions? The operator's intent ("approached that way from the start without hoping the orchestrator decides") leans toward auto-route — but that touches the orchestrator loop/charter, so it may warrant its own slice.
- **Gating:** show the control on all briefs, or only epic-candidates (planned, or has/expects children)?
[3] note_added flower-orchestrator: DECISIONS (operator Mike, 2026-07-04) — resolves the Open Questions:
1. **Auto-route scope = AUTO-SPAWN.** `force` is a HARD directive: when the orchestrator picks up a force-pinned brief it must AUTO-spawn an epic lead (flower:spawn-epic-lead) — fully deterministic, no "hoping the heuristic fires." This INCLUDES the orchestrator-loop/charter change to route force-pinned briefs to the epic-lead spawn path (not just a stronger recommendation). May split into two slices: (A) settable flag + UI control + brief_set_epic_lead_mode MCP tool + visible badge + EpicLeadPolicy honoring; (B) orchestrator auto-spawn-on-force routing. Ship A→B, but B is in-scope for this brief.
2. **Control shape = boolean "Force epic-lead" toggle** (force ↔ auto) as the primary /briefs control, with `never` available on brief detail (not the main row toggle). Mirror the #230 auto-dispatch toggle exactly.
3. **Gating = epic-candidate briefs** (planned; has/expects children) — same spirit as #230's planned-gating.
Operator directed: dispatch now.
[4] 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: #241` 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 20h ago
    agent · system:commit-trailer
  2. link added 20h ago
    agent · system:commit-trailer
  3. participant joined 20h ago
    system · system:commit-trailer
  4. status change 20h ago
    agent · flower-orchestrator
  5. merged 20h ago

    Merged flower/241-force-epic-lead-toggle (Part A: EpicLeadModeService + /briefs row toggle + Auto/Force/Never detail control + brief_set_epic_lead_mode MCP tool + badge; Part B: AutoDispatchService routes force-pinned briefs to the epic-lead spawn path with a ready flower:spawn-epic-lead command + routed_epic_lead outcome) to master by flower-orchestrator (daemon 40). Suite green 1237/1235 pass/2 skip. Post-merge: npm run build (view changes) + PromptTemplateSeeder --force (AgentConventions auto_dispatch-drain clause). Deferred follow-up (per worker + operator hands-off intent): orchestrator AUTO-EXECUTING the spawn end-to-end incl. epic branch/worktree auto-provisioning — filing a small follow-up brief.

    agent · flower-orchestrator
  6. status change 21h ago
    agent · flower-241-worker
  7. dispatched 21h ago

    Dispatch request #124 marked done.

    agent · flower-241-worker
  8. note added 21h ago

    DONE — built on branch `flower/241-force-epic-lead-toggle` (2 commits off master @ 07f8590). Full suite green: 1237 tests, 1236 passed, 1 skipped (pre-existing), 0 failures. pint clean, `npm run build` ok. **Part A (core) — commit cd8a6f2:** - `app/Services/Briefs/EpicLeadModeService.php` (new) — shared setter for `meta.epic_lead ∈ {auto,force,never}`, mirroring `AutoDispatchService::toggleFlag`. `setMode()` is idempotent (no-op + no trace event on unchanged mode); every real change writes the flag + appends a `note_added` provenance event via `BriefService` (auto-participant). `toggleForce()` = the boolean force↔auto flip both /briefs surfaces use. - `/briefs` row (Index.php + index.blade) — `toggleEpicLeadForce` row action + "force epic-lead"/"epic-lead · never" badge, gated on epic-candidates (planned epic w/ children, OR any brief already explicitly force/never). `epic_lead_mode`/`is_epic_candidate` computed in `relationMeta` from already-loaded data (pure meta read — no new query; QueryEfficiencyAudit stays green). - Brief detail (Show.php + show.blade) — Auto/Force/Never segmented control (never is detail-only per decision 2) in the Dispatch card actions + header force/never badge. - `brief_set_epic_lead_mode` MCP tool (new, registered in FlowerServer) — actor_ref → auto-participant + provenance; echoes `EpicLeadPolicy::recommend()`. Confirmed `recall_dispatch_queue` already reflects the set mode (reads the same policy) — no change needed there. `EpicLeadPolicy` already honors force/never (existing tests cover it). **Part B (deterministic routing) — commit 51fcc78:** - `AutoDispatchService::dispatchClaimedSignal` — a force-pinned brief is routed to the epic-lead spawn path (`routeEpicLead()`) after the eligibility gate and BEFORE the worker concurrency cap: the claimed signal completes with an `epic_lead` outcome carrying `epic_brief_id` + a ready `flower:spawn-epic-lead … --confirm` command, and NO plain `dispatch_request` is created. Additive — does not touch the MAIN baton or single-master-merge invariant. - `BriefAutoDispatchSignalTool` surfaces `routed_epic_lead=true`. - ⚠️ **CHARTER CHANGE (seeded body):** `app/Support/AgentConventions.php` — additive clause in the auto_dispatch drain step telling the orchestrator to run the spawn command when `routed_epic_lead=true`. **Standing daemons cache charter text at boot — this only takes effect after a daemon reset / `flower:daemon-schema-reload`.** No app/Jobs/* or migration touched (meta is JSON-cast). **Follow-up (deferred, noted per dispatch brief):** the loop is deterministic at the code/routing layer; the remaining closure is the orchestrator auto-EXECUTING `flower:spawn-epic-lead` end-to-end incl. epic branch/worktree auto-provisioning (worktree-manager is external — SpawnEpicLead errors clearly if the epic worktree is missing). Also: force-without-auto_dispatch relies on the orchestrator seeing the `recall_dispatch_queue` epic_lead=force hint (already surfaced) rather than the signal-drain hook. Recommend a small follow-up brief for the auto-provision + charter-reload orchestration if you want it fully hands-off. Tests added: EpicLeadModeServiceTest, BriefSetEpicLeadModeToolTest, AutoDispatchServiceTest force-routing case, + Index/Show badge/toggle/control/gating cases. Did NOT merge (operator merges).

    agent · flower-241-worker
  9. participant joined 21h ago
    system · flower-241-worker
  10. dispatched 21h ago

    Dispatch request #124 queued for flower.

    agent · flower-orchestrator
  11. status change 21h ago
    agent · flower-orchestrator
  12. status change 21h ago
    agent · flower-orchestrator
  13. note added 21h ago

    DECISIONS (operator Mike, 2026-07-04) — resolves the Open Questions: 1. **Auto-route scope = AUTO-SPAWN.** `force` is a HARD directive: when the orchestrator picks up a force-pinned brief it must AUTO-spawn an epic lead (flower:spawn-epic-lead) — fully deterministic, no "hoping the heuristic fires." This INCLUDES the orchestrator-loop/charter change to route force-pinned briefs to the epic-lead spawn path (not just a stronger recommendation). May split into two slices: (A) settable flag + UI control + brief_set_epic_lead_mode MCP tool + visible badge + EpicLeadPolicy honoring; (B) orchestrator auto-spawn-on-force routing. Ship A→B, but B is in-scope for this brief. 2. **Control shape = boolean "Force epic-lead" toggle** (force ↔ auto) as the primary /briefs control, with `never` available on brief detail (not the main row toggle). Mirror the #230 auto-dispatch toggle exactly. 3. **Gating = epic-candidate briefs** (planned; has/expects children) — same spirit as #230's planned-gating. Operator directed: dispatch now.

    agent · flower-orchestrator
  14. note added 21h ago

    Follow-up to epic #226 (epic-lead orchestration, now COMPLETE) — operator-requested (Mike, 2026-07-04). ## Problem Slice E (#235) shipped the per-brief opt-in flag `brief.meta.epic_lead ∈ {auto, force, never}`, and `EpicLeadPolicy` already HONORS it (`force` → always recommend a lead, `never` → never, `auto` → the child-count≥3 / phased / multi-hour heuristic; MAIN's judgment stays authoritative). BUT there is **no way to SET that flag** — the Slice E worker explicitly deferred it ("No meta-writer tool added — reading/honoring the flag is the deliverable; flag if a `brief_set_epic_lead_mode` helper is wanted"). So today the only path to an epic-lead run is *hoping the orchestrator's advisory heuristic picks it up.* The operator wants to **deterministically pin a brief to the epic-lead pipeline from the start** — mark it once, and have it planned / discussed / dispatched as an epic-lead epic throughout its lifecycle, not left to chance. ## Deliverable (mirror the #230 auto-dispatch toggle pattern) 1. **Operator control on /briefs** to set `meta.epic_lead`, built exactly like the #230 auto-dispatch toggle (brief #230 = `AutoDispatchService::toggleFlag(Brief)` shared method + `Index::toggleAutoDispatch` row action + detail-view control + `x-ui.toggle` in the bloom row action bar, no logic drift between surfaces, gated on `planned`). Extract a shared setter (e.g. `EpicLeadModeService::setMode(Brief, mode)` or an `AutoDispatchService`-style service) so the row control and the brief-detail control can't diverge. **Design fork for refine** (see Open questions): a boolean **"Force epic-lead"** toggle (force ↔ auto) vs a 3-state segmented **Auto / Force / Never** control. Recommend boolean force as primary (matches the operator's "toggle" framing) with `never` available on brief detail. 2. **`brief_set_epic_lead_mode` MCP write tool** (app/Mcp/Tools shape; requires `actor_ref` → auto-participant; append a brief event for provenance) so agents/operator can set it programmatically — parity with `brief_dispatch`/`brief_update_status`. 3. **Visibility** — a badge on the brief row + detail (like the auto-dispatch badge) showing Force / Never when set, so a pinned brief reads as pinned at a glance. Confirm `recall_dispatch_queue`'s existing `epic_lead: {recommend, mode, reasons}` payload reflects the set mode. 4. **Lifecycle honoring** — the whole point: a force-pinned brief should be *approached* as an epic-lead epic from capture → refine → dispatch, not just at the dispatch instant. At minimum, `force` must make `EpicLeadPolicy` deterministically recommend (already true), be visible, and be settable. STRETCH / verify scope: the orchestrator's dispatch pickup should route a force-pinned brief to `flower:spawn-epic-lead` (vs a plain worker). Today the heuristic is advisory (MAIN decides) — this brief should make `force` a strong, visible directive; whether the orchestrator loop/charter should AUTO-invoke spawn-epic-lead on a force brief (vs surface it for MAIN to action) is the key scoping question below. ## Constraints / patterns - No migration (`meta` is already JSON-cast — Slice E confirmed). Additive, backward-compatible. - Bloom design system (`resources/views/components/ui/*`), Livewire /briefs patterns, config-as-data, `app/Mcp/Tools` shape. - Keep `php artisan test` green; add tests for set (both surfaces + MCP tool) and honor (EpicLeadPolicy force/never → recommend/suppress) paths. Pint clean. - References: brief #230 (toggle pattern), #235 (EpicLeadPolicy + `meta.epic_lead`), epic #226 design doc `docs/design/226-epic-lead-orchestration.md` (spawn heuristic §#57). ## Open questions (for refine / operator) - **Control shape:** boolean "Force epic-lead" toggle, or 3-state Auto/Force/Never segmented control? (`never` is genuinely useful to suppress the heuristic on a large-but-cohesive brief.) - **Auto-route scope:** should a `force` brief cause the orchestrator to AUTO-spawn an epic lead on pickup (fully deterministic pipeline), or make `force` a strong visible recommendation that MAIN still actions? The operator's intent ("approached that way from the start without hoping the orchestrator decides") leans toward auto-route — but that touches the orchestrator loop/charter, so it may warrant its own slice. - **Gating:** show the control on all briefs, or only epic-candidates (planned, or has/expects children)?

    agent · flower-orchestrator
  15. participant joined 21h ago
    system · flower-orchestrator

epic · dependencies

Relationships

epic parent

depends on

No dependencies — dispatchable once planned.

agents · waves

Participants

  • flower-orchestrator participant · active
  • flower-241-worker participant · active
  • system:commit-trailer participant · active

trace · graph

Links

  • Commit #4050 execution
  • Commit #4051 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.