flower
/
All briefs
complete draft note flower

Feedback visibility/surfacing items needing operator action Let's do

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.

#104 done fresh flower · flower/156-feedback-visibility
agent: claude 1 scratchpad
You are being dispatched from flower Brief #156: Feedback visibility/surfacing items needing operator action

Let's do

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

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: flower/156-feedback-visibility
- worktree: not specified
- kind: fresh

Current brief spec:
## Goal
Make feedback that **needs operator action** visible and easy to find (mirror the Open Questions nav pattern), and make the **feedback status model legible** so the operator knows which items they must act on vs. which the daemons handle autonomously.

## Grounded status model (current — `App\Models\Feedback` + `App\Services\Feedback\FeedbackPromotionService`)
**Kinds** (`FeedbackKind`): `bug`, `note`, `idea`, `mcp_issue`.
**Statuses** (`Feedback::STATUSES`): `open` (new/untriaged) → `triaged` → `planned` (promoted to a brief or routed to the orchestrator) → resolved: `addressed` | `wontfix` | `duplicate`.
**Who acts (the funnel):**
- `note` → self-handled → `addressed`. **No operator action.**
- `bug` / `mcp_issue` / sentry-sourced → **AUTONOMOUS (Funnel B)** → promoted to a brief (no approval) or routed to the orchestrator (todo + fix-spec) → `planned`. **No operator action.**
- `idea` (and feature / changed-functionality signals) → **OPERATOR-GATED (Funnel A)** → promoted to a brief with `needs_operator_approval=true` (draft, non-dispatchable); the operator must approve (`FeedbackPromotionService::approveBrief`) before it can dispatch. **← the only bucket that needs operator action.**

So **"needs operator action" = feedback whose promotion produced an operator-gated brief still pending approval** (Funnel A / idea-class).

## Scope
1. **Nav "needs action" count + badge + link** — mirror `BriefQuestion::openCount()` / the Open Questions badge: a single source of truth (e.g. `Feedback::needsOperatorActionCount()` or a `briefs.needs_operator_approval` count) feeding the nav badge, broadcast on change (like `OpenQuestionsChanged`). Clicking → the `/feedback` view filtered to the needs-action set.
2. **/feedback filter** for "needs my action" (the operator-gated pending-approval set), alongside the existing kind/status filters.
3. **Status legend / help on `/feedback`** — a short inline legend explaining each status + which kinds are autonomous vs operator-gated + what the operator is expected to do (approve/reject the gated ones). Directly resolves the "I'm confused which items I act on" ask.

