191-baseline-compare-operator-mode #223
@ -0,0 +1,13 @@
|
|||||||
|
# Requirements Checklist: Baseline Compare Matrix: High-Density Operator Mode
|
||||||
|
|
||||||
|
- [x] Spec candidate check is complete and scores the candidate before approval.
|
||||||
|
- [x] The spec is explicitly scoped as a follow-up to the existing workspace matrix rather than a new domain truth.
|
||||||
|
- [x] Multi-tenant dense mode is defined as the primary operator-density gain.
|
||||||
|
- [x] Single-tenant compact mode is defined as a separate adaptive presentation path.
|
||||||
|
- [x] Filters, legends, actions, and refresh surfaces are explicitly compressed as supporting context.
|
||||||
|
- [x] Visible-set-only semantics and existing RBAC rules are preserved.
|
||||||
|
- [x] No new persisted artifact, state family, or generalized UI framework is introduced.
|
||||||
|
- [x] Manual presentation override is local to the route and not stored as domain truth.
|
||||||
|
- [x] Functional requirements include mode selection, action calming, filter workflow, and last-updated visibility.
|
||||||
|
- [x] Definition of done is testable and aligned with operator scanability rather than generic visual polish.
|
||||||
|
- [x] Tasks are grouped by user story and include focused verification work.
|
||||||
160
specs/191-baseline-compare-operator-mode/plan.md
Normal file
160
specs/191-baseline-compare-operator-mode/plan.md
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
# Implementation Plan: Baseline Compare Matrix: High-Density Operator Mode
|
||||||
|
|
||||||
|
**Branch**: `191-baseline-compare-operator-mode` | **Date**: 2026-04-11 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/191-baseline-compare-operator-mode/spec.md`
|
||||||
|
**Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/191-baseline-compare-operator-mode/spec.md`
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Rework the existing baseline compare matrix route into an operator-density follow-up to Spec 190. The route stays workspace-scoped and fully derived, but gains adaptive presentation rules: dense multi-tenant scanning when several visible tenants are present, compact single-tenant comparison when only one visible tenant remains, and calmer filter, legend, action, and refresh surfaces.
|
||||||
|
|
||||||
|
## Technical Context
|
||||||
|
|
||||||
|
**Language/Version**: PHP 8.4.15
|
||||||
|
**Primary Dependencies**: Laravel 12, Filament v5, Livewire v4, Pest v4, existing `BaselineCompareMatrixBuilder`, `BadgeCatalog`, `CanonicalNavigationContext`, and `UiEnforcement` patterns
|
||||||
|
**Storage**: Existing PostgreSQL truth only; no new tables or artifacts
|
||||||
|
**Testing**: Pest feature tests and one browser smoke path through Sail
|
||||||
|
**Target Platform**: Laravel monolith web application under `apps/platform`
|
||||||
|
**Project Type**: web application
|
||||||
|
**Performance Goals**: Improve operator scan throughput without adding more data queries than Spec 190; keep heavy filter changes explicit rather than chatty
|
||||||
|
**Constraints**: No compare-logic changes, no new persistence, no hidden-tenant leakage, no generalized UI framework, no Filament provider changes
|
||||||
|
**Scale/Scope**: One existing matrix page, one existing view, one existing builder, and focused test coverage updates
|
||||||
|
|
||||||
|
## Constitution Check
|
||||||
|
|
||||||
|
*GATE: Passed before design. No new source-of-truth or persistence changes are expected.*
|
||||||
|
|
||||||
|
| Principle | Status | Notes |
|
||||||
|
|-----------|--------|-------|
|
||||||
|
| Inventory-first / snapshots-second | PASS | The feature changes presentation only and keeps Spec 190 truth sources intact. |
|
||||||
|
| Read/write separation | PASS | `Compare assigned tenants` remains the only mutation and already exists. |
|
||||||
|
| Workspace + tenant isolation | PASS | Visible-set-only behavior remains unchanged. |
|
||||||
|
| RBAC-UX | PASS | Existing `404` vs `403` semantics stay intact; only presentation changes. |
|
||||||
|
| Ops-UX 3-surface feedback | PASS | Refresh and polling surfaces are clarified visually without changing run semantics. |
|
||||||
|
| Proportionality / anti-bloat | PASS | No new persistence, enum, framework, or cross-domain abstraction is introduced. |
|
||||||
|
| UI semantics / few layers | PASS | Dense and compact modes reuse existing badge and compare semantics rather than inventing new status taxonomies. |
|
||||||
|
| Filament v5 / Livewire v4 compliance | PASS | Work remains on the existing Filament page and Livewire-backed route. |
|
||||||
|
| Provider registration location | PASS | No provider changes; registration remains in `bootstrap/providers.php`. |
|
||||||
|
| Global search hard rule | PASS | No new global-searchable resource or page is introduced. |
|
||||||
|
| Destructive action safety | PASS | No destructive action is added by this spec. |
|
||||||
|
| Asset strategy | PASS | No new panel assets or shared assets are required. Existing deployment use of `filament:assets` remains unchanged. |
|
||||||
|
|
||||||
|
## Filament-Specific Compliance Notes
|
||||||
|
|
||||||
|
- **Livewire v4.0+ compliance**: This plan stays on the existing Filament v5 + Livewire v4 page stack and does not introduce legacy APIs.
|
||||||
|
- **Provider registration location**: No panel/provider work is needed. Laravel 11+ provider registration remains in `bootstrap/providers.php`.
|
||||||
|
- **Global search**: This spec does not add a new globally searchable resource. Existing baseline-resource search behavior is unchanged.
|
||||||
|
- **Destructive actions**: No new destructive action is introduced. Existing compare-start actions remain confirmation-gated where already defined.
|
||||||
|
- **Asset strategy**: No new global or on-demand asset registration is planned. Deployment handling of `cd apps/platform && php artisan filament:assets` remains unchanged.
|
||||||
|
- **Testing plan**: Extend the existing matrix feature and browser suites to cover presentation mode, density, compact controls, and non-blocking status surfaces.
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
```text
|
||||||
|
specs/191-baseline-compare-operator-mode/
|
||||||
|
├── spec.md
|
||||||
|
├── plan.md
|
||||||
|
├── tasks.md
|
||||||
|
└── checklists/
|
||||||
|
└── requirements.md
|
||||||
|
```
|
||||||
|
|
||||||
|
### Source Code
|
||||||
|
|
||||||
|
```text
|
||||||
|
apps/platform/
|
||||||
|
├── app/
|
||||||
|
│ ├── Filament/
|
||||||
|
│ │ └── Pages/
|
||||||
|
│ │ └── BaselineCompareMatrix.php
|
||||||
|
│ └── Support/
|
||||||
|
│ └── Baselines/
|
||||||
|
│ └── BaselineCompareMatrixBuilder.php
|
||||||
|
├── resources/views/filament/pages/
|
||||||
|
│ └── baseline-compare-matrix.blade.php
|
||||||
|
└── tests/
|
||||||
|
├── Browser/
|
||||||
|
│ └── Spec190BaselineCompareMatrixSmokeTest.php
|
||||||
|
├── Feature/
|
||||||
|
│ ├── Filament/
|
||||||
|
│ │ └── BaselineCompareMatrixPageTest.php
|
||||||
|
│ └── Guards/
|
||||||
|
│ └── ActionSurfaceContractTest.php
|
||||||
|
└── Feature/Baselines/
|
||||||
|
└── BaselineCompareMatrixBuilderTest.php
|
||||||
|
```
|
||||||
|
|
||||||
|
**Structure Decision**: Keep the work inside the existing Spec 190 implementation surface. This follow-up spec is a refactor of one page and its supporting builder/view behavior, not a new domain slice.
|
||||||
|
|
||||||
|
## Key Design Decisions
|
||||||
|
|
||||||
|
### D-001 — Keep the route and truth model unchanged
|
||||||
|
|
||||||
|
This spec modifies the existing `/compare-matrix` route only. No second route, second matrix artifact, or separate dense-report model is created.
|
||||||
|
|
||||||
|
### D-002 — Use adaptive presentation, not separate features
|
||||||
|
|
||||||
|
`auto` mode is the canonical default. `dense` and `compact` exist as local operator overrides, but the product concept remains one matrix page with adaptive presentation.
|
||||||
|
|
||||||
|
### D-003 — Keep dense cells state-first
|
||||||
|
|
||||||
|
Dense mode cells must prioritize compare state, trust, freshness, and attention. Detailed reasons and multiple navigation targets become secondary reveals rather than permanent default chrome.
|
||||||
|
|
||||||
|
### D-004 — Treat controls as supporting context
|
||||||
|
|
||||||
|
Filters, legends, and refresh hints remain available but must become visibly subordinate to the matrix body. The page should read as a working surface, not a form-first screen.
|
||||||
|
|
||||||
|
### D-005 — Keep single-tenant mode honest
|
||||||
|
|
||||||
|
If only one visible tenant remains, the operator should see a compact comparison surface rather than an artificially wide matrix. The page should not preserve multi-tenant structure when it no longer helps.
|
||||||
|
|
||||||
|
## Implementation Strategy
|
||||||
|
|
||||||
|
### Phase A — Presentation Mode Contract
|
||||||
|
|
||||||
|
- Add `auto`, `dense`, and `compact` mode state to the page.
|
||||||
|
- Keep override state local to the route and compatible with existing drilldown URLs.
|
||||||
|
- Reuse the current derived matrix bundle instead of adding a second persisted view model.
|
||||||
|
|
||||||
|
### Phase B — Dense Multi-Tenant Surface
|
||||||
|
|
||||||
|
- Reduce per-cell chrome and prioritize state/trust/freshness.
|
||||||
|
- Keep the subject axis sticky and readable across horizontal scroll.
|
||||||
|
- Move repeated actions into compact secondary affordances where necessary.
|
||||||
|
|
||||||
|
### Phase C — Compact Single-Tenant Surface
|
||||||
|
|
||||||
|
- Replace pseudo-matrix presentation with a shorter, calmer list optimized for one visible tenant.
|
||||||
|
- Remove repeated tenant headers and duplicated labels.
|
||||||
|
- Preserve subject focus and drilldowns.
|
||||||
|
|
||||||
|
### Phase D — Supporting Context Compression
|
||||||
|
|
||||||
|
- Convert heavy filters to an apply/reset workflow.
|
||||||
|
- Compress legends into grouped or collapsible supporting blocks.
|
||||||
|
- Clarify background polling, manual refresh, and last-updated status without using blocking loading surfaces.
|
||||||
|
|
||||||
|
### Phase E — Verification
|
||||||
|
|
||||||
|
- Extend feature coverage for mode selection and density rules.
|
||||||
|
- Extend browser coverage for one dense-mode path and one compact-mode path.
|
||||||
|
- Keep existing Spec 190 truth and RBAC guarantees intact.
|
||||||
|
|
||||||
|
## Risks & Mitigations
|
||||||
|
|
||||||
|
| Risk | Impact | Likelihood | Mitigation |
|
||||||
|
|------|--------|------------|------------|
|
||||||
|
| Dense mode becomes another framework | Medium | Low | Keep presentation logic local to the matrix page and view. |
|
||||||
|
| Compact mode hides too much drilldown value | Medium | Medium | Keep one clear follow-up path per subject and preserve existing drilldowns. |
|
||||||
|
| Apply/reset feels stale compared with live filters | Medium | Medium | Make staged filter state obvious and keep reset immediate. |
|
||||||
|
| Manual override confuses operators | Low | Medium | Keep `auto` as default and label override state clearly. |
|
||||||
|
|
||||||
|
## Test Strategy
|
||||||
|
|
||||||
|
- Extend feature tests for mode resolution based on visible tenant count.
|
||||||
|
- Add assertions for dense multi-tenant sticky subject behavior and reduced visible action noise.
|
||||||
|
- Add assertions for compact single-tenant rendering and shorter supporting chrome.
|
||||||
|
- Add coverage for explicit filter apply/reset behavior, grouped legends, and page-level last-updated messaging.
|
||||||
|
- Reuse existing browser smoke coverage and extend it for one dense path plus one compact-mode path.
|
||||||
|
- Run `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` and the focused matrix-related Pest suite before sign-off.
|
||||||
214
specs/191-baseline-compare-operator-mode/spec.md
Normal file
214
specs/191-baseline-compare-operator-mode/spec.md
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
# Feature Specification: Baseline Compare Matrix: High-Density Operator Mode
|
||||||
|
|
||||||
|
**Feature Branch**: `191-baseline-compare-operator-mode`
|
||||||
|
**Created**: 2026-04-11
|
||||||
|
**Status**: Draft
|
||||||
|
**Input**: User description: "Spec Candidate 190b — Baseline Compare Matrix: High-Density Operator Mode"
|
||||||
|
|
||||||
|
## Spec Candidate Check *(mandatory — SPEC-GATE-001)*
|
||||||
|
|
||||||
|
- **Problem**: The current baseline compare matrix is semantically strong but still too visually heavy for repeat operator use, especially when several visible tenants must be scanned quickly.
|
||||||
|
- **Today's failure**: Operators reach the right truth, but the page spends too much space on supporting context, repeated actions, and vertically expensive cells. Multi-tenant comparison is slower than it should be, and single-tenant viewing still feels like a stretched matrix instead of a compact operator surface.
|
||||||
|
- **User-visible improvement**: The same matrix route becomes faster to scan, calmer to use, and more obviously centered on drift detection. Multi-tenant work gets a true dense scan mode, while single-tenant work gets a compact compare list.
|
||||||
|
- **Smallest enterprise-capable version**: Rework the existing matrix route with adaptive presentation only: `auto` mode picks dense multi-tenant view for more than one visible tenant and compact single-tenant view for one visible tenant, while filters, legends, actions, and refresh feedback are compressed without changing compare logic.
|
||||||
|
- **Explicit non-goals**: No change to compare truth, no new finding semantics, no new persisted matrix artifact, no generalized table engine, no mobile-first redesign, no broader design-system rewrite.
|
||||||
|
- **Permanent complexity imported**: One page-level presentation-mode contract, denser cell-layout rules, compact control behavior, route/query persistence for local mode override, and focused regression coverage for the new operator surface behavior.
|
||||||
|
- **Why now**: Spec 190 established the truthful workspace compare surface. The next real bottleneck is not domain correctness but operator throughput and scan efficiency on the page that now exists.
|
||||||
|
- **Why not local**: Small CSS-only tweaks will not solve the actual product problem because the core issue is presentation mode, action hierarchy, and default information density rather than isolated spacing bugs.
|
||||||
|
- **Approval class**: Workflow Compression
|
||||||
|
- **Red flags triggered**: `New Meta-Infrastructure` risk if presentation-mode work grows into a reusable UI framework. Defense: this spec keeps all mode logic page-local to the existing baseline compare matrix and forbids a generalized density framework.
|
||||||
|
- **Score**: Nutzen: 2 | Dringlichkeit: 1 | Scope: 2 | Komplexität: 2 | Produktnähe: 2 | Wiederverwendung: 1 | **Gesamt: 10/12**
|
||||||
|
- **Decision**: approve
|
||||||
|
|
||||||
|
## Spec Scope Fields *(mandatory)*
|
||||||
|
|
||||||
|
- **Scope**: workspace
|
||||||
|
- **Primary Routes**:
|
||||||
|
- `/admin/baseline-profiles/{record}/compare-matrix` as the existing workspace matrix route that gains dense and compact operator modes
|
||||||
|
- `/admin/baseline-profiles/{record}` as the existing baseline profile detail that remains the canonical entry point into the matrix
|
||||||
|
- `/admin/t/{tenant}/baseline-compare` as the existing tenant drilldown destination
|
||||||
|
- `/admin/findings` and finding detail as the existing follow-up destinations
|
||||||
|
- Monitoring run-detail routes as existing compare-run drilldowns
|
||||||
|
- **Data Ownership**:
|
||||||
|
- Workspace-owned baseline profile, snapshot, and assignment truth remain unchanged.
|
||||||
|
- Tenant-owned compare runs and findings remain unchanged.
|
||||||
|
- Presentation mode, filter compaction, and dense cell rendering remain derived UI behavior only and introduce no new persisted truth.
|
||||||
|
- **RBAC**:
|
||||||
|
- Matrix access remains gated by workspace membership plus `WORKSPACE_BASELINES_VIEW`.
|
||||||
|
- `Compare assigned tenants` remains gated by `WORKSPACE_BASELINES_MANAGE`.
|
||||||
|
- Tenant and finding drilldowns continue to enforce their existing tenant-scope capabilities such as `TENANT_VIEW` and `TENANT_FINDINGS_VIEW`.
|
||||||
|
- Presentation-mode changes MUST NOT widen visibility, leak hidden tenants, or relax `404` vs `403` semantics already established in Spec 190.
|
||||||
|
|
||||||
|
## UI/UX Surface Classification *(mandatory when operator-facing surfaces are changed)*
|
||||||
|
|
||||||
|
| Surface | Surface Type | Primary Inspect/Open Model | Row Click | Secondary Actions Placement | Destructive Actions Placement | Canonical Collection Route | Canonical Detail Route | Scope Signals | Canonical Noun | Critical Truth Visible by Default | Exception Type |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| Workspace baseline compare matrix | Workspace matrix / operator surface | Explicit subject, cell, and tenant drilldown controls | forbidden | Header controls, compact cell action slot, focused subject utilities | none | `/admin/baseline-profiles/{record}/compare-matrix` | same route with filter and presentation state | Active workspace, baseline profile, visible tenant count, active filter count, presentation mode, last updated | Baseline compare matrix | Drift hotspots, trust, freshness, and next follow-up path | dense-grid + compact-single-tenant exception |
|
||||||
|
|
||||||
|
## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)*
|
||||||
|
|
||||||
|
| Surface | Primary Persona | Surface Type | Primary Operator Question | Default-visible Information | Diagnostics-only Information | Status Dimensions Used | Mutation Scope | Primary Actions | Dangerous Actions |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| Workspace baseline compare matrix | Workspace operator | Matrix / triage surface | Where is the meaningful drift across the visible tenant set, how trustworthy is it, and where should I go next? | Subject-by-tenant state, trust, freshness, severity or attention signal, visible-set filter scope, mode, last updated | Raw reason codes, run identifiers, detailed evidence gaps, low-level compare metadata | compare state, freshness, trust, severity/attention | `simulation only` for compare start; otherwise read-only | Compare assigned tenants, apply or reset filters, switch presentation mode, focus subject, drill into compare/finding/run | none |
|
||||||
|
|
||||||
|
## Proportionality Review *(mandatory when structural complexity is introduced)*
|
||||||
|
|
||||||
|
- **New source of truth?**: no
|
||||||
|
- **New persisted entity/table/artifact?**: no
|
||||||
|
- **New abstraction?**: no
|
||||||
|
- **New enum/state/reason family?**: no
|
||||||
|
- **New cross-domain UI framework/taxonomy?**: no
|
||||||
|
- **Current operator problem**: The matrix already answers the right governance question, but not with enough density or calmness for repeated operator scanning.
|
||||||
|
- **Existing structure is insufficient because**: The current single rendering shape tries to serve both multi-tenant and single-tenant use cases, so supporting context, cell chrome, and repeated actions stay too heavy for both.
|
||||||
|
- **Narrowest correct implementation**: Keep the same route, same truth sources, same drilldowns, and same compare semantics while adding one adaptive presentation contract and denser default rendering.
|
||||||
|
- **Ownership cost**: More page-view branching, additional view-state tests, and stricter UI regression coverage for density, action noise, and status visibility.
|
||||||
|
- **Alternative intentionally rejected**: A generalized dense-table framework or a second persisted reporting artifact was rejected because this need is local to the baseline compare matrix.
|
||||||
|
- **Release truth**: current-release operator workflow compression
|
||||||
|
|
||||||
|
## User Scenarios & Testing *(mandatory)*
|
||||||
|
|
||||||
|
### User Story 1 - Scan multi-tenant drift in dense mode (Priority: P1)
|
||||||
|
|
||||||
|
As a workspace operator, I want the matrix to switch into a true high-density view when multiple visible tenants are in scope so I can read drift patterns quickly without losing the subject axis.
|
||||||
|
|
||||||
|
**Why this priority**: Multi-tenant scanning is the core operator value of the matrix. If this remains visually slow, the page does not earn its workspace-level role.
|
||||||
|
|
||||||
|
**Independent Test**: Open the matrix for a baseline profile with multiple visible tenants and verify that one subject row and one tenant column remain readable in a dense layout with a sticky subject column and compact cell states.
|
||||||
|
|
||||||
|
**Acceptance Scenarios**:
|
||||||
|
|
||||||
|
1. **Given** a baseline profile with more than one visible assigned tenant, **When** the operator opens the matrix route in auto mode, **Then** the page renders the dense multi-tenant mode with one subject row per baseline subject and one tenant column per visible tenant.
|
||||||
|
2. **Given** the operator scrolls horizontally in dense mode, **When** the matrix remains wider than the viewport, **Then** the first subject column stays visible and anchored for cross-tenant reading.
|
||||||
|
3. **Given** a dense-mode cell represents a visible tenant and subject, **When** the page renders it, **Then** the primary visible signal is the technical state plus condensed trust and freshness rather than a block of repeated links or prose.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### User Story 2 - Work a single visible tenant in compact mode (Priority: P2)
|
||||||
|
|
||||||
|
As a workspace operator, I want the matrix to stop pretending to be multi-tenant when only one visible tenant remains so the screen becomes shorter and calmer.
|
||||||
|
|
||||||
|
**Why this priority**: A single-tenant compare surface should not spend horizontal and vertical space simulating columns that do not exist.
|
||||||
|
|
||||||
|
**Independent Test**: Open the matrix for a baseline profile where only one tenant is visible and verify that the page uses a compact compare-list mode instead of the dense cross-tenant layout.
|
||||||
|
|
||||||
|
**Acceptance Scenarios**:
|
||||||
|
|
||||||
|
1. **Given** exactly one visible assigned tenant after RBAC scoping, **When** the operator opens the matrix in auto mode, **Then** the page renders compact single-tenant mode instead of dense mode.
|
||||||
|
2. **Given** compact mode is active, **When** the operator scans a subject entry, **Then** repeated labels, repeated badges, and repeated action chrome are reduced compared with the current matrix surface.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### User Story 3 - Use filters, legends, and status surfaces without losing the matrix (Priority: P2)
|
||||||
|
|
||||||
|
As a workspace operator, I want supporting controls to stay available but compact so the matrix remains the primary working surface above the fold.
|
||||||
|
|
||||||
|
**Why this priority**: Filtering, legends, and refresh status are necessary, but they should support the matrix rather than compete with it.
|
||||||
|
|
||||||
|
**Independent Test**: Open the matrix, apply policy-type or state filters, and verify that active filter count, filter application, legend compaction, and refresh signals remain visible without dominating the page.
|
||||||
|
|
||||||
|
**Acceptance Scenarios**:
|
||||||
|
|
||||||
|
1. **Given** the operator changes multi-select filters, **When** those changes are staged, **Then** the page uses an explicit apply or reset pattern for heavy filter changes instead of re-rendering noisily on every click.
|
||||||
|
2. **Given** active compare runs or polling are present, **When** the matrix refreshes in the background, **Then** the operator sees a non-blocking update signal and a page-level freshness hint rather than a permanent loading impression.
|
||||||
|
3. **Given** the operator already understands the legends, **When** the page loads in daily-use mode, **Then** legends are grouped and visually compact, with deeper explanation still available on demand.
|
||||||
|
|
||||||
|
### Edge Cases
|
||||||
|
|
||||||
|
- If total assigned tenants are greater than one but only one tenant is visible to the current actor, auto mode MUST choose compact mode, not dense mode.
|
||||||
|
- If the operator manually overrides `auto` to `dense` or `compact`, the override MUST stay local to the matrix route and MUST NOT create a persisted user preference or domain artifact.
|
||||||
|
- If filters reduce the visible row set to zero, the page MUST preserve the active mode and still show a clear empty state.
|
||||||
|
- If compare runs are queued or running while the page is open, the refresh signal MUST remain distinct from a blocking loading state.
|
||||||
|
- If dense mode cannot fit all compact cell details legibly, secondary detail MUST move behind tooltip, popover, expand, or a deliberate drilldown instead of widening every cell again.
|
||||||
|
|
||||||
|
## Requirements *(mandatory)*
|
||||||
|
|
||||||
|
**Constitution alignment (required):** This follow-up spec changes only the operator presentation of the existing matrix surface. It introduces no new Microsoft Graph path, no new baseline or finding truth, and no new mutation beyond the already-existing compare-start behavior.
|
||||||
|
|
||||||
|
**Constitution alignment (PROP-001 / ABSTR-001 / PERSIST-001 / STATE-001 / BLOAT-001):** The feature must remain a local presentation refactor on top of Spec 190. It MUST NOT introduce a new persisted report, a new compare artifact, a new domain state family, or a reusable density framework.
|
||||||
|
|
||||||
|
**Constitution alignment (OPS-UX):** Any compare-start controls remain bound to the existing `baseline_compare` run semantics from Spec 190. This spec only changes the presentation around those controls and their feedback, not the run model.
|
||||||
|
|
||||||
|
**Constitution alignment (RBAC-UX):** All existing `404` versus `403` semantics, visible-set-only counts, drilldown authorization, and capability checks remain unchanged. Dense or compact mode MUST never reveal more tenant truth than the current actor can already see.
|
||||||
|
|
||||||
|
**Constitution alignment (BADGE-001):** Dense and compact mode MUST reuse centralized state, freshness, trust, and severity badge semantics. This spec MUST NOT create page-local status colors or a second status vocabulary.
|
||||||
|
|
||||||
|
**Constitution alignment (UI-FIL-001):** The matrix page should continue to use Filament-native sections, actions, and shared primitives. The dense matrix body and compact single-tenant layout may use custom Blade composition where Filament's one-axis primitives are insufficient, but the page MUST avoid inventing a local semantic component framework.
|
||||||
|
|
||||||
|
**Constitution alignment (UI-NAMING-001):** Operator-facing labels must stay aligned with the vocabulary established in Spec 190, including `Baseline compare matrix`, `Compare assigned tenants`, `Reference snapshot`, `Visible tenants`, and the existing compare-state labels.
|
||||||
|
|
||||||
|
**Constitution alignment (UI-CONST-001 / UI-SURF-001 / UI-HARD-001 / UI-REVIEW-001):** The matrix remains a workspace operator surface with explicit inspect controls and forbidden row click. The primary working surface is the matrix body, while filters, legends, and status strips become supporting context.
|
||||||
|
|
||||||
|
### Functional Requirements
|
||||||
|
|
||||||
|
- **FR-191-001 Primary working surface**: The matrix body MUST become visually dominant over reference context, filters, legends, and refresh hints.
|
||||||
|
- **FR-191-002 Auto presentation mode**: The page MUST support an `auto` presentation mode that chooses dense multi-tenant mode when more than one visible tenant is in scope and compact single-tenant mode when exactly one visible tenant is in scope.
|
||||||
|
- **FR-191-003 Manual override**: The page MUST allow a local manual override between `auto`, `dense`, and `compact` presentation without persisting that choice as domain truth or a stored user preference.
|
||||||
|
- **FR-191-004 Dense multi-tenant layout**: Dense mode MUST render one subject row and one visible-tenant column with a sticky first subject column.
|
||||||
|
- **FR-191-005 Dense cell contract**: Dense mode cells MUST default to compact state, trust, and freshness signals. Detailed reasons, long helper text, and multiple secondary links MUST NOT dominate the default cell chrome.
|
||||||
|
- **FR-191-006 Single-tenant compact layout**: Compact mode MUST render a shorter subject-result list optimized for one visible tenant instead of a pseudo-matrix with repeated tenant headers and oversized cells.
|
||||||
|
- **FR-191-007 Action calming**: Repeated follow-up actions such as tenant compare, finding, or run links MUST become visually secondary. The default focus in dense or compact mode MUST remain the compare state, not the link chrome.
|
||||||
|
- **FR-191-008 Filter density**: The page MUST show active filter count and active filter scope clearly while keeping the filter zone visually compact.
|
||||||
|
- **FR-191-009 Heavy-filter workflow**: Policy type and other heavy multi-select filters MUST use an explicit apply/reset interaction instead of forcing a full matrix recompute on every click.
|
||||||
|
- **FR-191-010 Policy type usability**: Policy type filtering MUST be faster than the current long checkbox stack, for example by searchability, type-to-find behavior, or another equally compact operator-first selector.
|
||||||
|
- **FR-191-011 Legend compression**: State, freshness, and trust legends MUST remain available but MUST be grouped and visually compressed so they do not displace the matrix in daily use.
|
||||||
|
- **FR-191-012 Honest status transitions**: The page MUST distinguish between active loading, background auto-refresh, and last-updated freshness so operators can tell whether the matrix is recalculating or simply polling for updates.
|
||||||
|
- **FR-191-013 Last updated visibility**: The page MUST show a page-level or matrix-level freshness hint indicating when the currently rendered matrix data was last refreshed.
|
||||||
|
- **FR-191-014 Visible-set truth preserved**: Dense and compact mode MUST preserve the visible-set-only semantics already defined in Spec 190 for all counts, subject breadth, and drilldowns.
|
||||||
|
- **FR-191-015 Drilldown continuity preserved**: Switching presentation mode MUST NOT break subject focus, tenant drilldowns, finding drilldowns, or return-path continuity already established on the matrix route.
|
||||||
|
- **FR-191-016 No compare-logic changes**: This spec MUST NOT change how drift, trust, freshness, severity, or evidence gaps are calculated.
|
||||||
|
- **FR-191-017 No new persistence**: This spec MUST NOT introduce a new matrix snapshot, portfolio report, stored view preference, or any other new persisted artifact.
|
||||||
|
- **FR-191-018 Automated regression coverage**: Automated coverage MUST prove mode selection, sticky dense layout, compact single-tenant layout, filter apply/reset behavior, legend compression, non-blocking refresh state, and preservation of existing drilldowns and RBAC semantics.
|
||||||
|
|
||||||
|
## Non-Goals
|
||||||
|
|
||||||
|
- No change to baseline compare logic or evidence resolution
|
||||||
|
- No new matrix export or stored report artifact
|
||||||
|
- No new generic dense-table framework for other pages
|
||||||
|
- No new finding workflow or remediation workflow
|
||||||
|
- No mobile-first redesign of the matrix surface
|
||||||
|
- No cross-workspace or tenant-vs-tenant compare feature
|
||||||
|
|
||||||
|
## Assumptions
|
||||||
|
|
||||||
|
- Spec 190 remains the canonical domain-truth foundation for the matrix.
|
||||||
|
- Existing builder outputs can be extended or re-rendered without introducing new persistence.
|
||||||
|
- Existing drilldown URLs and canonical navigation context can carry any local presentation override that must survive navigation.
|
||||||
|
- Existing badge semantics already cover the status information needed for denser rendering.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
- Spec 190 baseline compare matrix route and builder
|
||||||
|
- Existing matrix page and view
|
||||||
|
- Existing badge semantics for state, freshness, trust, and severity
|
||||||
|
- Existing tenant compare, finding, and run-detail destinations
|
||||||
|
|
||||||
|
## Risks
|
||||||
|
|
||||||
|
- Dense mode could drift into a local mini-framework if rendering rules become over-generalized.
|
||||||
|
- Compacting actions too aggressively could hide next steps instead of calming them.
|
||||||
|
- Apply/reset filtering could feel slower if the staged-filter state is not clearly signaled.
|
||||||
|
- Manual mode override could create confusion if `auto` behavior and override state are not explicit.
|
||||||
|
|
||||||
|
## Review Questions
|
||||||
|
|
||||||
|
- Does the page now clearly separate supporting context from the primary working surface?
|
||||||
|
- Is dense mode truly optimized for cross-tenant scanning rather than just a tighter version of the old layout?
|
||||||
|
- Is single-tenant mode clearly calmer and shorter than the current matrix?
|
||||||
|
- Are repeated actions secondary without becoming hard to discover?
|
||||||
|
- Are filter count, legend compression, and last-updated feedback visible without dominating the page?
|
||||||
|
- Does the spec stay local to the matrix surface and avoid importing a reusable UI framework?
|
||||||
|
|
||||||
|
## Definition of Done
|
||||||
|
|
||||||
|
This feature is complete when:
|
||||||
|
|
||||||
|
- the existing matrix route supports `auto`, `dense`, and `compact` presentation behavior,
|
||||||
|
- multi-tenant auto mode renders a clearly denser matrix with a sticky subject column,
|
||||||
|
- single-tenant auto mode renders a compact compare-list presentation instead of the current matrix-heavy layout,
|
||||||
|
- supporting context is visibly lighter than the matrix body,
|
||||||
|
- repeated per-cell or per-row actions no longer dominate the reading flow,
|
||||||
|
- active filters are counted and heavy filters use an explicit apply/reset pattern,
|
||||||
|
- legends remain available but are grouped and visually compressed,
|
||||||
|
- page-level refresh and last-updated signals are honest and non-blocking,
|
||||||
|
- no compare logic, trust logic, freshness logic, or RBAC semantics have changed,
|
||||||
|
- and focused feature plus browser coverage proves the new operator-density behavior.
|
||||||
146
specs/191-baseline-compare-operator-mode/tasks.md
Normal file
146
specs/191-baseline-compare-operator-mode/tasks.md
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
# Tasks: Baseline Compare Matrix: High-Density Operator Mode
|
||||||
|
|
||||||
|
**Input**: Design documents from `/specs/191-baseline-compare-operator-mode/`
|
||||||
|
**Prerequisites**: `plan.md`, `spec.md`
|
||||||
|
|
||||||
|
**Tests**: Tests are REQUIRED. Extend Pest feature coverage and browser smoke coverage around the existing matrix route.
|
||||||
|
**Operations**: This feature reuses existing `baseline_compare` run truth only. No new `OperationRun` type, no new run-summary contract, and no new notification channel should be introduced.
|
||||||
|
**RBAC**: Existing workspace and tenant visibility rules from Spec 190 remain authoritative. Tasks must preserve visible-set-only aggregation and existing `404` vs `403` behavior.
|
||||||
|
**Operator Surfaces**: The affected operator surface is the existing workspace baseline compare matrix route, with additive presentation changes only.
|
||||||
|
**Filament UI Action Surfaces**: The matrix page keeps explicit drilldown controls and forbidden row click. No destructive action is added.
|
||||||
|
**Badges**: Dense and compact rendering must continue to use centralized matrix state, trust, freshness, and severity semantics.
|
||||||
|
|
||||||
|
**Organization**: Tasks are grouped by user story so each operator-density improvement can be implemented and verified independently.
|
||||||
|
|
||||||
|
## Phase 1: Setup (Presentation Seams)
|
||||||
|
|
||||||
|
**Purpose**: Prepare focused acceptance seams for adaptive presentation work.
|
||||||
|
|
||||||
|
- [ ] T001 [P] Add presentation-mode acceptance scaffolds in `apps/platform/tests/Feature/Filament/BaselineCompareMatrixPageTest.php` and `apps/platform/tests/Browser/Spec190BaselineCompareMatrixSmokeTest.php`
|
||||||
|
- [ ] T002 [P] Extend surface-contract guard coverage for calmer matrix actions in `apps/platform/tests/Feature/Guards/ActionSurfaceContractTest.php`
|
||||||
|
|
||||||
|
**Checkpoint**: The test suite has clear seams for dense mode, compact mode, and action-noise expectations.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2: Foundational (Blocking Operator-Density Contract)
|
||||||
|
|
||||||
|
**Purpose**: Establish page-level presentation state and derived view metadata before reshaping the UI.
|
||||||
|
|
||||||
|
**⚠️ CRITICAL**: No story work should begin until the presentation contract is stable.
|
||||||
|
|
||||||
|
- [ ] T003 Add `auto`, `dense`, and `compact` presentation state handling plus route persistence in `apps/platform/app/Filament/Pages/BaselineCompareMatrix.php`
|
||||||
|
- [ ] T004 [P] Add derived density metadata for compact cell summaries and compact single-tenant summaries in `apps/platform/app/Support/Baselines/BaselineCompareMatrixBuilder.php`
|
||||||
|
- [ ] T005 [P] Add page-level last-updated and staged-filter metadata in `apps/platform/app/Filament/Pages/BaselineCompareMatrix.php`
|
||||||
|
|
||||||
|
**Checkpoint**: The page can resolve presentation mode and expose the supporting state required for dense and compact rendering.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3: User Story 1 - Scan multi-tenant drift in dense mode (Priority: P1) 🎯 MVP
|
||||||
|
|
||||||
|
**Goal**: Make multi-tenant reading materially denser and faster without changing compare truth.
|
||||||
|
|
||||||
|
**Independent Test**: Open the matrix with multiple visible tenants and verify dense mode, sticky subject behavior, and state-first cells.
|
||||||
|
|
||||||
|
### Tests for User Story 1
|
||||||
|
|
||||||
|
- [ ] T006 [P] [US1] Add dense multi-tenant page coverage in `apps/platform/tests/Feature/Filament/BaselineCompareMatrixPageTest.php`
|
||||||
|
- [ ] T007 [P] [US1] Extend browser smoke coverage for dense-mode scanning in `apps/platform/tests/Browser/Spec190BaselineCompareMatrixSmokeTest.php`
|
||||||
|
|
||||||
|
### Implementation for User Story 1
|
||||||
|
|
||||||
|
- [ ] T008 [US1] Render the dense multi-tenant matrix shell with sticky subject-column behavior in `apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php`
|
||||||
|
- [ ] T009 [US1] Reduce dense-cell chrome to compact state, trust, freshness, and attention signals in `apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php`
|
||||||
|
- [ ] T010 [US1] Calm repeated cell and tenant actions into compact secondary affordances in `apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php` and `apps/platform/app/Filament/Pages/BaselineCompareMatrix.php`
|
||||||
|
- [ ] T011 [US1] Run focused US1 verification against `apps/platform/tests/Feature/Filament/BaselineCompareMatrixPageTest.php` and `apps/platform/tests/Browser/Spec190BaselineCompareMatrixSmokeTest.php`
|
||||||
|
|
||||||
|
**Checkpoint**: Multi-tenant scanning is visibly denser and the matrix body reads as the primary working surface.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4: User Story 2 - Work a single visible tenant in compact mode (Priority: P2)
|
||||||
|
|
||||||
|
**Goal**: Replace pseudo-matrix rendering with a compact comparison surface when only one visible tenant remains.
|
||||||
|
|
||||||
|
**Independent Test**: Open the matrix with one visible tenant and verify compact mode in auto state plus drilldown continuity.
|
||||||
|
|
||||||
|
### Tests for User Story 2
|
||||||
|
|
||||||
|
- [ ] T012 [P] [US2] Add compact single-tenant coverage in `apps/platform/tests/Feature/Filament/BaselineCompareMatrixPageTest.php`
|
||||||
|
|
||||||
|
### Implementation for User Story 2
|
||||||
|
|
||||||
|
- [ ] T013 [US2] Resolve auto-to-compact presentation behavior for one visible tenant in `apps/platform/app/Filament/Pages/BaselineCompareMatrix.php`
|
||||||
|
- [ ] T014 [US2] Render the compact single-tenant compare list in `apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php`
|
||||||
|
- [ ] T015 [US2] Preserve subject focus and drilldown continuity across compact-mode state in `apps/platform/app/Filament/Pages/BaselineCompareMatrix.php`
|
||||||
|
- [ ] T016 [US2] Run focused US2 verification against `apps/platform/tests/Feature/Filament/BaselineCompareMatrixPageTest.php`
|
||||||
|
|
||||||
|
**Checkpoint**: One-tenant viewing is materially shorter and calmer than the current matrix surface.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 5: User Story 3 - Use filters, legends, and status surfaces without losing the matrix (Priority: P2)
|
||||||
|
|
||||||
|
**Goal**: Compress supporting context so it stays useful without pushing the matrix down or increasing visual noise.
|
||||||
|
|
||||||
|
**Independent Test**: Apply filters, inspect legends, and observe background refresh behavior without losing scanability.
|
||||||
|
|
||||||
|
### Tests for User Story 3
|
||||||
|
|
||||||
|
- [ ] T017 [P] [US3] Add filter apply/reset and legend-compaction coverage in `apps/platform/tests/Feature/Filament/BaselineCompareMatrixPageTest.php`
|
||||||
|
- [ ] T018 [P] [US3] Add non-blocking refresh and last-updated browser coverage in `apps/platform/tests/Browser/Spec190BaselineCompareMatrixSmokeTest.php`
|
||||||
|
|
||||||
|
### Implementation for User Story 3
|
||||||
|
|
||||||
|
- [ ] T019 [US3] Convert heavy matrix filters to a staged apply/reset workflow in `apps/platform/app/Filament/Pages/BaselineCompareMatrix.php` and `apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php`
|
||||||
|
- [ ] T020 [US3] Replace the current policy-type control with a faster compact operator-first selector in `apps/platform/app/Filament/Pages/BaselineCompareMatrix.php`
|
||||||
|
- [ ] T021 [US3] Group or collapse legends and lighten supporting context hierarchy in `apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php`
|
||||||
|
- [ ] T022 [US3] Render page-level last-updated, polling, and manual-refresh signals without blocking the matrix in `apps/platform/app/Filament/Pages/BaselineCompareMatrix.php` and `apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php`
|
||||||
|
- [ ] T023 [US3] Run focused US3 verification against `apps/platform/tests/Feature/Filament/BaselineCompareMatrixPageTest.php` and `apps/platform/tests/Browser/Spec190BaselineCompareMatrixSmokeTest.php`
|
||||||
|
|
||||||
|
**Checkpoint**: Filters, legends, and status surfaces support the operator without visually competing with the matrix.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 6: Polish & Cross-Cutting Concerns
|
||||||
|
|
||||||
|
**Purpose**: Finalize copy, formatting, and the focused verification pack.
|
||||||
|
|
||||||
|
- [ ] T024 [P] Review `auto`, `dense`, `compact`, `last updated`, and action-copy vocabulary in `apps/platform/app/Filament/Pages/BaselineCompareMatrix.php` and `apps/platform/resources/views/filament/pages/baseline-compare-matrix.blade.php`
|
||||||
|
- [ ] T025 [P] Run formatting with `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
|
||||||
|
- [ ] T026 Run the focused verification pack against `apps/platform/tests/Feature/Filament/BaselineCompareMatrixPageTest.php`, `apps/platform/tests/Feature/Baselines/BaselineCompareMatrixBuilderTest.php`, `apps/platform/tests/Feature/Guards/ActionSurfaceContractTest.php`, and `apps/platform/tests/Browser/Spec190BaselineCompareMatrixSmokeTest.php`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dependencies & Execution Order
|
||||||
|
|
||||||
|
### Phase Dependencies
|
||||||
|
|
||||||
|
- **Setup (Phase 1)**: starts immediately.
|
||||||
|
- **Foundational (Phase 2)**: depends on Setup and blocks presentation work.
|
||||||
|
- **US1 (Phase 3)**: depends on Phase 2 and is the MVP.
|
||||||
|
- **US2 (Phase 4)**: depends on Phase 2 and can follow US1 once the page contract is stable.
|
||||||
|
- **US3 (Phase 5)**: depends on Phase 2 and should land after dense and compact structure are in place.
|
||||||
|
- **Polish (Phase 6)**: depends on the desired user stories being complete.
|
||||||
|
|
||||||
|
### Within Each User Story
|
||||||
|
|
||||||
|
- Add or extend the story tests first.
|
||||||
|
- Land page-state changes before view-branching where possible.
|
||||||
|
- Keep each story independently shippable and verifiable.
|
||||||
|
|
||||||
|
### Parallel Opportunities
|
||||||
|
|
||||||
|
- `T001` and `T002` can run in parallel.
|
||||||
|
- `T004` and `T005` can run in parallel after `T003` defines the presentation contract.
|
||||||
|
- Within US1, `T006` and `T007` can run in parallel before `T008` through `T010`.
|
||||||
|
- Within US3, `T017` and `T018` can run in parallel before `T019` through `T022`.
|
||||||
|
|
||||||
|
## Implementation Strategy
|
||||||
|
|
||||||
|
1. Lock the presentation contract and route state first.
|
||||||
|
2. Deliver dense multi-tenant mode as the MVP operator gain.
|
||||||
|
3. Deliver compact single-tenant mode as the adaptive counterpart.
|
||||||
|
4. Compress filters, legends, and status surfaces last so they match the final page structure.
|
||||||
|
5. Finish with copy review, formatting, and the focused verification pack.
|
||||||
Loading…
Reference in New Issue
Block a user