feat: add tenant governance aggregate contract and action surface follow-ups #199

Merged
ahmido merged 6 commits from 168-tenant-governance-aggregate-contract into dev 2026-03-29 21:14:18 +00:00
8 changed files with 422 additions and 146 deletions
Showing only changes of commit 62c9b97d00 - Show all commits

View File

@ -1,32 +1,32 @@
<!-- <!--
Sync Impact Report Sync Impact Report
- Version change: 1.13.0 → 1.14.0 - Version change: 1.14.0 -> 2.0.0
- Modified principles: - Modified principles:
- Governance / Scope & Compliance → Governance / Scope, Compliance, and Review Expectations - Filament UI - Action Surface Contract -> Operator-Facing UI/UX Constitution v1 / Filament UI - Action Surface Contract
- Filament UI - Layout & Information Architecture Standards (UX-001) -> Operator-Facing UI/UX Constitution v1 / Filament UI - Layout & Information Architecture Standards (UX-001)
- Operator-facing UI Naming Standards (UI-NAMING-001) -> Operator-Facing UI/UX Constitution v1 / Operator-facing UI Naming Standards (UI-NAMING-001)
- Operator Surface Principles (OPSURF-001) -> Operator-Facing UI/UX Constitution v1 / Operator Surface Principles (OPSURF-001)
- Spec Scope Fields (SCOPE-002) -> Operator-Facing UI/UX Constitution v1 / Spec Scope Fields (SCOPE-002)
- Added sections: - Added sections:
- Proportionality First (PROP-001) - Operator-Facing UI/UX Constitution v1 (UI-CONST-001)
- No Premature Abstraction (ABSTR-001) - Surface Taxonomy (UI-SURF-001)
- No New Persisted Truth Without Source-of-Truth Need (PERSIST-001) - Hard Rules (UI-HARD-001)
- No New State Without Behavioral Consequence (STATE-001) - Exception Model (UI-EX-001)
- UI Semantics Must Not Become Their Own Framework (UI-SEM-001) - Enforcement Model (UI-REVIEW-001)
- V1 Prefers Explicit Narrow Implementations (V1-EXP-001) - Immediate Retrofit Priorities
- One Truth, Few Layers (LAYER-001) - Appendix A - One-page Condensed Constitution
- Spec Discipline Over Slice Proliferation (SPEC-DISC-001) - Appendix B - Feature Review Checklist
- Tests Must Protect Business Truth (TEST-TRUTH-001) - Appendix C - Red Flags for Future PRs
- Enterprise Complexity Is Allowed Only Where Risk Demands It (RISK-COMP-001)
- Mandatory Bloat Check for New Specs (BLOAT-001)
- Default Bias (BIAS-001)
- Removed sections: None - Removed sections: None
- Templates requiring updates: - Templates requiring updates:
- ✅ .specify/memory/constitution.md - ✅ .specify/memory/constitution.md
- ✅ .specify/templates/spec-template.md - ✅ .specify/templates/spec-template.md
- ✅ .specify/templates/plan-template.md - ✅ .specify/templates/plan-template.md
- ✅ .specify/templates/tasks-template.md - ✅ .specify/templates/tasks-template.md
- ✅ docs/product/principles.md
- ✅ docs/product/standards/README.md - ✅ docs/product/standards/README.md
- ✅ docs/HANDOVER.md - ✅ docs/HANDOVER.md
- ✅ docs/product/principles.md
- ✅ Agents.md
- Commands checked: - Commands checked:
- N/A `.specify/templates/commands/*.md` directory is not present in this repo - N/A `.specify/templates/commands/*.md` directory is not present in this repo
- Follow-up TODOs: - Follow-up TODOs:
@ -317,98 +317,266 @@ ### Scheduled/system runs (OPS-UX-SYS-001)
- Scheduled/queued operations MUST use locks + idempotency (no duplicates). - Scheduled/queued operations MUST use locks + idempotency (no duplicates).
- Graph throttling and transient failures MUST be handled with backoff + jitter (e.g., 429/503). - Graph throttling and transient failures MUST be handled with backoff + jitter (e.g., 429/503).
### Filament UI — Action Surface Contract (NON-NEGOTIABLE) ### Operator-Facing UI/UX Constitution v1 (UI-CONST-001)
For every new or modified Filament Resource / RelationManager / Page: Purpose and scope
- This section governs operator-facing admin UI semantics across TenantPilot / TenantAtlas.
- It defines allowed surface types, allowed interaction models, primary/secondary/destructive action hierarchy, list/detail/queue semantics, scope and context signals, canonical navigation and naming rules, visibility of critical operational truth, scanability and density rules, exception handling, and review and enforcement requirements.
- It does not govern branding, colors, typography, spacing tokens, marketing or landing pages, implementation details without UX effect, purely cosmetic copy changes, or backend architecture except where backend design would create false UI mental models.
- This section is governance, not a style guide. Its purpose is to prevent ambiguity, operator risk, and UI drift before they spread through the product.
#### Surface Taxonomy (UI-SURF-001)
Every new admin surface MUST be assigned exactly one surface type before implementation. Ad-hoc interaction models are forbidden.
##### CRUD / List-first Resource
- Purpose: scan, find, open, and selectively mutate many business records.
- Primary behavior: Browse -> Open -> Decide / Mutate.
- Primary model: one-click inspect/open. Full-row click is the default; identifier click is allowed only when full-row click conflicts with another dominant row mechanism.
- Secondary actions: at most one inline non-destructive shortcut; everything else belongs in overflow.
- Destructive actions: never inline beside inspect; only in overflow or the detail header; confirmation is mandatory.
- Explicit View/Inspect: forbidden when row click or identifier click already opens the same destination.
##### Queue / Review Surface
- Purpose: triage items, inspect them in context, decide, and continue working through the queue.
- Primary behavior: Inspect in context -> Decide -> Continue.
- Primary model: explicit Inspect using a slide-over, inline detail pane, or same-page inspect.
- Secondary actions: only queue-relevant actions belong in the row.
- Destructive actions: inline is allowed only when the destructive decision is part of the real queue work; irreversibility or high risk still requires confirmation.
- Row click: forbidden by default.
- Explicit View/Inspect: required unless the detail is already visible inline.
##### History / Audit Surface
- Purpose: inspect immutable history, events, and evidence without losing chronology.
- Primary behavior: Inspect event -> Follow trace -> Return to history context.
- Primary model: explicit Inspect, preferably in a slide-over or same-page detail.
- Secondary actions: related navigation only.
- Destructive actions: normally none.
- Row click: forbidden.
- Explicit View/Inspect: required.
##### Config-lite Resource
- Purpose: manage small, low-cardinality configuration where edit is effectively the detail surface.
- Primary behavior: Open config -> Adjust.
- Primary model: edit-as-inspect.
- Secondary actions: minimal and usually limited to Edit or overflow.
- Destructive actions: overflow or detail header only.
- Row click: allowed when it opens Edit directly and no separate View surface exists.
- Explicit View/Inspect: forbidden.
##### Read-only Registry / Report Surface
- Purpose: inspect, compare, reference, and export immutable or mostly read-only artifacts.
- Primary behavior: Scan -> Open detail -> Reference / Export.
- Primary model: row click or identifier click to detail.
- Secondary actions: optional single inline non-destructive shortcut when it serves the operator flow.
- Destructive actions: normally none; if they exist they belong in detail only.
- Explicit View/Inspect: forbidden when a functional one-click open already exists.
##### Detail-first Operational Surface
- Purpose: fully understand one operational record, including state, truth, context, and next steps.
- Primary behavior: Read -> Understand -> Act / Navigate.
- Primary model: dedicated detail page or dedicated operational page.
- Secondary actions: header actions and related-link groups.
- Destructive actions: detail header or grouped header actions only, always with confirmation.
- Row click and explicit View/Inspect: not applicable.
#### Hard Rules (UI-HARD-001)
##### Primary inspect model
- Every list surface MUST expose exactly one primary inspect/open model.
- A surface MUST NOT offer row click, identifier click, and explicit View/Inspect for the same destination as parallel primary models.
- CRUD / List-first and Read-only Registry / Report surfaces MUST provide an obvious one-click open path.
- Queue / Review and History / Audit surfaces MUST use explicit Inspect rather than row-click navigation.
##### Row-click semantics
- Full-row click is the default for CRUD / List-first and Read-only Registry / Report surfaces.
- Identifier-only click is allowed only when full-row click would conflict with another dominant row behavior such as selection-heavy interaction, expand/collapse, drag/sort, or another primary row mechanism.
- When row click is enabled, the row MUST feel consistent. Silent split behavior inside the same row is forbidden.
- Edit-as-inspect is allowed only for Config-lite resources.
##### View and Inspect actions
- Explicit View MUST NOT exist when the same destination is already opened through row click or identifier click.
- Explicit Inspect is the default only for Queue / Review, History / Audit, and explicitly catalogued exceptions.
- View and Inspect MUST NOT be treated as interchangeable labels. If the interaction preserves context and behaves unlike ordinary navigation, it is Inspect, not View.
##### Action hierarchy
- Every surface MUST distinguish between the primary inspect/open action, secondary safe actions, destructive actions, and long-running workflow launches.
- Standard CRUD and Read-only Registry rows MUST NOT exceed the primary open interaction plus one inline safe shortcut.
- All other secondary actions MUST move to overflow.
- Long-running workflow launches such as sync, compare, verify, generate, consent, setup, or retry SHOULD live in list headers or detail headers rather than in every row.
##### Destructive actions
- Destructive actions MUST NOT appear inline beside the primary inspect interaction on standard CRUD, Config-lite, or Read-only Registry surfaces.
- Destructive actions MUST live in overflow or the detail header.
- Destructive actions MUST use confirmation.
- High-risk or high-volume destructive bulk actions SHOULD use typed confirmation.
- The Queue Decision exception applies only when the destructive decision is part of the actual queue work.
##### Overflow and More
- Overflow actions MUST follow one product-wide pattern per surface class.
- Mixed labeled-overflow versus icon-only overflow patterns inside the same surface class are forbidden unless an approved exception documents why.
- Empty `ActionGroup` and empty `BulkActionGroup` are forbidden.
- Placeholder UI added only to satisfy a contract or slot is forbidden.
##### Bulk actions
- Bulk actions are allowed only when they are safe enough, materially faster than row-by-row execution, and genuinely fit the surface.
- A surface with no real bulk need MUST NOT render bulk UI.
- Bulk destructive actions follow the same protection rules as row destructive actions, with stricter confirmation and review expectations.
##### Row label length and action budget
- Inline row action labels MUST stay short and SHOULD be one or two words.
- Long workflow labels belong in overflow, headers, or detail surfaces.
- Standard list rows MUST NOT become control centers for onboarding recovery, provider management, consent flows, RBAC setup, diagnostics, and destructive lifecycle actions all at once.
##### Scope and context semantics
- Scope chips, tenant pills, and similar context signals MUST correspond to real scoping behavior.
- A scope signal MUST NOT be shown when it neither scopes the displayed data nor materially changes the action targets.
- Remembered context is allowed only when labeled clearly as reference context rather than active scope.
- Cross-panel navigation MUST NOT imply that the operator remains inside the same logical scope when that is not true.
##### Canonical navigation and terminology
- Every domain object MUST have one canonical collection noun and one canonical singular noun.
- The same domain object MUST NOT use competing primary nouns across shells.
- The Operations domain MUST use one canonical collection noun. Parallel primary nouns such as Runs beside Operations are forbidden.
- Cross-panel navigation is allowed only when it lands on a canonical surface, uses stable nouns, and keeps back navigation clear.
##### Visibility of critical operational truth
- Critical operational truth MUST be visible by default.
- It MUST NOT be hidden only in default-off columns, tooltips, helper text, overflow menus, or detail pages when list decisions depend on it.
- Lifecycle truth, operability truth, health truth, execution outcome, trust/confidence, and next action MUST remain separate semantic dimensions.
- One badge, column, or label MUST NOT collapse multiple truth dimensions into a generic status.
##### Row density and scanability
- Standard CRUD lists MUST remain scanable.
- Outside Queue / Review and History / Audit exceptions, each row MAY contain at most one multi-line explanatory column and at most one prose-heavy explanatory context.
- Standard CRUD rows MUST NOT carry more than one sentence of flowing prose.
- Next-step prose belongs in detail, inspect, or queue surfaces, not in ordinary CRUD rows.
##### Custom abstractions
- Custom UI abstractions MAY document and validate, but they MUST NOT create declaration-only safety that diverges from real behavior.
- Contract systems MUST NOT force placeholder UI.
- Behavior matters more than declaration. If declared conformance and rendered behavior differ, the surface is non-conformant.
- A feature MUST NOT ship when its implemented interaction semantics contradict its declared surface type.
#### Exception Model (UI-EX-001)
Only catalogued exception types are allowed. Every exception MUST be named in the spec, reference its exception type, include a reason block, be called out explicitly in the PR, and carry at least one dedicated test.
##### Queue Decision Exception
- Allowed when per-item decision-making is the real queue work.
- Guardrails: Inspect remains available unless detail is already inline; irreversible decisions require confirmation; unrelated maintenance actions do not join the row.
##### History In-place Inspect Exception
- Allowed when leaving the page would break chronology or traceability.
- Guardrails: explicit Inspect is mandatory; row click is forbidden; generic mutation rails are forbidden.
##### Config-lite Edit-as-Inspect Exception
- Allowed when a separate View surface would add no value.
- Guardrails: no parallel View surface; no high-risk destructive flow as the default entry point.
##### Read-only Shortcut Exception
- Allowed for exactly one dominant non-destructive shortcut.
- Guardrails: inspect/open remains dominant; only one shortcut exists; the shortcut does not compete with the primary open path.
##### Cross-panel Canonical Route Exception
- Allowed when only one canonical surface makes sense.
- Guardrails: nouns stay stable; shell transition is explicit; back navigation is clear; scope signals remain truthful.
#### Filament UI — Action Surface Contract (NON-NEGOTIABLE)
For every new or modified Filament Resource, RelationManager, or Page:
Required surfaces Required surfaces
- List/Table MUST define: Header Actions, Row Actions, Bulk Actions, and Empty-State CTA(s). - List/Table MUST define Header Actions, Row Actions, Bulk Actions, and Empty-State CTA(s).
- Inspect affordance (List/Table): Every table MUST provide a record inspection affordance. - Every table MUST provide a record inspection affordance that matches its surface type.
- Accepted forms: clickable rows via `recordUrl()` (preferred), a dedicated row “View” action, or a primary linked column. - Accepted forms are `recordUrl()` row click, a primary linked column, or an explicit row action when the taxonomy requires Inspect.
- Rule: Do NOT render a lone “View” row action button. If View is the only row action, prefer clickable rows. - CRUD / List-first, Config-lite, and Read-only Registry surfaces MUST NOT render a redundant View action when the same destination is already available through row click or identifier click.
- View/Detail MUST define Header Actions (Edit + “More” group when applicable). - Queue / Review and History / Audit surfaces MAY use a lone explicit Inspect action because context-preserving inspect is the primary interaction.
- View/Detail MUST be sectioned (e.g., Infolist Sections / Cards); avoid long ungrouped field lists. - View/Detail MUST define header actions and MUST keep destructive actions grouped and confirmed.
- Create/Edit MUST provide consistent Save/Cancel UX. - View/Detail MUST be sectioned using Infolists, Sections, Cards, Tabs, or equivalent composable structure.
- Create/Edit MUST provide consistent Save and Cancel UX.
Grouping & safety Grouping and safety
- Max 2 visible Row Actions (typically View/Edit). Everything else MUST be in an ActionGroup “More”. - Standard CRUD and Read-only Registry rows MUST NOT exceed inspect/open plus one inline safe shortcut.
- Bulk actions MUST be grouped via BulkActionGroup. - Queue / Review rows MAY expose inline decision actions only when allowed by UI-EX-001.
- RelationManagers MUST follow the same action surface rules (grouped row actions, bulk actions where applicable, inspection affordance). - Everything else MUST move to `ActionGroup::make()` or the detail header.
- Destructive actions MUST NOT be primary and MUST require confirmation; typed confirmation MAY be required for large/bulk changes. - Bulk actions MUST be grouped via `BulkActionGroup` only when the surface has a real bulk use case.
- Empty `ActionGroup` and `BulkActionGroup` are forbidden.
- Destructive actions MUST NOT be primary and MUST require confirmation; typed confirmation MAY be required for large or high-risk bulk changes.
- Relevant mutations MUST write an audit log entry. - Relevant mutations MUST write an audit log entry.
RBAC enforcement RBAC enforcement
- Non-member access MUST abort(404) and MUST NOT leak existence. - Non-member access MUST abort(404) and MUST NOT leak existence.
- Member without capability: UI visible but disabled with tooltip; server-side MUST abort(403). - Members without capability MAY see disabled actions with helper text, but server-side execution MUST still abort(403).
- Central enforcement helpers (tenant/workspace UI enforcement) MUST be used for gating. - Central tenant and workspace UI enforcement helpers MUST be used for gating.
Spec / DoD gates Behavior over declaration
- Every spec MUST include a “UI Action Matrix”. - Every spec MUST include both a UI/UX Surface Classification and a UI Action Matrix.
- A change is not “Done” unless the Action Surface Contract is met OR an explicit exemption exists with documented reason. - Custom action-surface contracts are legitimate only when they validate rendered behavior, not only declarations or slot counts.
- CI MUST run an automated Action Surface Contract check (test suite and/or command) that fails when required surfaces are missing. - A change is not Done unless the implemented interaction semantics conform to the declared surface type or an approved exception documents and tests the deviation.
### Filament UI — Layout & Information Architecture Standards (UX-001) #### Filament UI — Layout & Information Architecture Standards (UX-001)
Goal: Demo-level, enterprise-grade admin UX. These rules are NON-NEGOTIABLE for new or modified Filament screens. Goal: operator-facing Filament screens MUST feel enterprise-grade, legible, and decisive.
Page layout Page layout
- Create/Edit MUST default to a Main/Aside layout using a 3-column grid with `Main=columnSpan(2)` and `Aside=columnSpan(1)`. - Create/Edit MUST default to a Main/Aside layout using a 3-column grid with `Main=columnSpan(2)` and `Aside=columnSpan(1)`.
- All fields MUST be inside Sections/Cards. No “naked” inputs at the root schema level. - All fields MUST live inside Sections or Cards. Naked root-level inputs are forbidden.
- Main contains domain definition/content. Aside contains status/meta (status, version label, owner, scope selectors, timestamps). - Main content carries domain definition and working content. Aside carries status and meta such as scope, owner, timestamps, or version labels.
- Related data (assignments, relations, evidence, runs, findings, etc.) MUST render as separate Sections below the main/aside grid (or as tabs/sub-navigation), never mixed as unstructured long lists. - Related data MUST render as separate sections, tabs, or subordinate surfaces rather than as one long unstructured form or detail page.
View pages View pages
- View/Detail MUST be a read-only experience using Infolists (or equivalent), not disabled edit forms. - View/Detail MUST be a read-only surface built with Infolists or an equivalent read-first structure, not disabled edit forms.
- Status-like values MUST render as badges/chips using the centralized badge semantics (BADGE-001). - Status-like values MUST render via BADGE-001 semantics.
- Long text MUST render as readable prose (not textarea styling). - Long text MUST read like prose, not like disabled textarea output.
Empty states Empty states
- Empty lists/tables MUST show: a specific title, one-sentence explanation, and exactly ONE primary CTA in the empty state. - Empty lists and tables MUST show a specific title, a one-sentence explanation, and exactly one primary CTA.
- When non-empty, the primary CTA MUST move to the table header (top-right) and MUST NOT be duplicated in the empty state. - When records exist, that primary CTA moves to the header and MUST NOT be duplicated in the empty state shell.
Actions & flows Actions and flows
- Pages SHOULD expose at most 1 primary header action and 1 secondary action; all other actions MUST be grouped (ActionGroup / BulkActionGroup). - Pages SHOULD expose at most one primary header action and one secondary header action; all others belong in groups.
- Multi-step or high-risk flows MUST use a Wizard (e.g., capture/compare/restore with preview + confirmation). - Multi-step or high-risk flows MUST use a wizard or an equivalent staged flow with preview and confirmation.
- Destructive actions MUST remain non-primary and require confirmation (RBAC-UX-005). - Destructive actions remain non-primary and confirmed.
Table work-surface defaults Table defaults
- Tables SHOULD provide search (when the dataset can grow), a meaningful default sort, and filters for core dimensions (status/severity/type/tenant/time-range). - Tables SHOULD provide search when the dataset can grow, a meaningful default sort, and filters for core dimensions.
- Tables MUST render key statuses as badges/chips (BADGE-001) and avoid ad-hoc status mappings. - Standard CRUD tables MUST stay scanable and MUST NOT rely on row prose to communicate next steps.
- Critical operational truth that informs list decisions MUST be default-visible.
Enforcement Enforcement
- New resources/pages SHOULD use shared layout builders (e.g., `MainAsideForm`, `MainAsideInfolist`, `StandardTableDefaults`) to keep screens consistent. - Shared layout builders such as `MainAsideForm`, `MainAsideInfolist`, and `StandardTableDefaults` SHOULD be reused where available.
- A change is not “Done” unless UX-001 is satisfied OR an explicit exemption exists with a documented rationale in the spec/PR. - A change is not Done unless UX-001 is satisfied or an approved exception documents why not.
### Operator-facing UI Naming Standards (UI-NAMING-001) #### Operator-facing UI Naming Standards (UI-NAMING-001)
Goal: operator-facing actions, run labels, notifications, audit prose, and related UI copy MUST use consistent, Goal: operator-facing actions, runs, notifications, audit prose, and navigation MUST use one clear domain vocabulary.
enterprise-grade product language.
Naming model Naming model
- Operator-facing copy MUST distinguish four layers: Scope, Source/Domain, Operation, and Target Object. - Operator-facing copy MUST distinguish Scope, Source/Domain, Operation, and Target Object.
- Scope terms (`Workspace`, `Tenant`) describe execution context and MUST NOT be used as the primary action label unless they are the actual target object. - Scope terms such as Workspace and Tenant describe execution context and MUST NOT become the primary action label unless they are the actual target object.
- Source/Domain terms (`Intune`, `Entra`, `Teams`, future providers) are secondary and MUST NOT lead the primary label unless the current screen presents competing sources that need explicit disambiguation. - Source/domain terms such as Intune or Entra are secondary and lead only when same-screen disambiguation genuinely requires them.
Primary action labels Primary labels
- Primary buttons, header actions, and menu actions MUST use `Verb + Object`. - Primary buttons, header actions, and menu actions MUST use Verb + Object.
- Preferred examples: `Sync policies`, `Sync groups`, `Capture baseline`, `Compare baseline`, `Restore policy`, `Run review`, `Export review pack`. - Preferred examples are `Sync policies`, `Sync groups`, `Capture baseline`, `Compare baseline`, `Restore policy`, `Run review`, and `Export review pack`.
- Forbidden examples: `Sync from tenant`, `Backup tenant`, `Compare tenant`, `Sync from Intune`, `Run tenant sync now`, `Start inventory refresh from provider`. - Implementation-first labels such as `Sync from tenant`, `Sync from Intune`, `Run tenant sync now`, or `Start inventory refresh from provider` are forbidden.
Domain vocabulary Canonical nouns and routes
- Operator-facing copy MUST prefer product-domain objects such as `policies`, `groups`, `baseline`, `findings`, `review pack`, `alerts`, and `operations`. - Every domain object MUST keep one canonical collection noun and one canonical singular noun.
- Primary operator-facing copy MUST NOT use implementation-first terms such as `provider`, `gateway`, `resolver`, `collector`, `contract registry`, or `job dispatch`. - Cross-shell or cross-panel navigation MUST preserve the same noun.
- Source/domain details MAY appear in modal descriptions, helper text, run metadata, audit metadata, and notifications when needed for precision. - Operations is the canonical collection noun for run records. Runs MUST NOT appear as a competing primary collection noun.
Run, notification, and audit semantics Run, notification, and audit semantics
- Visible run titles MUST use the same domain vocabulary as the initiating action and SHOULD be concise noun phrases such as `Policy sync`, `Baseline capture`, `Baseline compare`, `Policy restore`, and `Tenant review`. - Visible run titles MUST use the same domain vocabulary as the initiating action and SHOULD remain concise noun phrases such as `Policy sync`, `Baseline capture`, `Baseline compare`, `Policy restore`, and `Tenant review`.
- Notifications MUST use either `{Object} {state}` or `{Operation} {result}` and remain short, e.g. `Policy sync queued`, `Policy sync completed`, `Policy sync failed`, `Baseline compare detected drift`. - Notifications MUST use either `{Object} {state}` or `{Operation} {result}` and remain short.
- Audit prose MUST use the same operator-facing language, e.g. `{actor} queued policy sync`, `{actor} captured baseline`, `{actor} reopened finding`. - Audit prose MUST use the same operator-facing language as the initiating action.
- The same user-visible action MUST keep the same domain vocabulary across button labels, modal titles, run titles, notifications, and audit prose. - The same user-visible action MUST keep the same domain vocabulary across button labels, modal titles, run titles, notifications, audit prose, and related navigation.
Verb standard Verb standard
- Preferred verbs are `Sync`, `Capture`, `Compare`, `Restore`, `Review`, `Export`, `Open`, `Archive`, `Resolve`, `Reopen`, and `Assign`. - Preferred verbs are `Sync`, `Capture`, `Compare`, `Restore`, `Review`, `Export`, `Open`, `Archive`, `Resolve`, `Reopen`, and `Assign`.
- `Start`, `Execute`, `Trigger`, and `Perform` SHOULD be avoided for operator-facing copy unless there is a deliberate domain reason. - `Start`, `Execute`, `Trigger`, and `Perform` SHOULD be avoided unless the domain specifically requires them.
- `Run` MAY be used only when the object is itself run-like, such as `Run review` or `Run compare`; it MUST NOT be the generic fallback verb for all operations. - `Run` MAY be used only when the object is itself run-like, such as `Run review`; it MUST NOT become the fallback verb for everything.
Current binding decision Current binding decision
- The Policies screen primary action MUST be `Sync policies`. - The Policies screen primary action MUST be `Sync policies`.
@ -417,75 +585,125 @@ ### Operator-facing UI Naming Standards (UI-NAMING-001)
- The visible run label for that action MUST be `Policy sync`. - The visible run label for that action MUST be `Policy sync`.
- The audit prose for that action MUST be `{actor} queued policy sync`. - The audit prose for that action MUST be `{actor} queued policy sync`.
### Operator Surface Principles (OPSURF-001) #### Operator Surface Principles (OPSURF-001)
Goal: operator-facing surfaces MUST optimize for the primary working audience rather than raw implementation visibility. Goal: operator-facing surfaces MUST optimize for the operator's working question instead of raw implementation visibility.
Operator-first default surfaces Operator-first default surfaces
- `/admin` is operator-first. - `/admin` is operator-first.
- Default-visible content MUST use operator-facing language, clear scope, and actionable status communication. - Default-visible content MUST use operator language, clear scope, and actionable status communication.
- Raw implementation details MUST NOT be default-visible on primary operator surfaces. - Raw implementation details MUST NOT be default-visible on primary operator surfaces.
Progressive disclosure for diagnostics Progressive disclosure for diagnostics
- Diagnostic detail MAY be available where needed, but it MUST be secondary and explicitly revealed. - Diagnostic detail MAY exist, but it MUST be secondary and explicitly revealed.
- JSON payloads, raw IDs, internal field names, provider error details, and low-level technical metadata belong in diagnostics surfaces, drawers, tabs, accordions, or modals rather than primary content. - JSON payloads, raw IDs, internal field names, provider error details, and low-level technical metadata belong in diagnostics surfaces rather than the primary content region.
- A surface MUST NOT require operators to parse raw JSON or provider-specific field names to understand the primary state or next action. - Operators MUST NOT need to parse raw payloads to understand current state or next action.
Distinct status dimensions Distinct truth dimensions
- Operator-facing surfaces MUST distinguish at least the following dimensions when they all exist in the domain: - When the domain has execution outcome, data completeness, governance result, lifecycle or readiness state, operability truth, health truth, trust/confidence, or next action semantics, the surface MUST keep them explicit instead of collapsing them into one ambiguous status.
- execution outcome - If multiple truth dimensions are summarized, the default-visible UI MUST label each dimension clearly.
- data completeness
- governance result
- lifecycle or readiness state
- These dimensions MUST NOT be collapsed into a single ambiguous status model.
- If a surface summarizes multiple status dimensions, the default-visible presentation MUST label each dimension explicitly.
Explicit mutation scope Explicit mutation scope
- Every action that changes state MUST communicate before execution whether it affects: - Every state-changing action MUST communicate before execution whether it affects TenantPilot only, the Microsoft tenant, or simulation only.
- TenantPilot only - Mutation scope MUST be understandable from nearby action copy, helper text, preview, or confirmation.
- the Microsoft tenant
- simulation only
- Mutation scope MUST be understandable from the action label, helper text, confirmation copy, preview, or nearby status copy before the operator commits.
- A mutating action MUST NOT rely on hidden implementation knowledge to communicate its blast radius.
Safe execution for dangerous actions Safe execution
- Dangerous actions MUST follow a consistent safe-execution pattern: - Dangerous actions MUST follow a consistent safety flow: configuration, safety checks or simulation, preview, hard confirmation where required, then execution.
- configuration - One-click high-blast-radius actions are forbidden unless an approved exception documents replacement safeguards.
- safety checks or simulation
- preview
- hard confirmation where required
- execute
- One-click destructive actions are not acceptable for high-blast-radius operations.
- When a full multi-step flow is not feasible, the spec MUST document the explicit exemption and the replacement safeguards.
Explicit workspace and tenant context Explicit workspace and tenant context
- Workspace and tenant scope MUST remain explicit in navigation, actions, and page semantics. - Workspace and tenant context MUST remain explicit in navigation, action copy, and page semantics.
- Tenant-scoped surfaces MUST NOT silently expose workspace-wide actions. - Tenant surfaces MUST NOT silently expose workspace-wide actions.
- Canonical workspace views that reference tenant-owned records MUST make the workspace and tenant context legible before the operator acts. - Canonical workspace views that operate on tenant-owned records MUST make both workspace and tenant context legible before the operator acts.
Critical truth visibility and scanability
- Critical operational truth MUST be default-visible wherever the list or summary surface is used to prepare decisions.
- Standard CRUD surfaces MUST preserve scanability and MUST avoid collapsing multiple truth dimensions into one generic badge or one prose-heavy row.
Page contract requirement Page contract requirement
- Every new or materially refactored operator-facing page MUST define: - Every new or materially refactored operator-facing page MUST define the primary persona, surface type, primary operator question, default-visible information, diagnostics-only information, status dimensions used, mutation scope, primary actions, and dangerous actions.
- primary persona - The page contract MUST live in the governing spec and stay in sync with implementation.
- surface type
- primary operator question
- default-visible information
- diagnostics-only information
- status dimensions used
- mutation scope
- primary actions
- dangerous actions
- This page contract MUST be recorded in the governing spec and kept in sync when the page semantics materially change.
Spec Scope Fields (SCOPE-002) #### Spec Scope Fields (SCOPE-002)
- Every feature spec MUST declare: - Every feature spec MUST declare Scope, Primary Routes, Data Ownership, and RBAC requirements.
- Scope: workspace | tenant | canonical-view - Canonical-view specs MUST define the default filter behavior when tenant context is active and the entitlement checks that prevent cross-tenant leakage.
- Primary Routes
- Data Ownership: workspace-owned vs tenant-owned tables/records impacted #### Enforcement Model (UI-REVIEW-001)
- RBAC: membership requirements + capability requirements
- For canonical-view specs, the spec MUST define: Spec review requirements
- Default filter behavior when tenant-context is active (e.g., prefilter to current tenant) - Every spec that changes an operator-facing surface MUST answer: surface type, primary inspect/open model, row-click rule, whether explicit View/Inspect exists or is forbidden, where secondary actions live, where destructive actions live, canonical collection route, canonical detail route, scope signals and their exact meaning, canonical noun, critical truth visible by default, and whether an exception type is used.
- Explicit entitlement checks that prevent cross-tenant leakage - Missing any of those answers makes the spec incomplete.
PR review requirements
- A PR MUST NOT pass when it introduces more than one primary inspect model, redundant View beside row click, destructive inline actions beside inspect on standard lists, empty overflow or bulk groups, long workflow labels in dense rows, misleading scope chips, drifting domain nouns, hidden critical operational truth, or undocumented exceptions without dedicated tests.
Guard tests
- Repository guards SHOULD validate: declared surface type, conformant primary inspect model, absence of redundant View actions, presence of explicit Inspect on Queue / Review and History / Audit surfaces, absence of empty `ActionGroup` or `BulkActionGroup`, correct placement of destructive actions, truthful scope signals, stable canonical nouns across shells, and dedicated tests for every approved exception.
#### Immediate Retrofit Priorities
Wave 1 - Interaction normalization
- First fixes target redundant row click plus View, destructive row actions on standard lists, empty overflow or bulk groups, and rows that have become pseudo-control centers.
- First-slice focus surfaces are Tenants, Workspaces, Policies, Alert Deliveries, and other CRUD-first list surfaces with the same drift pattern.
- Wave 1 is done only when each surface has exactly one primary inspect model, destructive actions are protected, and placeholder groups are gone.
Wave 2 - Scope, nouns, and truth
- Then fix scope and context leaks, stabilize canonical nouns, make cross-panel transitions explicit, move critical operational truth to default-visible regions, and reduce prose-heavy dense rows.
Wave 3 - Enforcement
- Then move the constitution into repo enforcement, require the PR checklist, anchor guard tests, and trim old declaration-only action-surface checks until behavior is the governing truth.
#### Appendix A - One-page Condensed Constitution
- Every admin surface has one surface type.
- Every list has exactly one primary inspect/open model.
- CRUD and Registry surfaces use one-click open.
- Queue and Audit surfaces use explicit Inspect.
- Edit-as-inspect exists only for Config-lite resources.
- Standard lists expose at most one inline safe shortcut.
- Destructive actions never sit openly beside inspect on standard lists.
- Overflow is standardized per surface class and is never empty.
- Bulk exists only when it is genuinely useful.
- Scope chips must be truthful.
- Domain nouns are canonical and stable.
- Critical operational truth is default-visible.
- Semantic truth dimensions are not collapsed into a generic status.
- Standard lists stay scanable.
- Exceptions are catalogued, justified, and tested.
- Features with ambiguous interaction semantics do not ship.
#### Appendix B - Feature Review Checklist
- Surface type is declared.
- Primary inspect/open model is defined.
- Row-click rule is decided.
- View/Inspect is correctly present or correctly forbidden.
- Edit-as-inspect is used only when allowed.
- Secondary actions are grouped correctly.
- Destructive actions are placed correctly.
- Overflow is not empty.
- Bulk is justified.
- Inline labels are short.
- Scope signals are truthful.
- Canonical nouns stay consistent.
- Critical truth is visible.
- Scanability is preserved.
- Exceptions are documented and tested.
#### Appendix C - Red Flags for Future PRs
- Row click and View open the same destination.
- A row becomes a control center.
- Archive or Delete sits openly beside View or Inspect on a standard list.
- More menus or bulk menus are empty.
- Scope chips have no real scope effect.
- Runs and Operations are used as competing primary collection nouns.
- Long workflow labels live in dense tables.
- Edit is used as default inspect even though a true View surface exists.
- Queue surfaces throw the operator out of context through row click.
- Critical health or operability truth is hidden by default.
- A contract claims conformance while the rendered UI behaves differently.
### Data Minimization & Safe Logging ### Data Minimization & Safe Logging
- Inventory MUST store only metadata + whitelisted `meta_jsonb`. - Inventory MUST store only metadata + whitelisted `meta_jsonb`.
@ -569,4 +787,4 @@ ### Versioning Policy (SemVer)
- **MINOR**: new principle/section or materially expanded guidance. - **MINOR**: new principle/section or materially expanded guidance.
- **MAJOR**: removing/redefining principles in a backward-incompatible way. - **MAJOR**: removing/redefining principles in a backward-incompatible way.
**Version**: 1.14.0 | **Ratified**: 2026-01-03 | **Last Amended**: 2026-03-27 **Version**: 2.0.0 | **Ratified**: 2026-01-03 | **Last Amended**: 2026-03-28