## Decision (defaulted — adjust if desired)
"Needs action" is scoped to **operator-gated briefs pending approval** (recommended — it's the only set the funnel actually requires the operator to touch). If you also want `open`/untriaged feedback surfaced (e.g. as a health signal for when the autonomous triage loop is down), add it as a **secondary** count rather than folding it into the primary badge. Defaulting to the former.

## Acceptance
- Nav shows a feedback "needs action" badge/count (single source of truth + live update) linking to the filtered `/feedback` view; count = operator-gated briefs pending approval.
- `/feedback` has a "needs my action" filter + a status legend explaining the model and who acts.
- Tests: the count excludes autonomous/resolved and includes only pending operator-gated; the filter works. `php artisan test` green + `./vendor/bin/pint`. `Brief: #156` trailer.

## Non-goals
- Changing the feedback status set or the funnel routing (this brief surfaces + explains the current model; if the review prompts a status-model change, that's a separate brief).

## Provenance
Operator note (#156, 2026-07-03) — "surface feedback needing my action, and clarify the status model." Grounded against `Feedback::STATUSES` + `FeedbackPromotionService` funnel by flower-refine 2026-07-03. UI pattern to mirror: the Open Questions badge (`BriefQuestion::openCount` / #109). Related: #154 (open-questions view/badge realignment).

Recent/key trace events:
[1] participant_joined operator:mike: (no body)
[2] note_added operator:mike: Feedback visibility/surfacing items needing operator action

Let's do something similar to the Open Questions link + count/badge + filter for Feedback so I know if there are items awaiting my action from the nav menu

Also - let's review how and what statuses the Feedback items can fall into and what those mean/what's next for them. I'm kind of confused as to which items I'm supposed to do something with and if I'm supposed to do something what I'm supposed to do.
[3] status_change operator:mike: (no body)
[4] participant_joined flower-refine: (no body)
[5] spec_snapshot flower-refine: Feedback visibility/surfacing items needing operator action

Let's do something similar to the Open Questions link + count/badge + filter for Feedback so I know if there are items awaiting my action from the nav menu

Also - let's review how and what statuses the Feedback items can fall into and what those mean/what's next for them. I'm kind of confused as to which items I'm supposed to do something with and if I'm supposed to do something what I'm supposed to do.
[6] refinement flower-refine: ## Goal
Make feedback that **needs operator action** visible and easy to find (mirror the Open Questions nav pattern), and make the **feedback status model legible** so the operator knows which items they must act on vs. which the daemons handle autonomously.

## Grounded status model (current — `App\Models\Feedback` + `App\Services\Feedback\FeedbackPromotionService`)
**Kinds** (`FeedbackKind`): `bug`, `note`, `idea`, `mcp_issue`.
**Statuses** (`Feedback::STATUSES`): `open` (new/untriaged) → `triaged` → `planned` (promoted to a brief or routed to the orchestrator) → resolved: `addressed` | `wontfix` | `duplicate`.
**Who acts (the funnel):**
- `note` → self-handled → `addressed`. **No operator action.**
- `bug` / `mcp_issue` / sentry-sourced → **AUTONOMOUS (Funnel B)** → promoted to a brief (no approval) or routed to the orchestrator (todo + fix-spec) → `planned`. **No operator action.**
- `idea` (and feature / changed-functionality signals) → **OPERATOR-GATED (Funnel A)** → promoted to a brief with `needs_operator_approval=true` (draft, non-dispatchable); the operator must approve (`FeedbackPromotionService::approveBrief`) before it can dispatch. **← the only bucket that needs operator action.**

So **"needs operator action" = feedback whose promotion produced an operator-gated brief still pending approval** (Funnel A / idea-class).

## Scope
1. **Nav "needs action" count + badge + link** — mirror `BriefQuestion::openCount()` / the Open Questions badge: a single source of truth (e.g. `Feedback::needsOperatorActionCount()` or a `briefs.needs_operator_approval` count) feeding the nav badge, broadcast on change (like `OpenQuestionsChanged`). Clicking → the `/feedback` view filtered to the needs-action set.
2. **/feedback filter** for "needs my action" (the operator-gated pending-approval set), alongside the existing kind/status filters.
3. **Status legend / help on `/feedback`** — a short inline legend explaining each status + which kinds are autonomous vs operator-gated + what the operator is expected to do (approve/reject the gated ones). Directly resolves the "I'm confused which items I act on" ask.

## Decision (defaulted — adjust if desired)
"Needs action" is scoped to **operator-gated briefs pending approval** (recommended — it's the only set the funnel actually requires the operator to touch). If you also want `open`/untriaged feedback surfaced (e.g. as a health signal for when the autonomous triage loop is down), add it as a **secondary** count rather than folding it into the primary badge. Defaulting to the former.

## Acceptance
- Nav shows a feedback "needs action" badge/count (single source of truth + live update) linking to the filtered `/feedback` view; count = operator-gated briefs pending approval.
- `/feedback` has a "needs my action" filter + a status legend explaining the model and who acts.
- Tests: the count excludes autonomous/resolved and includes only pending operator-gated; the filter works. `php artisan test` green + `./vendor/bin/pint`. `Brief: #156` trailer.

## Non-goals
- Changing the feedback status set or the funnel routing (this brief surfaces + explains the current model; if the review prompts a status-model change, that's a separate brief).

## Provenance
Operator note (#156, 2026-07-03) — "surface feedback needing my action, and clarify the status model." Grounded against `Feedback::STATUSES` + `FeedbackPromotionService` funnel by flower-refine 2026-07-03. UI pattern to mirror: the Open Questions badge (`BriefQuestion::openCount` / #109). Related: #154 (open-questions view/badge realignment).
[7] status_change flower-refine: (no body)
[8] 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: #156` 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. merged 1d ago

    Merged flower/156-feedback-visibility into master on MAIN — merge commit **9671c9a** (worker commit 60499f5). Clean 3-way merge, no collision (Feedback model / nav layout / app.js / feedback blade distinct from the decisions + briefs work). Full suite green on MAIN (1105 passed, 2 skips, 6863 assertions); pint clean; npm build done (nav badge + app.js + feedback view). Good reuse: leveraged Brief #180's existing pendingApprovalCount SSOT + PendingApprovalChanged broadcast rather than duplicating. No Horizon reload (no queued job/listener — plain broadcast). Worker proc 1126 closed.

    agent · flower-orchestrator
  4. status change 1d ago
    agent · flower-156-worker
  5. dispatched 1d ago

    Dispatch request #104 marked done.

    agent · flower-156-worker
  6. note added 1d ago

    Shipped on branch flower/156-feedback-visibility (commit 60499f5, `Brief: #156` trailer). Do NOT merge — orchestrator merges from MAIN. Approach: the SSOT + broadcast for "needs operator action" already existed from Brief #180 (`Brief::pendingApprovalCount()` + `PendingApprovalChanged` on the `pending-approval` channel, dispatched from FeedbackPromotionService promote/approve). So I reused them rather than adding a parallel count — surfacing the same value under Feedback and adding the /feedback filter + legend. Files: - app/Models/Feedback.php — new `scopeNeedsOperatorAction` (feedback-side projection of pendingApprovalCount: whereHas gated, non-terminal brief). - resources/views/components/layouts/app.blade.php — "Needs my action" sub-link + live badge under the Feedback nav item (mirrors Open Questions / Pending Approval sublinks), linking to /feedback?needs=me. Reuses the `$pendingApprovalCount` already computed for the Briefs sub-nav → no extra query. - resources/js/app.js — `updateFeedbackNeedsActionBadge()` driven off the same PendingApprovalChanged broadcast, so the Feedback badge stays in lockstep with the Briefs one. - app/Livewire/Feedback/Index.php — `#[Url] needs` filter (?needs=me) + `setNeeds()` + `needsActionCount`. - resources/views/livewire/feedback/index.blade.php — "Needs my action" filter chip (past a divider from the kind axis) + a collapsible status legend (three funnel lanes: note self-handled / bug·mcp·sentry autonomous / idea·feature operator-gated, plus per-status meanings). Hoisted the shared status→color map to the top. - tests/Feature/Feedback/FeedbackNeedsActionTest.php (new, 7 tests) — scope (only pending gated; excludes autonomous/resolved/terminal/un-promoted/notes), count consistency through the real funnel (promote→surfaced, approve→cleared, badge count == pendingApprovalCount 1:1), nav badge markup (renders count + hidden at 0), ?needs=me filter, legend presence. - tests/Feature/QueryEfficiencyAuditTest.php — bumped /feedback budget 4→5 for the one bounded needs-action count(*) aggregate (documented inline). Design note: nav badge count = Brief::pendingApprovalCount() (brief-side SSOT, already broadcast); /feedback filter chip count = Feedback::needsOperatorAction()->count() (feedback-side). They agree 1:1 in the funnel (each gated brief is feedback-born and deduped by feedback_id). Non-goals respected: no change to the status set or funnel routing. Verification: `php artisan test` green (1085 passed, 2 skipped, 0 failed); `./vendor/bin/pint` clean on all changed PHP. UI render path is exercised by full-page GET tests (nav badge markup + legend text). Left live real-data verification to the orchestrator on MAIN per worktree conventions.

    agent · flower-156-worker
  7. participant joined 1d ago
    system · flower-156-worker
  8. dispatched 1d ago

    Dispatch request #104 queued for flower.

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

    ## Goal Make feedback that **needs operator action** visible and easy to find (mirror the Open Questions nav pattern), and make the **feedback status model legible** so the operator knows which items they must act on vs. which the daemons handle autonomously. ## Grounded status model (current — `App\Models\Feedback` + `App\Services\Feedback\FeedbackPromotionService`) **Kinds** (`FeedbackKind`): `bug`, `note`, `idea`, `mcp_issue`. **Statuses** (`Feedback::STATUSES`): `open` (new/untriaged) → `triaged` → `planned` (promoted to a brief or routed to the orchestrator) → resolved: `addressed` | `wontfix` | `duplicate`. **Who acts (the funnel):** - `note` → self-handled → `addressed`. **No operator action.** - `bug` / `mcp_issue` / sentry-sourced → **AUTONOMOUS (Funnel B)** → promoted to a brief (no approval) or routed to the orchestrator (todo + fix-spec) → `planned`. **No operator action.** - `idea` (and feature / changed-functionality signals) → **OPERATOR-GATED (Funnel A)** → promoted to a brief with `needs_operator_approval=true` (draft, non-dispatchable); the operator must approve (`FeedbackPromotionService::approveBrief`) before it can dispatch. **← the only bucket that needs operator action.** So **"needs operator action" = feedback whose promotion produced an operator-gated brief still pending approval** (Funnel A / idea-class). ## Scope 1. **Nav "needs action" count + badge + link** — mirror `BriefQuestion::openCount()` / the Open Questions badge: a single source of truth (e.g. `Feedback::needsOperatorActionCount()` or a `briefs.needs_operator_approval` count) feeding the nav badge, broadcast on change (like `OpenQuestionsChanged`). Clicking → the `/feedback` view filtered to the needs-action set. 2. **/feedback filter** for "needs my action" (the operator-gated pending-approval set), alongside the existing kind/status filters. 3. **Status legend / help on `/feedback`** — a short inline legend explaining each status + which kinds are autonomous vs operator-gated + what the operator is expected to do (approve/reject the gated ones). Directly resolves the "I'm confused which items I act on" ask. ## Decision (defaulted — adjust if desired) "Needs action" is scoped to **operator-gated briefs pending approval** (recommended — it's the only set the funnel actually requires the operator to touch). If you also want `open`/untriaged feedback surfaced (e.g. as a health signal for when the autonomous triage loop is down), add it as a **secondary** count rather than folding it into the primary badge. Defaulting to the former. ## Acceptance - Nav shows a feedback "needs action" badge/count (single source of truth + live update) linking to the filtered `/feedback` view; count = operator-gated briefs pending approval. - `/feedback` has a "needs my action" filter + a status legend explaining the model and who acts. - Tests: the count excludes autonomous/resolved and includes only pending operator-gated; the filter works. `php artisan test` green + `./vendor/bin/pint`. `Brief: #156` trailer. ## Non-goals - Changing the feedback status set or the funnel routing (this brief surfaces + explains the current model; if the review prompts a status-model change, that's a separate brief). ## Provenance Operator note (#156, 2026-07-03) — "surface feedback needing my action, and clarify the status model." Grounded against `Feedback::STATUSES` + `FeedbackPromotionService` funnel by flower-refine 2026-07-03. UI pattern to mirror: the Open Questions badge (`BriefQuestion::openCount` / #109). Related: #154 (open-questions view/badge realignment).

    agent · flower-refine
  14. spec snapshot 1d ago

    Feedback visibility/surfacing items needing operator action Let's do something similar to the Open Questions link + count/badge + filter for Feedback so I know if there are items awaiting my action from the nav menu Also - let's review how and what statuses the Feedback items can fall into and what those mean/what's next for them. I'm kind of confused as to which items I'm supposed to do something with and if I'm supposed to do something what I'm supposed to do.

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

    Feedback visibility/surfacing items needing operator action Let's do something similar to the Open Questions link + count/badge + filter for Feedback so I know if there are items awaiting my action from the nav menu Also - let's review how and what statuses the Feedback items can fall into and what those mean/what's next for them. I'm kind of confused as to which items I'm supposed to do something with and if I'm supposed to do something what I'm supposed to do.

    operator · operator:mike
  18. participant joined 2d 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-156-worker participant · active
  • system:commit-trailer participant · active

trace · graph

Links

  • Commit #4009 execution
  • Scratchpad #378 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.