flower
/
All briefs
complete feedback flower
from feedback #71 · Orchestrator completed brief #143 while it still had...

Feedback #71: Orchestrator completed brief #143 while it still had 4 unanswered operator questions

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.

#99 done fresh flower · flower/159-completion-guard-open-questions
agent: claude 1 scratchpad
You are being dispatched from flower Brief #159: Feedback #71: Orchestrator completed brief #143 while it still had 4 unanswered operator questions

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

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: flower/159-completion-guard-open-questions
- worktree: not specified
- kind: fresh

Current brief spec:
## Status — "have we already addressed this?" (code grounding, 2026-07-03)
**Partially.**
- ✅ **Badge scoping — already fixed.** `BriefQuestion::openCount()` (`app/Models/BriefQuestion.php:39-48`) already excludes questions whose brief is `Complete` / `Cancelled` / `Abandoned` (docblock cites Brief #109). So the nav open-questions badge no longer counts stale-open questions on completed briefs — the "badge 8 vs view 4" half of feedback #71 is resolved. **Do not re-implement this.**
- ❌ **Completion guard — NOT present.** `DispatchService::recomputeRollup()` (`app/Services/Briefs/DispatchService.php:177-182`) flips a brief to `BriefStatus::Complete` as soon as it has a completed dispatch, with **no check for open operator questions**. So the #71 root cause — a brief auto-completing while operator questions are still `open`, silently dropping them (exactly what happened to #143's Q28-31) — can still recur. This is the remaining work.

## Goal
Prevent a brief from being marked **Complete while it has open operator questions**, so operator questions can never be silently dropped by dispatch rollup (or any other path).

## Change
- Enforce the invariant at the single status chokepoint — `BriefService::setStatus()` — when the target is `Complete`: if the brief has any `BriefQuestion` with `status = Open`, **refuse/hold the transition** rather than silently completing. Enforcing it here covers every path: dispatch `recomputeRollup()`, direct `brief_update_status`, and the auto-dispatch rollup.
  - **Recommended behavior: block/hold** — don't complete; keep the prior status (e.g. `Dispatched`) and record the reason in the trace. This preserves operator agency; #143's Q28-31 were meaningful decisions the operator DID want to answer.
  - **Explicit escape (so briefs aren't stranded):** an operator/orchestrator action to **dismiss** the open questions (or the operator answering them) — after which completion proceeds. `BriefQuestionStatus` already has a `dismissed` state.
  - **Alternative considered & rejected as default** (feedback #71's other option): auto-dismiss open questions on completion. Rejected because it reproduces the "silently dropped" failure; dismissal must be explicit.

## Acceptance
- A brief with an open operator question cannot transition to `Complete` via any path (dispatch rollup, direct status update, auto-dispatch); the attempt is blocked/held with a clear reason recorded.
- Explicitly dismissing (or answering) the open questions then allows completion.
- Regression test reproducing the #71/#143 scenario: worker posts operator questions → a dispatch completes → the brief does **not** flip to `Complete` while questions are open; once dismissed/answered, it can.
- `php artisan test` green + `./vendor/bin/pint` on touched files. `Brief: #159` trailer.

## Non-goals
- The nav badge scoping (already done via `openCount` / #109).
- The broader Open-Questions view/badge realignment (tracked on #154).

## Provenance
Feedback #71 (flower-orchestrator daemon 17) → autonomous-authority brief. Operator asked "have we already addressed this?" (2026-07-03) → grounded: badge half already fixed (#109), completion-guard half is the remaining work, specced here. Shares the `recomputeRollup` completion chokepoint with #143 (review gate).

Recent/key trace events:
[1] participant_joined operator:mike: (no body)
[2] note_added operator:mike: Feedback #71
Authority: AUTONOMOUS
Funnel: B - autonomous brief
Gate: this bug/MCP/Sentry feedback may be planned without operator approval.
Kind: bug
Source: flower-orchestrator (daemon 17)

Summary:
Orchestrator completed brief #143 while it still had 4 unanswered operator questions

Detail:
Brief #143 ("Adversarial reviews"): worker flower-design-143 posted 4 agent_questions for the operator at 14:36:25; an orchestrator then marked it dispatched→complete at 14:40:53 (~4 min later) with those 4 questions still status=open. Effects: (1) the operator's Q28-31 were silently dropped — the brief looked done, so the operator never saw them; (2) the nav open-questions badge counts these stale-open questions on a completed brief, which is the root of the "badge shows 8 but the open-questions view shows 4" mismatch the operator reported (view hides completed briefs; badge does not). Proposal: block (or at least warn on) completing a brief that has open operator questions, OR auto-resolve/dismiss its open questions on completion; and scope the nav badge (BriefQuestion::openCount) to exclude questions on complete/cancelled/abandoned briefs (being fixed separately).
[3] link_added operator:mike: (no body)
[4] status_change operator:mike: (no body)
[5] note_added operator:mike: Have we already addressed this?
[6] status_change operator:mike: (no body)
[7] participant_joined flower-refine: (no body)
[8] plan_proposed flower-refine: ## Status — "have we already addressed this?" (code grounding, 2026-07-03)
**Partially.**
- ✅ **Badge scoping — already fixed.** `BriefQuestion::openCount()` (`app/Models/BriefQuestion.php:39-48`) already excludes questions whose brief is `Complete` / `Cancelled` / `Abandoned` (docblock cites Brief #109). So the nav open-questions badge no longer counts stale-open questions on completed briefs — the "badge 8 vs view 4" half of feedback #71 is resolved. **Do not re-implement this.**
- ❌ **Completion guard — NOT present.** `DispatchService::recomputeRollup()` (`app/Services/Briefs/DispatchService.php:177-182`) flips a brief to `BriefStatus::Complete` as soon as it has a completed dispatch, with **no check for open operator questions**. So the #71 root cause — a brief auto-completing while operator questions are still `open`, silently dropping them (exactly what happened to #143's Q28-31) — can still recur. This is the remaining work.

## Goal
Prevent a brief from being marked **Complete while it has open operator questions**, so operator questions can never be silently dropped by dispatch rollup (or any other path).

## Change
- Enforce the invariant at the single status chokepoint — `BriefService::setStatus()` — when the target is `Complete`: if the brief has any `BriefQuestion` with `status = Open`, **refuse/hold the transition** rather than silently completing. Enforcing it here covers every path: dispatch `recomputeRollup()`, direct `brief_update_status`, and the auto-dispatch rollup.
  - **Recommended behavior: block/hold** — don't complete; keep the prior status (e.g. `Dispatched`) and record the reason in the trace. This preserves operator agency; #143's Q28-31 were meaningful decisions the operator DID want to answer.
  - **Explicit escape (so briefs aren't stranded):** an operator/orchestrator action to **dismiss** the open questions (or the operator answering them) — after which completion proceeds. `BriefQuestionStatus` already has a `dismissed` state.
  - **Alternative considered & rejected as default** (feedback #71's other option): auto-dismiss open questions on completion. Rejected because it reproduces the "silently dropped" failure; dismissal must be explicit.

## Acceptance
- A brief with an open operator question cannot transition to `Complete` via any path (dispatch rollup, direct status update, auto-dispatch); the attempt is blocked/held with a clear reason recorded.
- Explicitly dismissing (or answering) the open questions then allows completion.
- Regression test reproducing the #71/#143 scenario: worker posts operator questions → a dispatch completes → the brief does **not** flip to `Complete` while questions are open; once dismissed/answered, it can.
- `php artisan test` green + `./vendor/bin/pint` on touched files. `Brief: #159` trailer.

## Non-goals
- The nav badge scoping (already done via `openCount` / #109).
- The broader Open-Questions view/badge realignment (tracked on #154).

## Provenance
Feedback #71 (flower-orchestrator daemon 17) → autonomous-authority brief. Operator asked "have we already addressed this?" (2026-07-03) → grounded: badge half already fixed (#109), completion-guard half is the remaining work, specced here. Shares the `recomputeRollup` completion chokepoint with #143 (review gate).
[9] status_change flower-refine: (no body)
[10] link_added flower-refine: (no body)

Recommended linked context:
{
    "todos": [],
    "scratchpads": [
        {
            "id": 378,
            "solo_scratchpad_id": "1070",
            "name": "flower-refine — reset handoff (2026-07-04)",
            "archived": false,
            "revision": 2
        }
    ]
}

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: #159` 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 1d ago
    agent · system:commit-trailer
  2. participant joined 1d ago
    system · system:commit-trailer
  3. status change 1d ago
    agent · flower-orchestrator
  4. merged 1d ago

    Merged to master as cfb4d36 (branch commit 2c154fd). BriefService::setStatus() now HOLDS a brief at its prior status (recording a completion_blocked trace note) instead of flipping to Complete while it has any open operator question (Decision status=Open). Single chokepoint → covers dispatch recomputeRollup(), review rollup, direct brief_update_status, and auto-dispatch. Answering or dismissing the questions clears the hold. +CompletionGuardTest (5 tests) + a legit OpenQuestionsBadgeTest reorder (terminal status before asking; #109 openCount scoping intact). Full suite green (1049 passed, 2 skips). No migration. Horizon gracefully reloaded so queued rollups run the guard.

    agent · flower-orchestrator
  5. status change 1d ago
    agent · flower-159-worker
  6. dispatched 1d ago

    Dispatch request #99 marked done.

    agent · flower-159-worker
  7. note added 1d ago

    Completion guard shipped on branch flower/159-completion-guard-open-questions (commit 2c154fd, branched off master 129fbe1; NOT pushed — orchestrator merges). Change: BriefService::setStatus() now holds any transition to Complete while the brief has an open operator question (Decision status=Open), keeping the prior status and recording a machine-readable `completion_blocked` trace note instead of silently completing. setStatus() is the single status chokepoint, so this covers dispatch recomputeRollup(), the review-pass rollup, direct brief_update_status, and the auto-dispatch rollup. Answering or dismissing the questions clears the hold; the next completion attempt (rollup re-fire or direct set) proceeds. Hold note is idempotent (won't re-spam on a re-firing rollup). Chose BLOCK/HOLD per spec — did NOT auto-dismiss (rejected default). Grounding confirmed the badge half was already fixed (#109) and left untouched. Files: app/Services/Briefs/BriefService.php (+guard, +2 private helpers openOperatorQuestionCount / holdCompletionForOpenQuestions); tests/Feature/Briefs/CompletionGuardTest.php (new, 5 tests reproducing #71/#143: worker posts questions → dispatch completes → held at Dispatched not Complete; answer→completes; dismiss→completes; direct setStatus guarded; no-question path still completes). Also updated OpenQuestionsBadgeTest to set terminal status before asking (a brief can no longer be completed while a question is open — the old setup relied on the now-forbidden behavior; intent preserved: openCount still scopes out terminal briefs). Verify: full `php artisan test` green — 1051 tests, 1049 passed, 2 pre-existing skips, 6636 assertions. Pint clean on touched files.

    agent · flower-159-worker
  8. participant joined 1d ago
    system · flower-159-worker
  9. dispatched 1d ago

    Dispatch request #99 queued for flower.

    agent · flower-orchestrator
  10. status change 1d ago
    agent · flower-orchestrator
  11. participant joined 1d ago
    system · flower-orchestrator
  12. link added 1d ago
    agent · flower-refine
  13. status change 1d ago
    agent · flower-refine
  14. plan proposed 1d ago

    ## Status — "have we already addressed this?" (code grounding, 2026-07-03) **Partially.** - ✅ **Badge scoping — already fixed.** `BriefQuestion::openCount()` (`app/Models/BriefQuestion.php:39-48`) already excludes questions whose brief is `Complete` / `Cancelled` / `Abandoned` (docblock cites Brief #109). So the nav open-questions badge no longer counts stale-open questions on completed briefs — the "badge 8 vs view 4" half of feedback #71 is resolved. **Do not re-implement this.** - ❌ **Completion guard — NOT present.** `DispatchService::recomputeRollup()` (`app/Services/Briefs/DispatchService.php:177-182`) flips a brief to `BriefStatus::Complete` as soon as it has a completed dispatch, with **no check for open operator questions**. So the #71 root cause — a brief auto-completing while operator questions are still `open`, silently dropping them (exactly what happened to #143's Q28-31) — can still recur. This is the remaining work. ## Goal Prevent a brief from being marked **Complete while it has open operator questions**, so operator questions can never be silently dropped by dispatch rollup (or any other path). ## Change - Enforce the invariant at the single status chokepoint — `BriefService::setStatus()` — when the target is `Complete`: if the brief has any `BriefQuestion` with `status = Open`, **refuse/hold the transition** rather than silently completing. Enforcing it here covers every path: dispatch `recomputeRollup()`, direct `brief_update_status`, and the auto-dispatch rollup. - **Recommended behavior: block/hold** — don't complete; keep the prior status (e.g. `Dispatched`) and record the reason in the trace. This preserves operator agency; #143's Q28-31 were meaningful decisions the operator DID want to answer. - **Explicit escape (so briefs aren't stranded):** an operator/orchestrator action to **dismiss** the open questions (or the operator answering them) — after which completion proceeds. `BriefQuestionStatus` already has a `dismissed` state. - **Alternative considered & rejected as default** (feedback #71's other option): auto-dismiss open questions on completion. Rejected because it reproduces the "silently dropped" failure; dismissal must be explicit. ## Acceptance - A brief with an open operator question cannot transition to `Complete` via any path (dispatch rollup, direct status update, auto-dispatch); the attempt is blocked/held with a clear reason recorded. - Explicitly dismissing (or answering) the open questions then allows completion. - Regression test reproducing the #71/#143 scenario: worker posts operator questions → a dispatch completes → the brief does **not** flip to `Complete` while questions are open; once dismissed/answered, it can. - `php artisan test` green + `./vendor/bin/pint` on touched files. `Brief: #159` trailer. ## Non-goals - The nav badge scoping (already done via `openCount` / #109). - The broader Open-Questions view/badge realignment (tracked on #154). ## Provenance Feedback #71 (flower-orchestrator daemon 17) → autonomous-authority brief. Operator asked "have we already addressed this?" (2026-07-03) → grounded: badge half already fixed (#109), completion-guard half is the remaining work, specced here. Shares the `recomputeRollup` completion chokepoint with #143 (review gate).

    agent · flower-refine
  15. participant joined 1d ago
    system · flower-refine
  16. status change 1d ago
    agent · operator:mike
  17. note added 1d ago

    Have we already addressed this?

    operator · operator:mike
  18. status change 1d ago
    agent · operator:mike
  19. link added 1d ago
    agent · operator:mike
  20. note added 1d ago

    Feedback #71 Authority: AUTONOMOUS Funnel: B - autonomous brief Gate: this bug/MCP/Sentry feedback may be planned without operator approval. Kind: bug Source: flower-orchestrator (daemon 17) Summary: Orchestrator completed brief #143 while it still had 4 unanswered operator questions Detail: Brief #143 ("Adversarial reviews"): worker flower-design-143 posted 4 agent_questions for the operator at 14:36:25; an orchestrator then marked it dispatched→complete at 14:40:53 (~4 min later) with those 4 questions still status=open. Effects: (1) the operator's Q28-31 were silently dropped — the brief looked done, so the operator never saw them; (2) the nav open-questions badge counts these stale-open questions on a completed brief, which is the root of the "badge shows 8 but the open-questions view shows 4" mismatch the operator reported (view hides completed briefs; badge does not). Proposal: block (or at least warn on) completing a brief that has open operator questions, OR auto-resolve/dismiss its open questions on completion; and scope the nav badge (BriefQuestion::openCount) to exclude questions on complete/cancelled/abandoned briefs (being fixed separately).

    agent · operator:mike
  21. participant joined 1d ago
    system · operator:mike

epic · dependencies

Relationships

epic parent

depends on

No dependencies — dispatchable once planned.

agents · waves

Participants

  • operator:mike participant · active
  • flower-refine participant · active
  • flower-orchestrator participant · active
  • flower-159-worker participant · active
  • system:commit-trailer participant · active

trace · graph

Links

  • Commit #4001 execution
  • Scratchpad #378 execution
  • Feedback #71 seed

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.