View File

@ -57,6 +57,11 @@ ## Constitution Check
- Spec discipline / bloat check (SPEC-DISC-001, BLOAT-001): related semantic changes are grouped coherently, and any new enum, DTO/presenter, persisted entity, interface/registry/resolver, or taxonomy includes a proportionality review covering operator problem, insufficiency, narrowness, ownership cost, rejected alternative, and whether it is current-release truth - Spec discipline / bloat check (SPEC-DISC-001, BLOAT-001): related semantic changes are grouped coherently, and any new enum, DTO/presenter, persisted entity, interface/registry/resolver, or taxonomy includes a proportionality review covering operator problem, insufficiency, narrowness, ownership cost, rejected alternative, and whether it is current-release truth
- Badge semantics (BADGE-001): status-like badges use `BadgeCatalog` / `BadgeRenderer`; no ad-hoc mappings; new values include tests - Badge semantics (BADGE-001): status-like badges use `BadgeCatalog` / `BadgeRenderer`; no ad-hoc mappings; new values include tests
- Filament-native UI (UI-FIL-001): admin/operator surfaces use native Filament components or shared primitives first; no ad-hoc status UI, local semantic color/border decisions, or hand-built replacements when native/shared semantics exist; any exception is explicitly justified - Filament-native UI (UI-FIL-001): admin/operator surfaces use native Filament components or shared primitives first; no ad-hoc status UI, local semantic color/border decisions, or hand-built replacements when native/shared semantics exist; any exception is explicitly justified
- UI/UX surface taxonomy (UI-CONST-001 / UI-SURF-001): every changed operator-facing surface is classified as exactly one allowed surface type; ad-hoc interaction models are forbidden
- UI/UX inspect model (UI-HARD-001): each list surface has exactly one primary inspect/open model; redundant View beside row click or identifier click is forbidden; edit-as-inspect is limited to Config-lite resources
- UI/UX action hierarchy (UI-HARD-001 / UI-EX-001): standard CRUD and Registry rows expose at most one inline safe shortcut; destructive actions are grouped or in the detail header; queue exceptions are catalogued, justified, and tested
- UI/UX scope, truth, and naming (UI-HARD-001 / UI-NAMING-001 / OPSURF-001): scope signals are truthful, canonical nouns stay stable across shells, critical operational truth is default-visible, and standard lists remain scanable
- UI/UX placeholder ban (UI-HARD-001): empty `ActionGroup` / `BulkActionGroup` placeholders and declaration-only UI conformance are forbidden
- UI naming (UI-NAMING-001): operator-facing labels use `Verb + Object`; scope (`Workspace`, `Tenant`) is never the primary action label; source/domain is secondary unless disambiguation is required; runs/toasts/audit prose use the same domain vocabulary; implementation-first terms do not appear in primary operator UI - UI naming (UI-NAMING-001): operator-facing labels use `Verb + Object`; scope (`Workspace`, `Tenant`) is never the primary action label; source/domain is secondary unless disambiguation is required; runs/toasts/audit prose use the same domain vocabulary; implementation-first terms do not appear in primary operator UI
- Operator surfaces (OPSURF-001): `/admin` defaults are operator-first; default-visible content avoids raw implementation detail; diagnostics are explicitly revealed secondarily - Operator surfaces (OPSURF-001): `/admin` defaults are operator-first; default-visible content avoids raw implementation detail; diagnostics are explicitly revealed secondarily
- Operator surfaces (OPSURF-001): execution outcome, data completeness, governance result, and lifecycle/readiness are modeled as distinct status dimensions when all apply; they are not collapsed into one ambiguous status - Operator surfaces (OPSURF-001): execution outcome, data completeness, governance result, and lifecycle/readiness are modeled as distinct status dimensions when all apply; they are not collapsed into one ambiguous status
@ -64,7 +69,7 @@ ## Constitution Check
- Operator surfaces (OPSURF-001): dangerous actions follow configuration → safety checks/simulation → preview → hard confirmation where required → execute, unless a spec documents an explicit exemption and replacement safeguards - Operator surfaces (OPSURF-001): dangerous actions follow configuration → safety checks/simulation → preview → hard confirmation where required → execute, unless a spec documents an explicit exemption and replacement safeguards
- Operator surfaces (OPSURF-001): workspace and tenant context remain explicit in navigation, actions, and page semantics; tenant surfaces do not silently expose workspace-wide actions - Operator surfaces (OPSURF-001): workspace and tenant context remain explicit in navigation, actions, and page semantics; tenant surfaces do not silently expose workspace-wide actions
- Operator surfaces (OPSURF-001): each new or materially refactored operator-facing page defines a page contract covering persona, surface type, operator question, default-visible info, diagnostics-only info, status dimensions, mutation scope, primary actions, and dangerous actions - Operator surfaces (OPSURF-001): each new or materially refactored operator-facing page defines a page contract covering persona, surface type, operator question, default-visible info, diagnostics-only info, status dimensions, mutation scope, primary actions, and dangerous actions
- Filament UI Action Surface Contract: for any new/modified Filament Resource/RelationManager/Page, define Header/Row/Bulk/Empty-State actions, ensure every List/Table has a record inspection affordance (prefer `recordUrl()` clickable rows; do not render a lone View row action), keep max 2 visible row actions with the rest in “More”, group bulk actions, require confirmations for destructive actions (typed confirmation for large/bulk where applicable), write audit logs for mutations, enforce RBAC via central helpers (non-member 404, member missing capability 403), and ensure CI blocks merges if the contract is violated or not explicitly exempted - Filament UI Action Surface Contract: for any new/modified Filament Resource/RelationManager/Page, define Header/Row/Bulk/Empty-State actions, ensure every List/Table has a surface-appropriate inspect affordance, remove redundant View when row click or identifier click already opens the same destination, keep standard CRUD/Registry rows to inspect plus at most one inline safe shortcut, group or relocate the rest to “More” or detail header, forbid empty bulk/overflow groups, require confirmations for destructive actions, write audit logs for mutations, enforce RBAC via central helpers (non-member 404, member missing capability 403), and ensure CI blocks merges if the contract is violated or not explicitly exempted
- Filament UI UX-001 (Layout & IA): Create/Edit uses Main/Aside (3-col grid, Main=columnSpan(2), Aside=columnSpan(1)); all fields inside Sections/Cards (no naked inputs); View uses Infolists (not disabled edit forms); status badges use BADGE-001; empty states have specific title + explanation + 1 CTA; max 1 primary + 1 secondary header action; tables provide search/sort/filters for core dimensions; shared layout builders preferred for consistency - Filament UI UX-001 (Layout & IA): Create/Edit uses Main/Aside (3-col grid, Main=columnSpan(2), Aside=columnSpan(1)); all fields inside Sections/Cards (no naked inputs); View uses Infolists (not disabled edit forms); status badges use BADGE-001; empty states have specific title + explanation + 1 CTA; max 1 primary + 1 secondary header action; tables provide search/sort/filters for core dimensions; shared layout builders preferred for consistency
## Project Structure ## Project Structure

