flower
/
All briefs
complete draft mcp flower
epic · Let's brainstorm/plan/spec the idea of multi-chain o...

Epic-lead Slice B — Lead charter & spawn path (#226)

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.

#112 done fresh flower · flower/232-epic-lead-slice-b
agent: claude
You are being dispatched from flower Brief #232: Epic-lead Slice B — Lead charter & spawn path (#226)

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

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: flower/232-epic-lead-slice-b
- worktree: not specified
- kind: fresh

Current brief spec:
# Slice B — Lead charter & spawn path

Parent epic: #226. Design: `docs/design/226-epic-lead-orchestration.md` (§Spawn, §Identity pt.1). **Depends on Slice A (#231).** Target ≤~300 lines (charter prose excepted).

## Deliverable
1. **Relax the 3 spawn/charter role guards** to permit `lead` (still reject `other`):
   - `SpawnDaemonBridge::role()` (:170), `SpawnPacketService::role()` (:384), `CompactionPacketService::role()` (:83).
   - **Deliberately LEAVE** the operator-UI guard `Roster/Index.php` `SPAWNABLE_ROLES` (:588) rejecting `lead` — leads are spawned programmatically by MAIN, not hand-spawned from `/roster`.
2. **Lead charter** — `DaemonCharterDefaults::leadBody()` + seeded `daemon_charter` role=lead PromptTemplate row. Charter covers: own the epic (parent brief + children); delegate/review children like the orchestrator (scoped to the epic branch); merge children → epic branch under the `flower-epic-<id>-merge` Solo lock (NOT the baton); the epic-scoped `epic_delegate` mailbox drain carve-out (permitted despite not holding the baton); report up via `epic_return`; the bounded post-merge window + ops handoff + cooperative retire.
3. **Lead spawn-packet variables** — epic brief id, epic branch (`flower/epic-<id>`), epic worktree path.
4. **MAIN-facing spawn affordance** — `flower:spawn-epic-lead` command (or a DirectDispatch-style live spawn) that: ensures the epic branch + worktree exist (worktree-manager external; Brief #184 `WorktreePreparer` gate), `registerExpected('lead', project, actor_ref, epic_brief_id)`, then `SpawnDaemonBridge::spawn()` with the lead charter → `SoloClient::spawnAgent`.

## Tests
- Lead spawn renders the lead charter (not orchestrator/ops/refine).
- The 3 spawn/charter guards permit `lead`, still reject `other`.
- `flower:spawn-epic-lead` registers an expected lead row with the right `epic_brief_id` + actor_ref.

## Notes
- Reuse the existing spawn path; only the charter body + packet vars + the MAIN affordance are new.

Recent/key trace events:
[1] participant_joined flower-226-worker: (no body)
[2] note_added flower-226-worker: # Slice B — Lead charter & spawn path

Design: `docs/design/226-epic-lead-orchestration.md` (§Spawn, §Identity pt.1). Depends on Slice A. Target ≤~300 lines (charter prose excepted).

## Deliverable
1. **Relax the 3 spawn/charter role guards** to permit `lead` (still reject `other`):
   - `SpawnDaemonBridge::role()` (:170), `SpawnPacketService::role()` (:384), `CompactionPacketService::role()` (:83).
   - **Deliberately LEAVE** the operator-UI guard `Roster/Index.php` `SPAWNABLE_ROLES` (:588) rejecting `lead` — leads are spawned programmatically by MAIN, not hand-spawned from `/roster`.
2. **Lead charter** — `DaemonCharterDefaults::leadBody()` + seeded `daemon_charter` role=lead PromptTemplate row. Charter covers: own the epic (parent brief + children); delegate/review children like the orchestrator (scoped to the epic branch); merge children → epic branch under the `flower-epic-<id>-merge` Solo lock (NOT the baton); the epic-scoped `epic_delegate` mailbox drain carve-out (permitted despite not holding the baton); report up via `epic_return`; the bounded post-merge window + ops handoff + cooperative retire.
3. **Lead spawn-packet variables** — epic brief id, epic branch (`flower/epic-<id>`), epic worktree path.
4. **MAIN-facing spawn affordance** — `flower:spawn-epic-lead` command (or a DirectDispatch-style live spawn) that: ensures the epic branch + worktree exist (worktree-manager external; Brief #184 `WorktreePreparer` gate), `registerExpected('lead', project, actor_ref, epic_brief_id)`, then `SpawnDaemonBridge::spawn()` with the lead charter → `SoloClient::spawnAgent`.

## Tests
- Lead spawn renders the lead charter (not orchestrator/ops/refine).
- The 3 spawn/charter guards permit `lead`, still reject `other`.
- `flower:spawn-epic-lead` registers an expected lead row with the right `epic_brief_id` + actor_ref.

## Notes
- Reuse the existing spawn path; only the charter body + packet vars + the MAIN affordance are new.
[3] parent_set flower-226-worker: Grouped under epic #226.
[4] dependency_added flower-226-worker: Now depends on #231 (Epic-lead Slice A — Lead identity & roster scaffolding (#226)).
[5] plan_proposed flower-226-worker: # Slice B — Lead charter & spawn path

Parent epic: #226. Design: `docs/design/226-epic-lead-orchestration.md` (§Spawn, §Identity pt.1). **Depends on Slice A (#231).** Target ≤~300 lines (charter prose excepted).

## Deliverable
1. **Relax the 3 spawn/charter role guards** to permit `lead` (still reject `other`):
   - `SpawnDaemonBridge::role()` (:170), `SpawnPacketService::role()` (:384), `CompactionPacketService::role()` (:83).
   - **Deliberately LEAVE** the operator-UI guard `Roster/Index.php` `SPAWNABLE_ROLES` (:588) rejecting `lead` — leads are spawned programmatically by MAIN, not hand-spawned from `/roster`.
2. **Lead charter** — `DaemonCharterDefaults::leadBody()` + seeded `daemon_charter` role=lead PromptTemplate row. Charter covers: own the epic (parent brief + children); delegate/review children like the orchestrator (scoped to the epic branch); merge children → epic branch under the `flower-epic-<id>-merge` Solo lock (NOT the baton); the epic-scoped `epic_delegate` mailbox drain carve-out (permitted despite not holding the baton); report up via `epic_return`; the bounded post-merge window + ops handoff + cooperative retire.
3. **Lead spawn-packet variables** — epic brief id, epic branch (`flower/epic-<id>`), epic worktree path.
4. **MAIN-facing spawn affordance** — `flower:spawn-epic-lead` command (or a DirectDispatch-style live spawn) that: ensures the epic branch + worktree exist (worktree-manager external; Brief #184 `WorktreePreparer` gate), `registerExpected('lead', project, actor_ref, epic_brief_id)`, then `SpawnDaemonBridge::spawn()` with the lead charter → `SoloClient::spawnAgent`.

## Tests
- Lead spawn renders the lead charter (not orchestrator/ops/refine).
- The 3 spawn/charter guards permit `lead`, still reject `other`.
- `flower:spawn-epic-lead` registers an expected lead row with the right `epic_brief_id` + actor_ref.

## Notes
- Reuse the existing spawn path; only the charter body + packet vars + the MAIN affordance are new.
[6] participant_joined flower-231-worker: (no body)
[7] unblocked flower-231-worker: Unblocked — #231 reached complete.
[8] participant_joined flower-orchestrator: (no body)
[9] 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: #232` 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 22h ago
    agent · system:commit-trailer
  2. participant joined 22h ago
    system · system:commit-trailer
  3. merged 22h ago

    Merged flower/232-epic-lead-slice-b (Slice B — lead charter & spawn path, flower:spawn-epic-lead command) to master by flower-orchestrator (daemon 40). Combined suite green: 1180/1178 pass/2 skip/0 fail.

    agent · flower-orchestrator
  4. status change 22h ago
    agent · flower-232-worker
  5. dispatched 22h ago

    Dispatch request #112 marked done.

    agent · flower-232-worker
  6. note added 22h ago

    Slice B landed on branch flower/232-epic-lead-slice-b (commit 80fe44d). Full test suite green (1155 passed, 1 pre-existing skip); pint clean. What shipped: 1. Relaxed the 3 spawn/charter role guards (SpawnDaemonBridge::role, SpawnPacketService::role, CompactionPacketService::role) to permit `lead`, still rejecting `other`. Deliberately LEFT the operator-UI Roster/Index SPAWNABLE_ROLES rejecting lead (leads are spawned programmatically by MAIN, not from /roster). 2. Lead charter — DaemonCharterDefaults::leadBody() + seeded daemon_charter role=lead PromptTemplate row (daemon_charter.lead.default, v4). Covers: own the epic (parent brief + children); delegate/review children scoped to the epic branch with its own flower.epic_lead.max_concurrent cap; merge children→epic branch under the flower-epic-<id>-merge Solo lock (NOT the baton); the epic-scoped epic_delegate mailbox drain carve-out; report up via epic_return; bounded post-merge window + ops handoff + cooperative retire (daemon_winddown_ready then epic_return{retire}). 3. Lead spawn-packet vars — EPIC_BRIEF_ID / EPIC_BRANCH / EPIC_WORKTREE_PATH + a computed LEAD_ACTOR_REF; the packet's check-in command renders `--role=lead --actor-ref=flower-lead-<id> --epic-brief-id=<id>` and omits the /flower-checkin alias (which can't carry the epic id). 4. SpawnDaemonBridge::spawn() gained an epicBriefId param (threaded to registerExpected + seeded into the packet override so actor_ref never drifts) and plan() resolves the Solo project by a scope_path override so a lead boots into its epic worktree. 5. flower:spawn-epic-lead command — resolves the epic brief + project + branch (default flower/epic-<id>), locates the epic worktree (worktree-manager external; falls back to the discovered worktrees row or --worktree-path), runs the Brief #184 WorktreePreparer gate, then registerExpected('lead', …, epic_brief_id) + SpawnDaemonBridge::spawn with the lead charter. Dry-run by default; --confirm to spawn. Tests added: lead packet renders the lead charter with the epic-scoped check-in (SpawnPacketServiceTest); the 3 guards permit lead / reject other (SpawnPacketServiceTest, SpawnDaemonBridgeTest, CompactionPacketServiceTest); the command registers an expected lead row with the right epic_brief_id + actor_ref + blocks on missing worktree (SpawnEpicLeadCommandTest); charter protocol coverage (DaemonCharterDefaultsTest). Updated the 3 spawn-bridge test doubles for the new spawn() arity and the RecallCharters/seed-count assertions for the 4th charter. Not merged — MAIN orchestrator owns the merge. Signals (epic_delegate/epic_return helpers) + the daemonLines() epic_return drain clause remain Slice C; the lead charter carries only its own carve-out prose per the design.

    agent · flower-232-worker
  7. participant joined 22h ago
    system · flower-232-worker
  8. dispatched 23h ago

    Dispatch request #112 queued for flower.

    agent · flower-orchestrator
  9. status change 23h ago
    agent · flower-orchestrator
  10. status change 23h ago
    agent · flower-orchestrator
  11. participant joined 23h ago
    system · flower-orchestrator
  12. unblocked 23h ago

    Unblocked — #231 reached complete.

    system · flower-231-worker
  13. participant joined 23h ago
    system · flower-231-worker
  14. plan proposed 1d ago

    # Slice B — Lead charter & spawn path Parent epic: #226. Design: `docs/design/226-epic-lead-orchestration.md` (§Spawn, §Identity pt.1). **Depends on Slice A (#231).** Target ≤~300 lines (charter prose excepted). ## Deliverable 1. **Relax the 3 spawn/charter role guards** to permit `lead` (still reject `other`): - `SpawnDaemonBridge::role()` (:170), `SpawnPacketService::role()` (:384), `CompactionPacketService::role()` (:83). - **Deliberately LEAVE** the operator-UI guard `Roster/Index.php` `SPAWNABLE_ROLES` (:588) rejecting `lead` — leads are spawned programmatically by MAIN, not hand-spawned from `/roster`. 2. **Lead charter** — `DaemonCharterDefaults::leadBody()` + seeded `daemon_charter` role=lead PromptTemplate row. Charter covers: own the epic (parent brief + children); delegate/review children like the orchestrator (scoped to the epic branch); merge children → epic branch under the `flower-epic-<id>-merge` Solo lock (NOT the baton); the epic-scoped `epic_delegate` mailbox drain carve-out (permitted despite not holding the baton); report up via `epic_return`; the bounded post-merge window + ops handoff + cooperative retire. 3. **Lead spawn-packet variables** — epic brief id, epic branch (`flower/epic-<id>`), epic worktree path. 4. **MAIN-facing spawn affordance** — `flower:spawn-epic-lead` command (or a DirectDispatch-style live spawn) that: ensures the epic branch + worktree exist (worktree-manager external; Brief #184 `WorktreePreparer` gate), `registerExpected('lead', project, actor_ref, epic_brief_id)`, then `SpawnDaemonBridge::spawn()` with the lead charter → `SoloClient::spawnAgent`. ## Tests - Lead spawn renders the lead charter (not orchestrator/ops/refine). - The 3 spawn/charter guards permit `lead`, still reject `other`. - `flower:spawn-epic-lead` registers an expected lead row with the right `epic_brief_id` + actor_ref. ## Notes - Reuse the existing spawn path; only the charter body + packet vars + the MAIN affordance are new.

    agent · flower-226-worker
  15. dependency added 1d ago

    Now depends on #231 (Epic-lead Slice A — Lead identity & roster scaffolding (#226)).

    agent · flower-226-worker
  16. parent set 1d ago

    Grouped under epic #226.

    agent · flower-226-worker
  17. note added 1d ago

    # Slice B — Lead charter & spawn path Design: `docs/design/226-epic-lead-orchestration.md` (§Spawn, §Identity pt.1). Depends on Slice A. Target ≤~300 lines (charter prose excepted). ## Deliverable 1. **Relax the 3 spawn/charter role guards** to permit `lead` (still reject `other`): - `SpawnDaemonBridge::role()` (:170), `SpawnPacketService::role()` (:384), `CompactionPacketService::role()` (:83). - **Deliberately LEAVE** the operator-UI guard `Roster/Index.php` `SPAWNABLE_ROLES` (:588) rejecting `lead` — leads are spawned programmatically by MAIN, not hand-spawned from `/roster`. 2. **Lead charter** — `DaemonCharterDefaults::leadBody()` + seeded `daemon_charter` role=lead PromptTemplate row. Charter covers: own the epic (parent brief + children); delegate/review children like the orchestrator (scoped to the epic branch); merge children → epic branch under the `flower-epic-<id>-merge` Solo lock (NOT the baton); the epic-scoped `epic_delegate` mailbox drain carve-out (permitted despite not holding the baton); report up via `epic_return`; the bounded post-merge window + ops handoff + cooperative retire. 3. **Lead spawn-packet variables** — epic brief id, epic branch (`flower/epic-<id>`), epic worktree path. 4. **MAIN-facing spawn affordance** — `flower:spawn-epic-lead` command (or a DirectDispatch-style live spawn) that: ensures the epic branch + worktree exist (worktree-manager external; Brief #184 `WorktreePreparer` gate), `registerExpected('lead', project, actor_ref, epic_brief_id)`, then `SpawnDaemonBridge::spawn()` with the lead charter → `SoloClient::spawnAgent`. ## Tests - Lead spawn renders the lead charter (not orchestrator/ops/refine). - The 3 spawn/charter guards permit `lead`, still reject `other`. - `flower:spawn-epic-lead` registers an expected lead row with the right `epic_brief_id` + actor_ref. ## Notes - Reuse the existing spawn path; only the charter body + packet vars + the MAIN affordance are new.

    agent · flower-226-worker
  18. participant joined 1d ago
    system · flower-226-worker

epic · dependencies

Relationships

depends on

agents · waves

Participants

  • flower-226-worker participant · active
  • flower-231-worker participant · active
  • flower-orchestrator participant · active
  • flower-232-worker participant · active
  • system:commit-trailer participant · active

trace · graph

Links

  • Commit #4025 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.