TenantAtlas/specs/327-governance-inbox-decision-first-workbench-productization/repo-truth-map.md
ahmido 1c38a08919 feat: productize governance inbox decision-first workbench (#388)
## Summary
- productize the governance inbox decision-first workbench surface and related section-building logic
- update the panel theme asset and governance inbox Blade view for the new page treatment
- add Governance Inbox feature coverage and a Spec 327 browser smoke test
- add Spec 327 planning artifacts under `specs/327-governance-inbox-decision-first-workbench-productization`

## Testing
- not run as part of this handoff

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #388
2026-05-18 16:20:17 +00:00

100 lines
15 KiB
Markdown

# Spec 327 Repo Truth Map
Status: implemented
Created: 2026-05-18
Purpose: classify each Governance Inbox decision-first workbench element before runtime implementation. This map is based on repository inspection only; implementation must update it before runtime changes if new source gaps appear.
## Classification Legend
- `repo-verified`: exact runtime source exists and was inspected.
- `foundation-real`: backend model/service/policy exists, but exact page binding still needs implementation verification.
- `derived from existing model`: display value can be derived from existing persisted/domain truth.
- `empty state / unavailable`: no safe source/action exists for v1; show explicit unavailable state or omit.
- `deferred future capability`: outside Spec 327 and must not be shown as live runtime truth.
## Required Data Areas
| Data area | Repo source | Preparation finding |
|---|---|---|
| Findings | `Finding`, `FindingResource`, `GovernanceInboxSectionBuilder::assignedFindingsSection()` and `intakeFindingsSection()` | repo-real for subject/title, status, owner/assignee, due, environment, source links, severity/family fields |
| Finding Exceptions / Accepted Risks | `FindingException`, `FindingExceptionDecision`, `FindingExceptionEvidenceReference`, `FindingExceptionsQueue`, `FindingExceptionResource` | repo-real for status, validity, owner, request reason, due/expiry, current decision, evidence refs |
| Governance Inbox current state | `GovernanceInbox`, `governance-inbox.blade.php`, `GovernanceInboxSectionBuilder` | route/page/view/builder exist; current layout is section/queue-first |
| Decision Register / decisions | `DecisionRegister`, `FindingExceptionDecision`, Specs 265/306/307/308 | foundation-real for decision-related links/states; only show if existing source route/action is repo-real and authorized |
| Evidence links | `EvidenceSnapshot`, `EvidenceSnapshotItem`, `FindingExceptionEvidenceReference`, `EvidenceSnapshotPolicy`, `Capabilities::EVIDENCE_VIEW` | foundation-real; exact inbox binding must be verified during implementation |
| OperationRun links | `OperationRun`, `OperationRunLinks`, `RelatedNavigationResolver` | repo-real for stale/terminal follow-up and proof deep links |
| Workspace / Environment filter state | `WorkspaceContext`, `WorkspaceHubEnvironmentFilter`, `WorkspaceHubFilterStateResetter`, `WorkspaceHubRegistry`, filter chip partial | repo-real canonical `environment_id`, clear filter, alias rejection, cross-workspace guard |
| Owners / assignments | `Finding.owner_user_id`, `Finding.assignee_user_id`, `FindingException.owner_user_id`, resource display helpers | repo-real where fields are present; unavailable otherwise |
| Due dates | `Finding.due_at`, `FindingException.review_due_at`, `FindingException.expires_at` | repo-real where fields are present; unavailable otherwise |
| Statuses / priorities / severities | source model status/severity fields and builder ordering | derived; no new persisted status family |
| Alerts | `AlertDelivery`, `AlertDeliveryResource`, `Capabilities::ALERTS_VIEW` | repo-real for failed delivery attention family |
| Reviews / review follow-up | `ManagedEnvironmentTriageReview`, `EnvironmentReview`, `EnvironmentReviewRegisterService`, `CustomerReviewWorkspace` | repo-real for follow-up and review workspace handoff |
## UI Element Map
| UI element | Source model/service/page | Status source | Authorization/capability | Workspace/Environment scope | Evidence/OperationRun/Audit link | Fallback/empty state | Classification |
|---|---|---|---|---|---|---|---|
| Governance Inbox route | `GovernanceInbox` page, slug `governance/inbox` | Filament page registration | workspace membership via `WorkspaceCapabilityResolver::isMember()` | `WorkspaceContext` session; optional `environment_id` | no direct audit found during prep | redirect workspace chooser, 404, or 403 per existing behavior | repo-verified |
| Header title | `governance-inbox.blade.php`, page title | static page copy | page access | workspace-wide or filtered | none | static title | repo-verified |
| Workspace chip | `appliedScope()['workspace_label']` | current `Workspace` name | page access | workspace session | none | omit if unavailable | repo-verified |
| Environment filter chip | `workspace-hub-environment-filter-chip` partial | `WorkspaceHubEnvironmentFilter::fromRequest()` | actor must access environment | `?environment_id={id}` only | none | no chip on clean URL | repo-verified |
| Clear filter action | `pageUrl(['environment_id' => null])`, shared chip | clean URL generated by page/helper | page access | removes canonical filter | none | omit when unfiltered | repo-verified |
| Legacy alias rejection | `WorkspaceHubRegistry`, `WorkspaceHubFilterStateResetter`, navigation tests | forbidden query keys | page/source access | aliases do not set filter | none | workspace-wide view or safe 404 | repo-verified |
| Cross-workspace environment guard | `WorkspaceHubEnvironmentFilter::fromRequest()` | environment scoped by workspace and `canAccessTenant()` | workspace and environment entitlement | current workspace only | none | `NotFoundHttpException` | repo-verified |
| Main decision question | new page/view copy | static stable copy | page access | current scope | none | visible even empty with honest state | empty state / unavailable until implemented |
| Highest-priority/selected item | existing section entries plus builder ordering | entry `urgency_rank`, source model status/due | source-family capabilities | current workspace/filter | source links | no selected item / no visible decisions | derived from existing model |
| Decision title | `Finding` subject, `FindingException` finding label, `OperationRun` problem class, alert title, review family label | existing entry `headline` | source-family capability | current workspace/filter | source route | fallback source identifier | repo-verified |
| Reason | `FindingException.request_reason`, operation problem class, alert error/event, review row state, finding status/reopened/due | source fields and builder summaries | source-family capability | current workspace/filter | source route/proof links | `Reason unavailable` if absent | derived from existing model |
| Impact | source severity/status/validity/problem class/review follow-up | `Finding.severity`, `FindingException.current_validity_state`, `OperationRun::problemClass()`, review state | source-family capability | current workspace/filter | source route/proof links | `Impact unavailable` if no safe mapping | derived from existing model |
| Owner | `Finding.ownerUser`, `Finding.assigneeUser`, `FindingException.owner` | owner/assignee user relationships | source-family capability | environment/workspace scoped | source route | `Owner missing` or `Owner unavailable` | repo-verified |
| Due date | `Finding.due_at`, `FindingException.review_due_at`, `FindingException.expires_at` | model casts and resource relative-time helpers | source-family capability | environment/workspace scoped | source route | `Due date unavailable` | repo-verified |
| Evidence state | `Finding.evidence_jsonb`, `FindingException.evidence_summary`, `FindingExceptionEvidenceReference`, `EvidenceSnapshot` | existing JSON/relations where linked | `Capabilities::EVIDENCE_VIEW` for evidence links | environment/workspace scoped | evidence snapshot/reference links if authorized | `Evidence missing`, `Unavailable`, or omit | foundation-real |
| Evidence path | evidence refs, snapshots, review context, source routes | relation presence and policy checks | `EVIDENCE_VIEW` plus source policies | current workspace/filter | evidence/operation/review links only | unavailable rows | foundation-real |
| Operation proof | `OperationRun`, `OperationRunLinks` | run relation or operation attention entry | existing operation entitlement checks | workspace and environment entitlement | canonical operation links | `Operation proof unavailable` | repo-verified |
| Accepted-risk / exception state | `FindingException.status`, `current_validity_state`, `Finding.status = risk_accepted` | existing constants and validity fields | `FINDING_EXCEPTION_VIEW/MANAGE/APPROVE`, findings view | environment/workspace scoped | current decision/evidence references if authorized | `No exception` or unavailable | repo-verified |
| Decision Register link/action | `DecisionRegister`, `FindingExceptionDecision`, existing decision routes/tests | current decision/link presence | existing decision/finding exception capabilities | workspace hub with optional filter | decision proof/run links where existing | omit / `No active decision record` | foundation-real |
| Primary next action | existing source routes/actions from builder entries | destination URL/action label per family | source route/action authorization | current workspace/filter | source route/proof links | `Next action unavailable` | repo-verified for open-source links; derived for selected action label |
| Assign owner action | `FindingPolicy::assign`, `Capabilities::TENANT_FINDINGS_ASSIGN` | existing capability/policy | tenant/environment capability | source environment | audit on source action if existing | hide/unavailable unless source action exists | foundation-real |
| Create/update exception action | `FindingExceptionPolicy`, `Capabilities::FINDING_EXCEPTION_MANAGE/APPROVE`, existing source surfaces | existing policy and source action | workspace/environment capability | source environment | source audit if action exists | hide/unavailable unless source action exists | foundation-real |
| Open evidence action | `EvidenceSnapshotResource`, `EvidenceSnapshotPolicy` | linked evidence and capability | `EVIDENCE_VIEW` | source environment/workspace | evidence detail route | hide/unavailable | foundation-real |
| Open diagnostics action | `Capabilities::SUPPORT_DIAGNOSTICS_VIEW` if exposed | no current default inbox raw diagnostics | support diagnostics capability | current scope | source diagnostics only if repo-real | collapsed/hidden | empty state / unavailable |
| Summary card: open decisions | current selected/available entries count | builder `total_count` or filtered item count | source-family capabilities | current scope | source links | `0 visible decisions` | repo-verified as visible attention count; label must avoid unsupported claim |
| Summary card: critical/high priority | `Finding.severity`, exception validity/status, operation problem class | model fields | source-family capabilities | current scope | source links | unavailable if no safe cross-family mapping | derived from existing model |
| Summary card: overdue | `Finding.due_at`, `FindingException.review_due_at/expires_at` | datetime fields | source-family capabilities | current scope | source links | `No due dates available` | derived from existing model |
| Summary card: owner missing | finding/exception owner fields | nullable owner/assignee IDs | source-family capabilities | current scope | source links | unavailable for families without owner source | derived from existing model |
| Summary card: evidence missing | evidence refs/summary/snapshot presence | evidence fields/relations | source-family and evidence capabilities | current scope | evidence links | unavailable where not supported | foundation-real |
| Queue/table context | existing sections/entries rendered in Blade | builder sections and entries | source-family capabilities | current scope and family filter | source routes | existing calm empty states | repo-verified |
| Right decision/detail panel | new layout over selected/highest entry | selected entry and source-specific derived fields | source-family capabilities | current scope | source/evidence/operation links | panel shows unavailable states | empty state / unavailable until implemented |
| Diagnostics disclosure | new collapsed section if needed | safe copy only unless authorized diagnostics source exists | `SUPPORT_DIAGNOSTICS_VIEW` if raw detail exists | current scope | source routes only | collapsed/hidden | empty state / unavailable |
| Raw provider payloads | raw Graph/provider payloads | not safe default | support-only future | N/A | N/A | never default-visible | deferred future capability |
| Platform-context tenant copy guard | runtime copy/tests | string assertions | N/A | page copy | N/A | use Workspace/Environment | repo-verified need; implementation test required |
## Required Runtime Element Decisions
| Element | v1 decision |
|---|---|
| New persisted inbox item | deferred future capability; do not build |
| New Decision Register workflow | deferred future capability; do not rebuild |
| AI prioritization | deferred future capability; do not show |
| Owner/due/evidence where absent | explicit unavailable/missing state; do not invent |
| Green success state | allowed only for exact repo-backed proof; otherwise avoid |
| Diagnostics | collapsed/hidden by default and capability-aware if exposed |
| Dangerous/mutating actions | do not add unless spec/plan updated first |
| Legacy query aliases | rejected/neutralized; do not support |
## Implementation Update Rule
If implementation discovers that a planned UI element has no safe source, no authorization path, or would require new persisted truth, the element must become `empty state / unavailable` or `deferred future capability`. Do not create backend foundation inside Spec 327 without updating `spec.md`, `plan.md`, and this map first.
## Implementation Close-Out
Implemented on 2026-05-18 against the existing `/admin/governance/inbox` Filament page.
- The workbench now derives selected/highest-priority state from existing `GovernanceInboxSectionBuilder` entries; no new persisted inbox item, status family, queue, migration, or backend source of truth was added.
- Findings and finding exceptions now expose repo-backed decision labels, reasons, impact, owner/due, evidence, accepted-risk/exception, and primary source-action labels. Unsupported fields render explicit missing or unavailable states.
- Alert delivery failure copy no longer exposes raw provider/error diagnostics in the default inbox entry. Diagnostics remain collapsed and point operators back to authorized source surfaces.
- The page remains workspace-owned with optional canonical `environment_id` filtering. Legacy tenant/environment aliases were not added or supported.
- Primary actions are read-first source navigation links. No destructive, provider-changing, approve/reject, restore, delete, or remediation action was added.
- Browser proof and screenshots live under `specs/327-governance-inbox-decision-first-workbench-productization/artifacts/screenshots/`. The route inventory/design coverage registry were not changed because the route and UI-028 strategic-surface classification are unchanged.
- Follow-up refinement removed the duplicate in-view page heading and moved the first dominant experience to the decision/evidence workbench. Empty workbench state now renders one compact `No governance decisions need attention` decision state instead of primary zero-metric cards.
- Final browser proof keeps the empty state separate and adds a non-empty repo-backed finding fixture that visibly renders the decision title, reason, impact, missing owner, due date, missing evidence, accepted-risk state, and primary next action in the decision workbench plus right-side evidence panel. The required screenshot artifact is `artifacts/screenshots/governance-inbox-decision-workbench.png`.