View File

@ -17,6 +17,15 @@ ## Spec Scope Fields *(mandatory)*
- **Default filter behavior when tenant-context is active**: [e.g., prefilter to current tenant] - **Default filter behavior when tenant-context is active**: [e.g., prefilter to current tenant]
- **Explicit entitlement checks preventing cross-tenant leakage**: [Describe checks] - **Explicit entitlement checks preventing cross-tenant leakage**: [Describe checks]
## UI/UX Surface Classification *(mandatory when operator-facing surfaces are changed)*
If this feature adds or materially changes an operator-facing list, detail, queue, audit, config, or report surface,
fill out one row per affected surface.
| 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 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| e.g. Tenant policies page | CRUD / List-first Resource | Full-row click | required | One inline safe shortcut + More | More / detail header | /admin/t/{tenant}/policies | /admin/t/{tenant}/policies/{record} | Tenant chip scopes rows and actions | Policies / Policy | Policy health, drift, assignment coverage | none |
## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)* ## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)*
If this feature adds a new operator-facing page or materially refactors one, fill out one row per affected page/surface. If this feature adds a new operator-facing page or materially refactors one, fill out one row per affected page/surface.
@ -172,6 +181,19 @@ ## Requirements *(mandatory)*
- how the same domain vocabulary is preserved across button labels, modal titles, run titles, notifications, and audit prose, - how the same domain vocabulary is preserved across button labels, modal titles, run titles, notifications, and audit prose,
- and how implementation-first terms are kept out of primary operator-facing labels. - and how implementation-first terms are kept out of primary operator-facing labels.
**Constitution alignment (UI-CONST-001 / UI-SURF-001 / UI-HARD-001 / UI-EX-001 / UI-REVIEW-001):** If this feature adds or changes an operator-facing surface, the spec MUST describe:
- the chosen surface type and why it is the correct classification,
- the one and only primary inspect/open model,
- whether row click is required, allowed, or forbidden,
- whether explicit View or Inspect is present, and why it is present or forbidden,
- where secondary actions live,
- where destructive actions live,
- the canonical collection route and canonical detail route,
- the scope signals shown to the operator and what real effect each one has,
- the canonical noun used across routes, labels, runs, notifications, and audit prose,
- which critical operational truth is visible by default,
- and any catalogued exception type, rationale, and dedicated test coverage.
**Constitution alignment (OPSURF-001):** If this feature adds or materially refactors an operator-facing surface, the spec MUST describe: **Constitution alignment (OPSURF-001):** If this feature adds or materially refactors an operator-facing surface, the spec MUST describe:
- how the default-visible content stays operator-first on `/admin` and avoids raw implementation detail, - how the default-visible content stays operator-first on `/admin` and avoids raw implementation detail,
- which diagnostics are secondary and how they are explicitly revealed, - which diagnostics are secondary and how they are explicitly revealed,
@ -190,6 +212,8 @@ ## Requirements *(mandatory)*
**Constitution alignment (Filament Action Surfaces):** If this feature adds or modifies any Filament Resource / RelationManager / Page, **Constitution alignment (Filament Action Surfaces):** If this feature adds or modifies any Filament Resource / RelationManager / Page,
the spec MUST include a “UI Action Matrix” (see below) and explicitly state whether the Action Surface Contract is satisfied. the spec MUST include a “UI Action Matrix” (see below) and explicitly state whether the Action Surface Contract is satisfied.
The same section MUST state that each affected surface has exactly one primary inspect/open model, that redundant View actions are absent,
that empty `ActionGroup` / `BulkActionGroup` placeholders are absent, and that destructive actions follow the required placement rules for the chosen surface type.
If the contract is not satisfied, the spec MUST include an explicit exemption with rationale. If the contract is not satisfied, the spec MUST include an explicit exemption with rationale.
The same section MUST also state whether UI-FIL-001 is satisfied and identify any approved exception. The same section MUST also state whether UI-FIL-001 is satisfied and identify any approved exception.
**Constitution alignment (UX-001 — Layout & Information Architecture):** If this feature adds or modifies any Filament screen, **Constitution alignment (UX-001 — Layout & Information Architecture):** If this feature adds or modifies any Filament screen,
@ -220,7 +244,7 @@ ## UI Action Matrix *(mandatory when Filament is changed)*
If this feature adds/modifies any Filament Resource / RelationManager / Page, fill out the matrix below. If this feature adds/modifies any Filament Resource / RelationManager / Page, fill out the matrix below.
For each surface, list the exact action labels, whether they are destructive (confirmation? typed confirmation?), For each surface, list the exact action labels, whether they are destructive (confirmation? typed confirmation?),
RBAC gating (capability + enforcement helper), and whether the mutation writes an audit log. RBAC gating (capability + enforcement helper), whether the mutation writes an audit log, and any exemption or exception used.
| Surface | Location | Header Actions | Inspect Affordance (List/Table) | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions | | Surface | Location | Header Actions | Inspect Affordance (List/Table) | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions |
|---|---|---|---|---|---|---|---|---|---| |---|---|---|---|---|---|---|---|---|---|

