104 lines
5.8 KiB
Markdown
104 lines
5.8 KiB
Markdown
# Research: Decision-Based Governance Inbox v1
|
|
|
|
**Date**: 2026-04-28
|
|
**Feature**: [spec.md](spec.md)
|
|
|
|
## Decision Summary
|
|
|
|
The repo already contains the underlying governance attention signals. The missing product slice is not another source page or another workflow state, but one bounded decision-first page that composes the existing source seams into a calm workspace starting point.
|
|
|
|
## Key Decisions
|
|
|
|
### 1. Use section-based composition, not a generic task engine
|
|
|
|
- **Decision**: Build the inbox as one read-only Filament page with bounded family sections and preview entries.
|
|
- **Why**: A polymorphic table or persisted inbox-item model would import a second workflow truth before the first read-only operator surface is proven.
|
|
- **Repo truth**: Findings, operations, alerts, and review follow-up already have their own truthful pages and models.
|
|
|
|
### 2. Reuse findings queue semantics directly
|
|
|
|
- **Decision**: The assigned-findings and intake sections should reuse the inclusion and urgency rules already owned by `MyFindingsInbox` and `FindingsIntakeQueue`.
|
|
- **Why**: Those pages already codify open-status filtering, tenant entitlement, urgency ordering, and calm empty states.
|
|
- **Source seams**:
|
|
- `apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php`
|
|
- `apps/platform/app/Filament/Pages/Findings/FindingsIntakeQueue.php`
|
|
|
|
### 3. Use stale or terminal-follow-up operations as the operations-family signal
|
|
|
|
- **Decision**: The operations section should derive from the same stale or follow-up attention rules already exposed on the canonical `Operations` page.
|
|
- **Why**: The repo already has a canonical operations monitoring surface and run-detail route; the inbox should route into it instead of inventing a second operations diagnostic layer.
|
|
- **Source seams**:
|
|
- `apps/platform/app/Filament/Pages/Monitoring/Operations.php`
|
|
- `apps/platform/app/Filament/Pages/Operations/TenantlessOperationRunViewer.php`
|
|
- `apps/platform/app/Support/OperationRunLinks.php`
|
|
|
|
### 4. Keep the alert-family slice narrow: failed alert deliveries, not alert-rule config
|
|
|
|
- **Decision**: The alerts section should surface delivery failures or similar operator-attention alert outcomes, not alert-rule configuration.
|
|
- **Why**: Delivery failure is the actionable alerting gap that belongs in an attention inbox. Alert-rule editing stays a configuration workflow on its existing surfaces.
|
|
- **Source seams**:
|
|
- `apps/platform/app/Filament/Pages/Monitoring/Alerts.php`
|
|
- `apps/platform/app/Filament/Resources/AlertDeliveryResource.php`
|
|
- `apps/platform/app/Models/AlertDelivery.php`
|
|
|
|
### 5. Use triage-review follow-up as the review-family signal
|
|
|
|
- **Decision**: The review section should derive from `TenantTriageReview` states such as `follow_up_needed` and changed-since-review semantics.
|
|
- **Why**: The repo already distinguishes review follow-up from the underlying review artifact; the inbox should reuse that distinction rather than invent a second attention reason model.
|
|
- **Source seams**:
|
|
- `apps/platform/app/Services/PortfolioTriage/TenantTriageReviewService.php`
|
|
- `apps/platform/app/Models/TenantTriageReview.php`
|
|
- `apps/platform/app/Filament/Resources/TenantReviewResource.php`
|
|
|
|
### 6. Preserve navigation continuity through shared context helpers
|
|
|
|
- **Decision**: Every section and preview entry should use existing navigation helpers for back links and canonical destinations.
|
|
- **Why**: The inbox only reduces attention load if it preserves return context instead of opening detached utility flows.
|
|
- **Source seams**:
|
|
- `apps/platform/app/Support/Navigation/CanonicalNavigationContext.php`
|
|
- `apps/platform/app/Support/Navigation/RelatedNavigationResolver.php`
|
|
- `apps/platform/app/Support/OperateHub/OperateHubShell.php`
|
|
|
|
### 7. Keep the inbox read-only in v1
|
|
|
|
- **Decision**: No claim, snooze, acknowledge, assign, or triage mutations are introduced on the inbox page.
|
|
- **Why**: Those mutations already belong to source surfaces and would force the inbox to become a second workflow owner.
|
|
- **Result**: The inbox remains a decision hub, not an execution surface.
|
|
|
|
## Access Model Decision
|
|
|
|
- Workspace membership remains the first gate.
|
|
- The page only needs to exist for actors who can already see at least one family.
|
|
- Rows and counts must stay family-specific:
|
|
- findings sections require `Capabilities::TENANT_FINDINGS_VIEW`
|
|
- review follow-up requires `Capabilities::TENANT_REVIEW_VIEW`
|
|
- alert-family sections require `Capabilities::ALERTS_VIEW`
|
|
- source mutations remain on source pages with their existing capabilities
|
|
- Explicit out-of-scope `tenant_id` inputs return `404`.
|
|
|
|
## Rejected Alternatives
|
|
|
|
### Rejected: persisted inbox-item table
|
|
|
|
- **Reason**: adds durable workflow truth, migration cost, audit burden, and new lifecycle semantics before the read-only composition page is proven.
|
|
|
|
### Rejected: generic cross-domain work-item abstraction
|
|
|
|
- **Reason**: over-generalizes five concrete families into a second vocabulary and invites a platform-level task framework that current-release truth does not require.
|
|
|
|
### Rejected: extend one existing page instead of adding a canonical inbox
|
|
|
|
- **Reason**: no single existing page can truthfully host all five families without becoming the wrong domain owner.
|
|
|
|
## Implications For Implementation
|
|
|
|
- Prefer one bounded `Support/GovernanceInbox/` seam only if page-local composition becomes unreadable.
|
|
- Keep source-family labels close to existing UI copy to avoid a second UX language.
|
|
- Keep empty states honest:
|
|
- tenant-prefilter-hidden attention -> `Clear tenant filter`
|
|
- globally calm -> one neutral workspace return CTA
|
|
- Do not add page-level audit noise for mere page views.
|
|
|
|
## Planning Outcome
|
|
|
|
The smallest viable implementation slice is one new read-only workspace page that reuses existing source-page queries, existing navigation helpers, and existing capability semantics. No new persistence or mutation lane is justified. |