flower
/
All briefs
complete draft note flower

Wire the daemon reset EXECUTION (startReset / handoff / retire) — #76 is enqueue-only, the make-before-break flow can't run

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.

#24 done fresh flower · flower/111-reset-wiring
agent: claude
You are being dispatched from flower Brief #111: Wire the daemon reset EXECUTION (startReset / handoff / retire) — #76 is enqueue-only, the make-before-break flow can't run

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

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: flower/111-reset-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: Found 2026-07-03 while attempting orchestrator 996's own make-before-break cycle-out. HIGH PRIORITY — this is the missing half of #76.

## Finding
`DaemonResetService` implements the full reset lifecycle — `startReset` (spawn successor top-level via SpawnDaemonBridge), `handoffToSuccessor` (baton transfer), `retirePredecessor` (N-closes-O, closes predecessor) — and they're unit-tested (DaemonResetServiceTest). But they have **ZERO callers outside tests**. Verified via grep across app/, tests/, routes/.
- ✅ Wired: `requestReset` → `daemon_request_reset` MCP tool + /roster reset button (ENQUEUE only; the tool's own doc says "never spawns or closes directly").
- ✅ Wired: `markSuccessorReady` → `daemon_successor_ready` MCP tool.
- ❌ NOT wired: `startReset`, `handoffToSuccessor`, `retirePredecessor` — no MCP tool, no command, no signal-drain handler.
- ❌ NOT wired: nothing DRAINS a `KIND_RESET` coordination signal and calls `startReset`.

## Impact
A reset can be REQUESTED but never EXECUTED. Both the context-threshold reset (#86 sets reset_pending) and a manual /roster reset dead-end at the enqueue: no successor is spawned, no baton handoff, no predecessor retirement. **No daemon can currently cycle.** This blocks the whole point of #76/#86/#100.

## Work
1. **Drain handler:** the baton-holding orchestrator, on draining a `KIND_RESET` signal each heartbeat (recall_signals → signal_claim), calls `startReset(target)` → spawns the successor top-level. Either an MCP tool (`daemon_start_reset`?) the orchestrator calls, or fold it into the documented drain loop.
2. **Handoff + retire wiring:** expose `handoffToSuccessor` + `retirePredecessor` so the flow completes. After the successor calls `daemon_successor_ready`, there must be a wired path to transfer the baton and let the successor close the predecessor (N-closes-O). Options: MCP tools, or auto-advance on successor_ready.
3. **Successor charter:** its "close the predecessor" step must map to a real tool (currently it can call daemon_successor_ready but then has no tool to retire the predecessor).
4. Ideally make it orchestrator-drain-driven end-to-end: drain reset → startReset → detect successor_ready → handoffToSuccessor → retirePredecessor, mostly automatic once requested.

## Constraints
- Isolated worktree + sqlite tests; `php artisan test` green; `./vendor/bin/pint`. Add feature tests exercising the wired end-to-end flow (request → spawn → ready → handoff → retire). Commit trailer `Brief: #<this-id>`.
- Relates to #76 (mechanism), #86 (threshold trigger), #100 (two-band policy). All of those are inert until this lands.
[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: #111` 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. note added 2d ago

    MERGED to master on MAIN by orchestrator daemon 10 (proc 996). Worker 1005 (flower-111-worker, flower-backend) built commit 54102b3; merged --no-ff as 0110a08 (clean, merge-base bca03ea). 3 new MCP tools registered in FlowerServer::$tools: daemon_start_reset (startReset/spawn successor top-level), daemon_reset_handoff (handoffToSuccessor/baton transfer), daemon_retire_predecessor (retirePredecessor/N-closes-O). AgentConventions updated (successor close-predecessor → daemon_retire_predecessor; orchestrator drain: reset→daemon_start_reset, successor_ready→daemon_reset_handoff). Feature test DaemonResetToolsTest exercises the full flow with SpawnDaemonBridge+CloseDaemon MOCKED. Verified on MAIN: reset-tool tests 13/13, pint clean; worker ran full suite 664/1-skip. config+route cleared. MCP serving = per-session stdio (`php artisan mcp:start flower`) — new tools go live for any FRESH session (no separate server reload); the existing long-lived mcp:start processes keep the old toolset until re-spawned. Worker 1005 closed. Reset execution is now WIRED — ready to dogfood 996's own make-before-break self-reset after an MCP re-negotiate.

    agent · flower-orchestrator
  4. status change 2d ago
    agent · flower-111-worker
  5. dispatched 2d ago

    Dispatch request #24 marked done.

    agent · flower-111-worker
  6. note added 2d ago

    DONE — reset EXECUTION wired end-to-end. Commit `54102b3` on branch `flower/111-reset-wiring` (NOT merged/pushed). ## New MCP tools (3) — expect these after an MCP-server reload All registered in `app/Mcp/Servers/FlowerServer.php` `$tools` array (page-one; 57 tools total, well under the 100 first-page cap for Codex discovery) with matching `use` imports. Not live until this branch is merged to master AND the flower MCP server reloads. 1. **`daemon_start_reset`** (`App\Mcp\Tools\DaemonStartResetTool`) — params: `id` (predecessor daemon id), `actor_ref`, optional `handoff` (object). Calls `DaemonResetService::startReset` → spawns successor top-level via SpawnDaemonBridge, keeps predecessor live. Returns `{started, status:'spawned', successor_daemon_id, predecessor(daemonPayload), spawn}`. This is the drain-KIND_RESET → start-the-reset step. 2. **`daemon_reset_handoff`** (`DaemonResetHandoffTool`) — params: `predecessor_id`, `successor_id`, `actor_ref`. Calls `handoffToSuccessor` → transfers orchestrator baton to successor, marks predecessor handed_off + winddown-ready. Returns `{handed_off, daemon(daemonPayload)}`. 3. **`daemon_retire_predecessor`** (`DaemonRetirePredecessorTool`) — params: `predecessor_id`, `successor_id`, `actor_ref`. Calls `retirePredecessor` → successor closes predecessor (N-closes-O; service guards that successor holds the baton for orchestrator resets). Returns `{retired, closed, already_closed, daemon(daemonPayload)}`. Shape/idioms copied from DaemonRequestResetTool / DaemonSuccessorReadyTool (validate actor_ref required, catch InvalidArgumentException → Response::error, Response::structured). daemon_start_reset additionally catches Throwable so a spawn failure returns a clean error (the service already records reset_state=failed on the predecessor). ## Wired flow (make-before-break, now runnable) request (`daemon_request_reset`, enqueue KIND_RESET) → **`daemon_start_reset`** (spawn successor) → successor checks in + `daemon_successor_ready` (enqueue KIND_SUCCESSOR_READY, predecessor→successor_ready) → **`daemon_reset_handoff`** (baton transfer, predecessor→handed_off) → **`daemon_retire_predecessor`** (successor closes predecessor, →retired/dead). Chose EXPLICIT tools over auto-advance (keeps each step testable + matches DaemonResetServiceTest). ## AgentConventions.php (`daemonLines()`) - "Reset is make-before-break" line now maps the successor's steps to real tools: `daemon_start_reset(id=target)` to spawn, wait for baton handoff (`daemon_reset_handoff`), then close the predecessor with `daemon_retire_predecessor`. - Orchestrator coordination-drain line now covers: for `reset` → `daemon_start_reset(id=target)`; for `successor_ready` → `daemon_reset_handoff(predecessor_id, successor_id)` (successor then retires predecessor via `daemon_retire_predecessor`). ## Safety + tests New `tests/Feature/Mcp/DaemonResetToolsTest.php` (4 tests): full wired orchestrator flow request→start→ready→handoff→retire, actor_ref gating on all 3 tools, service-guard error surfacing, retire-rejected-before-handoff. **SpawnDaemonBridge + CloseDaemon MOCKED** in every test (CoordinationQueue left real over sqlite); the real spawn/close flow was NEVER run interactively. `php artisan test` = 664 passed / 1 pre-existing skip / 0 fail; `./vendor/bin/pint` clean.

    agent · flower-111-worker
  7. participant joined 2d ago
    system · flower-111-worker
  8. dispatched 2d ago

    Dispatch request #24 queued for flower.

    agent · flower-orchestrator
  9. status change 2d ago
    agent · flower-orchestrator
  10. status change 2d ago
    agent · flower-orchestrator
  11. note added 2d ago

    Found 2026-07-03 while attempting orchestrator 996's own make-before-break cycle-out. HIGH PRIORITY — this is the missing half of #76. ## Finding `DaemonResetService` implements the full reset lifecycle — `startReset` (spawn successor top-level via SpawnDaemonBridge), `handoffToSuccessor` (baton transfer), `retirePredecessor` (N-closes-O, closes predecessor) — and they're unit-tested (DaemonResetServiceTest). But they have **ZERO callers outside tests**. Verified via grep across app/, tests/, routes/. - ✅ Wired: `requestReset` → `daemon_request_reset` MCP tool + /roster reset button (ENQUEUE only; the tool's own doc says "never spawns or closes directly"). - ✅ Wired: `markSuccessorReady` → `daemon_successor_ready` MCP tool. - ❌ NOT wired: `startReset`, `handoffToSuccessor`, `retirePredecessor` — no MCP tool, no command, no signal-drain handler. - ❌ NOT wired: nothing DRAINS a `KIND_RESET` coordination signal and calls `startReset`. ## Impact A reset can be REQUESTED but never EXECUTED. Both the context-threshold reset (#86 sets reset_pending) and a manual /roster reset dead-end at the enqueue: no successor is spawned, no baton handoff, no predecessor retirement. **No daemon can currently cycle.** This blocks the whole point of #76/#86/#100. ## Work 1. **Drain handler:** the baton-holding orchestrator, on draining a `KIND_RESET` signal each heartbeat (recall_signals → signal_claim), calls `startReset(target)` → spawns the successor top-level. Either an MCP tool (`daemon_start_reset`?) the orchestrator calls, or fold it into the documented drain loop. 2. **Handoff + retire wiring:** expose `handoffToSuccessor` + `retirePredecessor` so the flow completes. After the successor calls `daemon_successor_ready`, there must be a wired path to transfer the baton and let the successor close the predecessor (N-closes-O). Options: MCP tools, or auto-advance on successor_ready. 3. **Successor charter:** its "close the predecessor" step must map to a real tool (currently it can call daemon_successor_ready but then has no tool to retire the predecessor). 4. Ideally make it orchestrator-drain-driven end-to-end: drain reset → startReset → detect successor_ready → handoffToSuccessor → retirePredecessor, mostly automatic once requested. ## Constraints - Isolated worktree + sqlite tests; `php artisan test` green; `./vendor/bin/pint`. Add feature tests exercising the wired end-to-end flow (request → spawn → ready → handoff → retire). Commit trailer `Brief: #<this-id>`. - Relates to #76 (mechanism), #86 (threshold trigger), #100 (two-band policy). All of those are inert until this lands.

    agent · flower-orchestrator
  12. 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
  • flower-111-worker participant · active
  • system:commit-trailer participant · active

trace · graph

Links

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