View File

@ -39,22 +39,31 @@ # Tasks: [FEATURE NAME]
- aligning button labels, modal titles, run titles, notifications, and audit prose to the same domain vocabulary, - aligning button labels, modal titles, run titles, notifications, and audit prose to the same domain vocabulary,
- removing implementation-first wording from primary operator-facing copy. - removing implementation-first wording from primary operator-facing copy.
**Operator Surfaces**: If this feature adds or materially refactors an operator-facing page or flow, tasks MUST include: **Operator Surfaces**: If this feature adds or materially refactors an operator-facing page or flow, tasks MUST include:
- filling the specs UI/UX Surface Classification for every affected surface,
- filling the specs Operator Surface Contract for every affected page, - filling the specs Operator Surface Contract for every affected page,
- making default-visible content operator-first and moving JSON payloads, raw IDs, internal field names, provider error details, and low-level metadata into explicitly revealed diagnostics surfaces, - making default-visible content operator-first and moving JSON payloads, raw IDs, internal field names, provider error details, and low-level metadata into explicitly revealed diagnostics surfaces,
- modeling execution outcome, data completeness, governance result, and lifecycle/readiness as distinct status dimensions when applicable, - modeling execution outcome, data completeness, governance result, and lifecycle/readiness as distinct status dimensions when applicable,
- making mutation scope legible before execution for every state-changing action (`TenantPilot only`, `Microsoft tenant`, or `simulation only`), - making mutation scope legible before execution for every state-changing action (`TenantPilot only`, `Microsoft tenant`, or `simulation only`),
- implementing the safe-execution flow for dangerous actions (configuration, safety checks/simulation, preview, hard confirmation where required, execute) or documenting an approved exemption, - implementing the safe-execution flow for dangerous actions (configuration, safety checks/simulation, preview, hard confirmation where required, execute) or documenting an approved exemption,
- keeping canonical nouns stable across routes, buttons, run titles, notifications, and audit prose,
- keeping scope signals truthful and ensuring critical operational truth is visible by default,
- keeping standard CRUD / Registry rows scanable rather than prose-heavy,
- keeping workspace and tenant context explicit in navigation, actions, and page semantics so tenant pages do not silently expose workspace-wide actions. - keeping workspace and tenant context explicit in navigation, actions, and page semantics so tenant pages do not silently expose workspace-wide actions.
**Filament UI Action Surfaces**: If this feature adds/modifies any Filament Resource / RelationManager / Page, tasks MUST include: **Filament UI Action Surfaces**: If this feature adds/modifies any Filament Resource / RelationManager / Page, tasks MUST include:
- filling the specs “UI Action Matrix” for all changed surfaces, - filling the specs “UI Action Matrix” for all changed surfaces,
- implementing required action surfaces (header/row/bulk/empty-state CTA for lists; header actions for view; consistent save/cancel on create/edit), - implementing required action surfaces (header/row/bulk/empty-state CTA for lists; header actions for view; consistent save/cancel on create/edit),
- ensuring every List/Table has a record inspection affordance (prefer `recordUrl()` clickable rows; do not render a lone View row action), - ensuring every List/Table has exactly one primary inspect/open model with the correct surface-appropriate affordance,
- enforcing the “max 2 visible row actions; everything else in More ActionGroup” rule, - removing redundant View/Inspect actions when row click or identifier click already opens the same destination,
- keeping standard CRUD / Registry rows to inspect/open plus at most one inline safe shortcut,
- moving additional secondary actions into More or the detail header,
- placing destructive actions in More or the detail header for standard lists and using catalogued exceptions only where allowed,
- grouping bulk actions via BulkActionGroup, - grouping bulk actions via BulkActionGroup,
- preventing empty `ActionGroup` / `BulkActionGroup` placeholders,
- adding confirmations for destructive actions (and typed confirmation where required by scale), - adding confirmations for destructive actions (and typed confirmation where required by scale),
- adding `AuditLog` entries for relevant mutations, - adding `AuditLog` entries for relevant mutations,
- using native Filament components or shared UI primitives before any local Blade/Tailwind assembly for badges, alerts, buttons, and semantic status surfaces, - using native Filament components or shared UI primitives before any local Blade/Tailwind assembly for badges, alerts, buttons, and semantic status surfaces,
- avoiding page-local semantic color, border, rounding, or highlight styling when Filament props or shared primitives can express the same state, - avoiding page-local semantic color, border, rounding, or highlight styling when Filament props or shared primitives can express the same state,
- documenting any catalogued UI exception in the spec/PR and adding dedicated test coverage,
- documenting any UI-FIL-001 exception with rationale in the spec/PR, - documenting any UI-FIL-001 exception with rationale in the spec/PR,
- adding/updated tests that enforce the contract and block merge on violations, OR documenting an explicit exemption with rationale. - adding/updated tests that enforce the contract and block merge on violations, OR documenting an explicit exemption with rationale.
**Filament UI UX-001 (Layout & IA)**: If this feature adds/modifies any Filament screen, tasks MUST include: **Filament UI UX-001 (Layout & IA)**: If this feature adds/modifies any Filament screen, tasks MUST include:

