flower
/
All briefs
complete draft note flower

Briefs: "Pending Approval" sub-nav filter row + live badge/counter (mirror Open 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.

#67 done fresh flower
agent: claude claimed by flower-180 proc #1074
You are being dispatched from flower Brief #180: Briefs: "Pending Approval" sub-nav filter row + live badge/counter (mirror Open Questions)

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

Target:
- project: flower (/Users/mikeferrara/Documents/code/flower)
- branch: choose an appropriate branch
- worktree: not specified
- kind: fresh

Current brief spec:
## Objective
Add a "Pending Approval" sub-nav filter row under Briefs in the left nav, with a live counter/badge — mirroring the existing "Open Questions" sub-nav + badge — so operator-gated briefs awaiting approval are surfaced at a glance and one click away. Operator-requested (2026-07-04). Sibling to approved brief #178 (same for Decisions); same Open Questions precedent.

## Context / why
Ops routes ideas → operator-gated briefs (`needs_operator_approval=true`), which accumulate on /briefs with no at-a-glance signal (e.g. #167, #179; #178 now approved). The operator has to hunt for them. A nav sub-link + counter (like Open Questions) makes the pending-approval queue visible + one click to filter.

## Precedent to mirror (already in the codebase — copy this pattern)
- **Nav sub-link + badge:** `resources/views/components/layouts/app.blade.php` (~L89-97): the "Open Questions" `nav-sublink` under Briefs → `route('briefs.index', ['questions' => 'open'])`, `aria-current` when active (`$onOpenQuestions = routeIs('briefs.index') && query('questions')==='open'`), and a live badge `<span data-open-questions-badge>` (server-rendered count then live-updated; Brief #109).
- **List filter already exists:** `app/Livewire/Briefs/Index.php` L428 — `$approvalOnly` → `->when($this->approvalOnly, fn($q) => $q->where('needs_operator_approval', true))`. So the LIST filter is done; this brief adds the NAV entry + badge + query-param deep-link.
- **Pending-approval definition:** `Brief.needs_operator_approval === true` (boolean cast, Brief.php:24); a brief is dispatchable only when `Planned && !needs_operator_approval` (Index.php:500). Exclude terminal statuses (cancelled/abandoned/complete) from the count.

## Scope
1. **Nav sub-link:** add a "Pending Approval" `nav-sublink` under Briefs in `app.blade.php` → `route('briefs.index', ['approval' => 'only'])`, with active/`aria-current` styling mirroring Open Questions.
2. **Query-param wiring:** make `?approval=only` drive `$approvalOnly` on `Briefs/Index` on mount (mirror how `questions=open` sets the open-questions filter) so the sub-link deep-links into the filtered list.
3. **Live badge/counter:** add a `data-pending-approval-badge` span with the server-rendered count `Brief::where('needs_operator_approval', true)->whereNotIn('status', [cancelled, abandoned, complete])->count()`, refreshed live via the SAME mechanism as the open-questions badge (Brief #109 — reuse it, don't reinvent).
4. **(Stretch — consistency with #78):** optionally trigger the site-wide ding/bell when a new pending-approval brief appears. Keep off the critical path if the ding plumbing is broader than this slice.

## Constraints / non-goals
- Reuse the Open Questions badge refresh mechanism (Brief #109); match its markup/refresh path — do not invent a new one.
- Don't change approval semantics — only SURFACE the existing `needs_operator_approval` queue.
- Frontend + thin Livewire wiring; follow the bloom design system in `resources/views/components/ui/*`.

## Definition of done
A "Pending Approval" sub-nav row under Briefs with active styling + a live badge showing the count of `needs_operator_approval` (non-terminal) briefs; clicking it deep-links to the filtered /briefs list; badge updates live like Open Questions; verified against current pending-approval briefs (#167/#179/…).

Recent/key trace events:
[1] participant_joined flower-ops: (no body)
[2] note_added flower-ops: ## Objective
Add a "Pending Approval" sub-nav filter row under Briefs in the left nav, with a live counter/badge — mirroring the existing "Open Questions" sub-nav + badge — so operator-gated briefs awaiting approval are surfaced at a glance and one click away. Operator-requested (2026-07-04). Sibling to approved brief #178 (same for Decisions); same Open Questions precedent.

## Context / why
Ops routes ideas → operator-gated briefs (`needs_operator_approval=true`), which accumulate on /briefs with no at-a-glance signal (e.g. #167, #179; #178 now approved). The operator has to hunt for them. A nav sub-link + counter (like Open Questions) makes the pending-approval queue visible + one click to filter.

## Precedent to mirror (already in the codebase — copy this pattern)
- **Nav sub-link + badge:** `resources/views/components/layouts/app.blade.php` (~L89-97): the "Open Questions" `nav-sublink` under Briefs → `route('briefs.index', ['questions' => 'open'])`, `aria-current` when active (`$onOpenQuestions = routeIs('briefs.index') && query('questions')==='open'`), and a live badge `<span data-open-questions-badge>` (server-rendered count then live-updated; Brief #109).
- **List filter already exists:** `app/Livewire/Briefs/Index.php` L428 — `$approvalOnly` → `->when($this->approvalOnly, fn($q) => $q->where('needs_operator_approval', true))`. So the LIST filter is done; this brief adds the NAV entry + badge + query-param deep-link.
- **Pending-approval definition:** `Brief.needs_operator_approval === true` (boolean cast, Brief.php:24); a brief is dispatchable only when `Planned && !needs_operator_approval` (Index.php:500). Exclude terminal statuses (cancelled/abandoned/complete) from the count.

## Scope
1. **Nav sub-link:** add a "Pending Approval" `nav-sublink` under Briefs in `app.blade.php` → `route('briefs.index', ['approval' => 'only'])`, with active/`aria-current` styling mirroring Open Questions.
2. **Query-param wiring:** make `?approval=only` drive `$approvalOnly` on `Briefs/Index` on mount (mirror how `questions=open` sets the open-questions filter) so the sub-link deep-links into the filtered list.
3. **Live badge/counter:** add a `data-pending-approval-badge` span with the server-rendered count `Brief::where('needs_operator_approval', true)->whereNotIn('status', [cancelled, abandoned, complete])->count()`, refreshed live via the SAME mechanism as the open-questions badge (Brief #109 — reuse it, don't reinvent).
4. **(Stretch — consistency with #78):** optionally trigger the site-wide ding/bell when a new pending-approval brief appears. Keep off the critical path if the ding plumbing is broader than this slice.

## Constraints / non-goals
- Reuse the Open Questions badge refresh mechanism (Brief #109); match its markup/refresh path — do not invent a new one.
- Don't change approval semantics — only SURFACE the existing `needs_operator_approval` queue.
- Frontend + thin Livewire wiring; follow the bloom design system in `resources/views/components/ui/*`.

## Definition of done
A "Pending Approval" sub-nav row under Briefs with active styling + a live badge showing the count of `needs_operator_approval` (non-terminal) briefs; clicking it deep-links to the filtered /briefs list; badge updates live like Open Questions; verified against current pending-approval briefs (#167/#179/…).
[3] plan_proposed flower-ops: ## Objective
Add a "Pending Approval" sub-nav filter row under Briefs in the left nav, with a live counter/badge — mirroring the existing "Open Questions" sub-nav + badge — so operator-gated briefs awaiting approval are surfaced at a glance and one click away. Operator-requested (2026-07-04). Sibling to approved brief #178 (same for Decisions); same Open Questions precedent.

## Context / why
Ops routes ideas → operator-gated briefs (`needs_operator_approval=true`), which accumulate on /briefs with no at-a-glance signal (e.g. #167, #179; #178 now approved). The operator has to hunt for them. A nav sub-link + counter (like Open Questions) makes the pending-approval queue visible + one click to filter.

## Precedent to mirror (already in the codebase — copy this pattern)
- **Nav sub-link + badge:** `resources/views/components/layouts/app.blade.php` (~L89-97): the "Open Questions" `nav-sublink` under Briefs → `route('briefs.index', ['questions' => 'open'])`, `aria-current` when active (`$onOpenQuestions = routeIs('briefs.index') && query('questions')==='open'`), and a live badge `<span data-open-questions-badge>` (server-rendered count then live-updated; Brief #109).
- **List filter already exists:** `app/Livewire/Briefs/Index.php` L428 — `$approvalOnly` → `->when($this->approvalOnly, fn($q) => $q->where('needs_operator_approval', true))`. So the LIST filter is done; this brief adds the NAV entry + badge + query-param deep-link.
- **Pending-approval definition:** `Brief.needs_operator_approval === true` (boolean cast, Brief.php:24); a brief is dispatchable only when `Planned && !needs_operator_approval` (Index.php:500). Exclude terminal statuses (cancelled/abandoned/complete) from the count.

## Scope
1. **Nav sub-link:** add a "Pending Approval" `nav-sublink` under Briefs in `app.blade.php` → `route('briefs.index', ['approval' => 'only'])`, with active/`aria-current` styling mirroring Open Questions.
2. **Query-param wiring:** make `?approval=only` drive `$approvalOnly` on `Briefs/Index` on mount (mirror how `questions=open` sets the open-questions filter) so the sub-link deep-links into the filtered list.
3. **Live badge/counter:** add a `data-pending-approval-badge` span with the server-rendered count `Brief::where('needs_operator_approval', true)->whereNotIn('status', [cancelled, abandoned, complete])->count()`, refreshed live via the SAME mechanism as the open-questions badge (Brief #109 — reuse it, don't reinvent).
4. **(Stretch — consistency with #78):** optionally trigger the site-wide ding/bell when a new pending-approval brief appears. Keep off the critical path if the ding plumbing is broader than this slice.

## Constraints / non-goals
- Reuse the Open Questions badge refresh mechanism (Brief #109); match its markup/refresh path — do not invent a new one.
- Don't change approval semantics — only SURFACE the existing `needs_operator_approval` queue.
- Frontend + thin Livewire wiring; follow the bloom design system in `resources/views/components/ui/*`.

## Definition of done
A "Pending Approval" sub-nav row under Briefs with active styling + a live badge showing the count of `needs_operator_approval` (non-terminal) briefs; clicking it deep-links to the filtered /briefs list; badge updates live like Open Questions; verified against current pending-approval briefs (#167/#179/…).
[4] status_change flower-ops: (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: #180` 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/180-pending-approval-subnav → master (merge commit from --no-ff) from MAIN. app.blade.php auto-merged cleanly with #174's top-nav badge — verified BOTH the ingest-health-badge and the pending-approval nav sublink+badge coexist. No new migration. Verified: full suite green (860 tests / 859 passed / 1 skip / 5582 assertions); pint clean; npm run build succeeded (app.js pending-approval subscribe/badge JS now in public/build/app-*.js). PendingApprovalChanged implements ShouldBroadcast (queued) + FeedbackPromotionService dispatch changed → issued graceful `php artisan horizon:terminate` to reload Horizon with the new event/broadcast code. Worker proc 1074 (wt1) closing.

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

    Dispatch request #67 marked done.

    agent · flower-180
  6. note added 1d ago

    Landed on branch `flower/180-pending-approval-subnav` (commit 6cc034e), committed + ready for orchestrator review/merge from MAIN. Mirrors the Open Questions sub-nav/badge precedent (Brief #109) closely. **What landed** - `Brief::pendingApprovalCount()` — single source of truth: `needs_operator_approval=true`, excluding terminal statuses (complete/cancelled/abandoned). Mirrors `Decision::openCount()`. - `app.blade.php` nav: new "Pending Approval" `nav-sublink` under Briefs → `route('briefs.index', ['approval'=>'only'])` with `aria-current` like Open Questions, plus a `data-pending-approval-badge` span (server-rendered count, `hidden` at 0). Parent Briefs link's active guard now also excludes `$onApproval`. - `Briefs/Index::mount()` coerces `?approval=only` → `$approvalOnly=true` (the `$approvalOnly` list filter + "pending approval" chip already existed at Index.php:428/blade). Deep-link now filters the list. - New `PendingApprovalChanged` event + `pending-approval` private channel (routes/channels.php), mirroring `OpenQuestionsChanged`. Dispatched after-commit in `FeedbackPromotionService`: `created:true` when a new gated brief joins the queue (feedback promotion), `created:false` when `approveBrief` clears the gate (guarded so a no-op re-approve doesn't broadcast). - `app.js`: `subscribePendingApproval()` + `updatePendingApprovalBadge()` mirror the open-questions pair; badge updates live, and the stretch site-wide ding fires on `created:true` (reuses the existing mute-aware chime). **Verification**: new `PendingApprovalBadgeTest` (7 tests) covers the count helper (excludes terminal + ungated), both broadcast edges + no-op re-approve, badge shown/hidden markup, and the `?approval=only` filter. Full suite green (844 passed / 1 pre-existing skip), pint clean. No daemons started; MAIN untouched. **Scope note**: intentionally did NOT rebroadcast from `BriefService::setStatus` when a gated brief goes terminal — the Open Questions precedent likewise doesn't rebroadcast on that edge (badge self-corrects on next full page load), so this keeps faithful parity. The stretch ding is included since it reused existing plumbing (not broader than this slice).

    agent · flower-180
  7. link added 1d ago
    agent · flower-180
  8. link added 1d ago
    agent · flower-180
  9. link added 1d ago
    agent · flower-180
  10. status change 1d ago
    agent · flower-180
  11. link added 1d ago
    agent · flower-180
  12. link added 1d ago
    agent · flower-180
  13. dispatched 1d ago

    Dispatch request #67 claimed and spawned as process #1074.

    agent · flower-180
  14. participant joined 1d ago
    system · flower-180
  15. dispatched 1d ago

    Dispatch request #67 queued for flower.

    agent · flower-orchestrator
  16. status change 1d ago
    agent · flower-orchestrator
  17. participant joined 1d ago
    system · flower-orchestrator
  18. status change 1d ago
    agent · flower-ops
  19. plan proposed 1d ago

    ## Objective Add a "Pending Approval" sub-nav filter row under Briefs in the left nav, with a live counter/badge — mirroring the existing "Open Questions" sub-nav + badge — so operator-gated briefs awaiting approval are surfaced at a glance and one click away. Operator-requested (2026-07-04). Sibling to approved brief #178 (same for Decisions); same Open Questions precedent. ## Context / why Ops routes ideas → operator-gated briefs (`needs_operator_approval=true`), which accumulate on /briefs with no at-a-glance signal (e.g. #167, #179; #178 now approved). The operator has to hunt for them. A nav sub-link + counter (like Open Questions) makes the pending-approval queue visible + one click to filter. ## Precedent to mirror (already in the codebase — copy this pattern) - **Nav sub-link + badge:** `resources/views/components/layouts/app.blade.php` (~L89-97): the "Open Questions" `nav-sublink` under Briefs → `route('briefs.index', ['questions' => 'open'])`, `aria-current` when active (`$onOpenQuestions = routeIs('briefs.index') && query('questions')==='open'`), and a live badge `<span data-open-questions-badge>` (server-rendered count then live-updated; Brief #109). - **List filter already exists:** `app/Livewire/Briefs/Index.php` L428 — `$approvalOnly` → `->when($this->approvalOnly, fn($q) => $q->where('needs_operator_approval', true))`. So the LIST filter is done; this brief adds the NAV entry + badge + query-param deep-link. - **Pending-approval definition:** `Brief.needs_operator_approval === true` (boolean cast, Brief.php:24); a brief is dispatchable only when `Planned && !needs_operator_approval` (Index.php:500). Exclude terminal statuses (cancelled/abandoned/complete) from the count. ## Scope 1. **Nav sub-link:** add a "Pending Approval" `nav-sublink` under Briefs in `app.blade.php` → `route('briefs.index', ['approval' => 'only'])`, with active/`aria-current` styling mirroring Open Questions. 2. **Query-param wiring:** make `?approval=only` drive `$approvalOnly` on `Briefs/Index` on mount (mirror how `questions=open` sets the open-questions filter) so the sub-link deep-links into the filtered list. 3. **Live badge/counter:** add a `data-pending-approval-badge` span with the server-rendered count `Brief::where('needs_operator_approval', true)->whereNotIn('status', [cancelled, abandoned, complete])->count()`, refreshed live via the SAME mechanism as the open-questions badge (Brief #109 — reuse it, don't reinvent). 4. **(Stretch — consistency with #78):** optionally trigger the site-wide ding/bell when a new pending-approval brief appears. Keep off the critical path if the ding plumbing is broader than this slice. ## Constraints / non-goals - Reuse the Open Questions badge refresh mechanism (Brief #109); match its markup/refresh path — do not invent a new one. - Don't change approval semantics — only SURFACE the existing `needs_operator_approval` queue. - Frontend + thin Livewire wiring; follow the bloom design system in `resources/views/components/ui/*`. ## Definition of done A "Pending Approval" sub-nav row under Briefs with active styling + a live badge showing the count of `needs_operator_approval` (non-terminal) briefs; clicking it deep-links to the filtered /briefs list; badge updates live like Open Questions; verified against current pending-approval briefs (#167/#179/…).

    agent · flower-ops
  20. note added 1d ago

    ## Objective Add a "Pending Approval" sub-nav filter row under Briefs in the left nav, with a live counter/badge — mirroring the existing "Open Questions" sub-nav + badge — so operator-gated briefs awaiting approval are surfaced at a glance and one click away. Operator-requested (2026-07-04). Sibling to approved brief #178 (same for Decisions); same Open Questions precedent. ## Context / why Ops routes ideas → operator-gated briefs (`needs_operator_approval=true`), which accumulate on /briefs with no at-a-glance signal (e.g. #167, #179; #178 now approved). The operator has to hunt for them. A nav sub-link + counter (like Open Questions) makes the pending-approval queue visible + one click to filter. ## Precedent to mirror (already in the codebase — copy this pattern) - **Nav sub-link + badge:** `resources/views/components/layouts/app.blade.php` (~L89-97): the "Open Questions" `nav-sublink` under Briefs → `route('briefs.index', ['questions' => 'open'])`, `aria-current` when active (`$onOpenQuestions = routeIs('briefs.index') && query('questions')==='open'`), and a live badge `<span data-open-questions-badge>` (server-rendered count then live-updated; Brief #109). - **List filter already exists:** `app/Livewire/Briefs/Index.php` L428 — `$approvalOnly` → `->when($this->approvalOnly, fn($q) => $q->where('needs_operator_approval', true))`. So the LIST filter is done; this brief adds the NAV entry + badge + query-param deep-link. - **Pending-approval definition:** `Brief.needs_operator_approval === true` (boolean cast, Brief.php:24); a brief is dispatchable only when `Planned && !needs_operator_approval` (Index.php:500). Exclude terminal statuses (cancelled/abandoned/complete) from the count. ## Scope 1. **Nav sub-link:** add a "Pending Approval" `nav-sublink` under Briefs in `app.blade.php` → `route('briefs.index', ['approval' => 'only'])`, with active/`aria-current` styling mirroring Open Questions. 2. **Query-param wiring:** make `?approval=only` drive `$approvalOnly` on `Briefs/Index` on mount (mirror how `questions=open` sets the open-questions filter) so the sub-link deep-links into the filtered list. 3. **Live badge/counter:** add a `data-pending-approval-badge` span with the server-rendered count `Brief::where('needs_operator_approval', true)->whereNotIn('status', [cancelled, abandoned, complete])->count()`, refreshed live via the SAME mechanism as the open-questions badge (Brief #109 — reuse it, don't reinvent). 4. **(Stretch — consistency with #78):** optionally trigger the site-wide ding/bell when a new pending-approval brief appears. Keep off the critical path if the ding plumbing is broader than this slice. ## Constraints / non-goals - Reuse the Open Questions badge refresh mechanism (Brief #109); match its markup/refresh path — do not invent a new one. - Don't change approval semantics — only SURFACE the existing `needs_operator_approval` queue. - Frontend + thin Livewire wiring; follow the bloom design system in `resources/views/components/ui/*`. ## Definition of done A "Pending Approval" sub-nav row under Briefs with active styling + a live badge showing the count of `needs_operator_approval` (non-terminal) briefs; clicking it deep-links to the filtered /briefs list; badge updates live like Open Questions; verified against current pending-approval briefs (#167/#179/…).

    agent · flower-ops
  21. participant joined 1d ago
    system · flower-ops

epic · dependencies

Relationships

epic parent

depends on

No dependencies — dispatchable once planned.

agents · waves

Participants

  • flower-ops participant · active
  • flower-orchestrator participant · active
  • flower-180 participant · active
  • system:commit-trailer participant · active

trace · graph

Links

  • Commit #1991 execution
  • Session #3457 execution
  • Session #3455 execution
  • Session #3451 execution
  • Session #3456 execution
  • dispatch_request #67 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.