View File

@ -120,7 +120,7 @@ ### Missing (no code, no spec beyond brainstorming)
## Architecture & Principles (Non-Negotiables) ## Architecture & Principles (Non-Negotiables)
Source: [.specify/memory/constitution.md](.specify/memory/constitution.md) (v1.14.0) Source: [.specify/memory/constitution.md](.specify/memory/constitution.md) (v2.0.0)
### Core Principles ### Core Principles
@ -130,7 +130,7 @@ ### Core Principles
4. **Deterministic Capabilities** — Backup/restore/risk flags derived from config via `CoverageCapabilitiesResolver`. 4. **Deterministic Capabilities** — Backup/restore/risk flags derived from config via `CoverageCapabilitiesResolver`.
5. **Workspace Isolation** — Non-member → 404; workspace is primary session context. Enforced via `DenyNonMemberTenantAccess` middleware + `EnsureFilamentTenantSelected`. 5. **Workspace Isolation** — Non-member → 404; workspace is primary session context. Enforced via `DenyNonMemberTenantAccess` middleware + `EnsureFilamentTenantSelected`.
6. **Tenant Isolation** — Every read/write must be tenant-scoped; `DerivesWorkspaceIdFromTenant` concern auto-fills `workspace_id` from tenant. 6. **Tenant Isolation** — Every read/write must be tenant-scoped; `DerivesWorkspaceIdFromTenant` concern auto-fills `workspace_id` from tenant.
7. **Operator Surface Principles** — `/admin` defaults are operator-first, diagnostics are progressively disclosed, status dimensions stay distinct, mutation scope is explicit before execution, and every materially changed operator page carries an explicit page contract. 7. **UI/UX Constitution v1** — Every operator-facing admin surface is classified before implementation, each list gets exactly one primary inspect/open model, scope signals must be truthful, critical operational truth stays default-visible, and exceptions are catalogued and tested.
8. **Filament-native first / no ad-hoc styling** — Admin and operator UI must use Filament-native components or shared primitives before any local Blade/Tailwind assembly; page-local status styling is not an acceptable substitute. 8. **Filament-native first / no ad-hoc styling** — Admin and operator UI must use Filament-native components or shared primitives before any local Blade/Tailwind assembly; page-local status styling is not an acceptable substitute.
9. **Proportionality first** — New structure, layers, persistence, and semantic machinery must be justified by current release truth, current operator workflow, and why a narrower solution is insufficient. 9. **Proportionality first** — New structure, layers, persistence, and semantic machinery must be justified by current release truth, current operator workflow, and why a narrower solution is insufficient.
10. **Anti-bloat guardrails** — No premature abstraction, no new persisted truth without independent source-of-truth need, no new domain state without behavioral consequence, and specs that add structural complexity must carry an explicit proportionality review. 10. **Anti-bloat guardrails** — No premature abstraction, no new persisted truth without independent source-of-truth need, no new domain state without behavioral consequence, and specs that add structural complexity must carry an explicit proportionality review.
@ -158,7 +158,7 @@ ### Operations UX
### Filament Standards ### Filament Standards
- **Action Surface Contract**: List/View/Create/Edit pages each have defined required surfaces (Spec 082, 090). - **Action Surface Contract**: List/View/Create/Edit pages each have defined required surfaces, one primary inspect model, no redundant View beside row click, and no empty overflow or bulk groups (Specs 082, 090).
- **Layout**: Main/Aside layout, sections required, view pages use Infolists. - **Layout**: Main/Aside layout, sections required, view pages use Infolists.
- **Badge Semantics**: Centralized via `BadgeCatalog`/`BadgeRenderer` (Specs 059, 060). - **Badge Semantics**: Centralized via `BadgeCatalog`/`BadgeRenderer` (Specs 059, 060).
- **Filament-native UI**: Native Filament components and shared primitives come before any local styling or replacement markup for semantic UI elements. - **Filament-native UI**: Native Filament components and shared primitives come before any local styling or replacement markup for semantic UI elements.

View File

@ -3,7 +3,7 @@ # Product Principles
> Permanent product principles that govern every spec, every UI decision, and every architectural choice. > Permanent product principles that govern every spec, every UI decision, and every architectural choice.
> New specs must align with these. If a principle needs to change, update this file first. > New specs must align with these. If a principle needs to change, update this file first.
**Last reviewed**: 2026-03-27 **Last reviewed**: 2026-03-28
--- ---
@ -101,14 +101,25 @@ ### Data minimization & safe logging
## UI & Information Architecture ## UI & Information Architecture
### UI/UX constitution governs operator surfaces
Every operator-facing admin surface must be classified before implementation.
Allowed surface types are CRUD / List-first, Queue / Review, History / Audit, Config-lite, Read-only Registry / Report, and Detail-first Operational.
Ad-hoc interaction models are forbidden.
### One primary inspect model per list
Every list has exactly one dominant inspect/open model.
No redundant View beside row click or identifier click.
Queue and Audit surfaces use explicit Inspect; Config-lite alone may use edit-as-inspect.
### UX-001: Layout & IA Standards ### UX-001: Layout & IA Standards
Main/Aside layout. Sections required. View pages use Infolists. Main/Aside layout. Sections required. View pages use Infolists.
Empty states with specific title + explanation + exactly 1 CTA. Empty states with specific title + explanation + exactly 1 CTA.
### Action Surface Contract (non-negotiable) ### Action Surface Contract (non-negotiable)
Required surfaces per page type (list/view/create/edit). Required surfaces per page type (list/view/create/edit).
Max 2 visible row actions. Destructive requires confirmation. Standard CRUD and Registry rows expose exactly one primary open path plus at most one inline safe shortcut.
Every spec with UI changes must include a UI Action Matrix. Destructive actions are grouped and confirmed. Empty overflow or bulk groups are forbidden.
Every spec with UI changes must include both a UI/UX Surface Classification and a UI Action Matrix.
### Badge semantics centralized ### Badge semantics centralized
All status badges via `BadgeCatalog` / `BadgeRenderer`. No ad-hoc badge mappings. All status badges via `BadgeCatalog` / `BadgeRenderer`. No ad-hoc badge mappings.
@ -124,7 +135,7 @@ ### UI semantics stay lightweight
### Canonical navigation and terminology ### Canonical navigation and terminology
Consistent naming, consistent routing, consistent mental model. Consistent naming, consistent routing, consistent mental model.
No competing terms for the same concept. No competing terms for the same concept. Scope signals must remain truthful.
### Operator-first surfaces ### Operator-first surfaces
`/admin` defaults are for operators, not raw implementation visibility. `/admin` defaults are for operators, not raw implementation visibility.
@ -134,6 +145,14 @@ ### Distinct status and mutation semantics
Execution outcome, data completeness, governance result, and lifecycle/readiness stay separate when they all exist. Execution outcome, data completeness, governance result, and lifecycle/readiness stay separate when they all exist.
Every state-changing action tells the operator whether it affects TenantPilot only, the Microsoft tenant, or simulation only before execution. Every state-changing action tells the operator whether it affects TenantPilot only, the Microsoft tenant, or simulation only before execution.
### Critical truth is default-visible
Critical operational truth must not hide only in tooltips, overflow menus, default-off columns, or detail pages when the list prepares decisions.
Standard CRUD surfaces stay scanable and do not collapse multiple truth dimensions into one generic status.
### Exceptions are catalogued and tested
Only named UI exception types are allowed.
Every exception must be documented in the spec and PR with rationale and dedicated tests.
### Page contract requirement ### Page contract requirement
Every new or materially refactored operator-facing page defines its persona, surface type, primary operator question, Every new or materially refactored operator-facing page defines its persona, surface type, primary operator question,
default-visible information, diagnostics-only information, status dimensions, mutation scope, primary actions, and dangerous actions. default-visible information, diagnostics-only information, status dimensions, mutation scope, primary actions, and dangerous actions.

View File

@ -4,7 +4,7 @@ # Product Standards
> Specs reference these standards; they do not redefine them. > Specs reference these standards; they do not redefine them.
> Guard tests enforce critical constraints automatically. > Guard tests enforce critical constraints automatically.
**Last reviewed**: 2026-03-27 **Last reviewed**: 2026-03-28
--- ---
@ -42,7 +42,7 @@ ## Related Docs
| Document | Location | Purpose | | Document | Location | Purpose |
|---|---|---| |---|---|---|
| Constitution | `.specify/memory/constitution.md` | Permanent principles (PROP-001, BLOAT-001, OPSURF-001, UI-FIL-001, UX-001, Action Surface Contract, RBAC-UX) | | Constitution | `.specify/memory/constitution.md` | Permanent principles (PROP-001, BLOAT-001, UI-CONST-001, UI-SURF-001, UI-HARD-001, UI-EX-001, OPSURF-001, UI-FIL-001, UX-001, Action Surface Contract, RBAC-UX) |
| Product Principles | `docs/product/principles.md` | High-level product decisions | | Product Principles | `docs/product/principles.md` | High-level product decisions |
| Table Rollout Audit | `docs/ui/filament-table-standard.md` | Rollout inventory and implementation state from Spec 125 | | Table Rollout Audit | `docs/ui/filament-table-standard.md` | Rollout inventory and implementation state from Spec 125 |
| Action Surface Contract | `docs/ui/action-surface-contract.md` | Original action surface reference (now governed by this standard) | | Action Surface Contract | `docs/ui/action-surface-contract.md` | Original action surface reference (now governed by this standard) |

View File

@ -43,7 +43,7 @@ ### User Story 2 - Consistent, enterprise-grade actions and empty-state guidance
**Acceptance Scenarios**: **Acceptance Scenarios**:
1. **Given** a list view with records, **When** a user inspects available actions, **Then** they see at most two visible row actions and all secondary actions are grouped under a consistent label. 1. **Given** a list view with records, **When** a user inspects available actions, **Then** they see exactly one inspect model for the list (prefer clickable rows when a View page exists), at most two visible non-destructive row actions, and all secondary actions are grouped under a consistent label.
2. **Given** a list view with zero records, **When** the page is shown, **Then** it includes at least one CTA that helps resolve the empty state. 2. **Given** a list view with zero records, **When** the page is shown, **Then** it includes at least one CTA that helps resolve the empty state.
3. **Given** a list view that supports selection, **When** the user selects one or more records, **Then** at least one bulk action is available or the UI explicitly documents why bulk is intentionally not offered. 3. **Given** a list view that supports selection, **When** the user selects one or more records, **Then** at least one bulk action is available or the UI explicitly documents why bulk is intentionally not offered.
@ -100,7 +100,8 @@ ### Functional Requirements
- lists any exemptions with reasons. - lists any exemptions with reasons.
- **FR-005 (Automated gate)**: The system MUST automatically validate contract compliance for all in-scope UI components in the code review pipeline, and MUST fail with actionable messages when requirements are not met. - **FR-005 (Automated gate)**: The system MUST automatically validate contract compliance for all in-scope UI components in the code review pipeline, and MUST fail with actionable messages when requirements are not met.
- **FR-006 (Consistency rules)**: The system MUST enforce the following UX conventions through (a) declaration validation for all in-scope surfaces and (b) runtime tests on representative surfaces: - **FR-006 (Consistency rules)**: The system MUST enforce the following UX conventions through (a) declaration validation for all in-scope surfaces and (b) runtime tests on representative surfaces:
- no more than two visible row actions (typically View/Edit), - one inspect affordance per list surface; when a View page exists, prefer row-click inspection and do not pair it with a redundant lone `View` row button,
- no more than two visible non-destructive row actions, and when inspection is row-click driven keep at most one additional inline shortcut,
- secondary actions grouped under the standard label “More”, - secondary actions grouped under the standard label “More”,
- bulk actions grouped under the standard label “More”, - bulk actions grouped under the standard label “More”,
- destructive actions are never primary. - destructive actions are never primary.
@ -154,9 +155,9 @@ ## UI Action Matrix *(mandatory when admin UI components are changed)*
| Surface | Location | Header Actions | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions | | Surface | Location | Header Actions | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions |
|---|---|---|---|---|---|---|---|---|---| |---|---|---|---|---|---|---|---|---|---|
| CRUD list + detail | Tenant panel + Admin panel | Primary: Create (if allowed). Optional: domain CTA (e.g., Sync/Run) | Primary: View, Edit (if allowed). Secondary: grouped under “More” | At least 1 bulk action (e.g., Archive/Restore/Export) | Primary CTA: Create or domain CTA | Primary: Edit (if allowed). Secondary grouped under “More” | Consistent Save + Cancel; no destructive primary | Yes (for mutations + operation-start) | Exempt bulk only with explicit reason (e.g., no safe bulk operation exists) | | CRUD list + detail | Tenant panel + Admin panel | Primary: Create (if allowed). Optional: domain CTA (e.g., Sync/Run) | Inspect via clickable row or `View` action, not both. Optional: one inline safe shortcut such as `Edit`; secondary actions grouped under “More” | At least 1 bulk action (e.g., Archive/Restore/Export) | Primary CTA: Create or domain CTA | Primary: Edit (if allowed). Secondary grouped under “More” | Consistent Save + Cancel; no destructive primary | Yes (for mutations + operation-start) | Exempt bulk only with explicit reason (e.g., no safe bulk operation exists) |
| ReadOnly list + detail | Tenant panel + Admin panel | At least 1 CTA that provides value (e.g., Export/Refresh) | Primary: View. Secondary grouped under “More” | Bulk: Export (default) | CTA that resolves empty state (e.g., Refresh now) | “More” group for secondary actions | N/A | Maybe (typically for operation-start actions) | Exempt Export only with explicit reason (e.g., legal/security constraints) | | ReadOnly list + detail | Tenant panel + Admin panel | At least 1 CTA that provides value (e.g., Export/Refresh) | Inspect via clickable row or `View` action, not both. Secondary grouped under “More” when needed | Bulk: Export (default) | CTA that resolves empty state (e.g., Refresh now) | “More” group for secondary actions | N/A | Maybe (typically for operation-start actions) | Exempt Export only with explicit reason (e.g., legal/security constraints) |
| RunLog list + detail | Tenant panel + Admin panel | Optional CTA routing to Operations hub | Primary: View | Bulk: Export (default) or Prune if retention exists; otherwise exempt with reason | Optional CTA routing to Operations hub | “View run” canonical link; optional Export | N/A | Maybe (for prune/retention changes) | “View run” must be canonical tenantless as primary deep link | | RunLog list + detail | Tenant panel + Admin panel | Optional CTA routing to Operations hub | Inspect via clickable row or `View` action, not both | Bulk: Export (default) or Prune if retention exists; otherwise exempt with reason | Optional CTA routing to Operations hub | “View run” canonical link; optional Export | N/A | Maybe (for prune/retention changes) | “View run” must be canonical tenantless as primary deep link |
| Embedded relationship sub-list | Under parent detail | Header: Add/Attach/Create/Refresh depending on context | Primary: View and one context action (e.g., Detach/Remove). Secondary grouped under “More” | At least 1 bulk action or exemption with reason | CTA: next step (Add/Attach/Refresh) | N/A | N/A | Yes (for mutations) | Bulk may be exempted if relationship action is inherently single-record | | Embedded relationship sub-list | Under parent detail | Header: Add/Attach/Create/Refresh depending on context | Primary: View and one context action (e.g., Detach/Remove). Secondary grouped under “More” | At least 1 bulk action or exemption with reason | CTA: next step (Add/Attach/Refresh) | N/A | N/A | Yes (for mutations) | Bulk may be exempted if relationship action is inherently single-record |
### Key Entities *(include if feature involves data)* ### Key Entities *(include if feature involves data)*