# Feature Specification: Verification Surfaces Unification

**Feature Branch**: `084-verification-surfaces-unification`  
**Created**: 2026-02-09  
**Status**: Draft  
**Input**: User description: "Unify tenant + onboarding verification so all verification uses the same run-based mechanism with DB-only viewing and always-available reports (including blocked)."

## Clarifications

### Session 2026-02-09

- Q: For tenant members who are in-scope but lack the capability to start verification, how should the “Verify configuration” action behave in the UI? → A: Visible but disabled, with helper text explaining the missing capability (server still enforces 403 if invoked).
- Q: When rendering the embedded verification viewer on the tenant detail page, which run should be selected as “the last relevant run”? → A: Latest run attempt for that tenant+type (even if queued/running); if active and no report yet, show a DB-only “in progress” state.
- Q: On the tenant detail page, when no verification run exists yet, what should the embedded verification section do? → A: Show a DB-only empty state with a “Start verification” CTA.
- Q: For the canonical tenantless run viewer (/admin/operations/{run}), what should be required to view a run that is associated with a tenant? → A: Require both workspace membership AND tenant entitlement; missing either is deny-as-not-found (404).

## User Scenarios & Testing *(mandatory)*

<!--
  IMPORTANT: User stories should be PRIORITIZED as user journeys ordered by importance.
  Each user story/journey must be INDEPENDENTLY TESTABLE - meaning if you implement just ONE of them,
  you should still have a viable MVP (Minimum Viable Product) that delivers value.
  
  Assign priorities (P1, P2, P3, etc.) to each story, where P1 is the most critical.
  Think of each story as a standalone slice of functionality that can be:
  - Developed independently
  - Tested independently
  - Deployed independently
  - Demonstrated to users independently
-->

### User Story 1 - Verify tenant configuration consistently (Priority: P1)

As a workspace member with the appropriate permission, I can start a tenant verification from the tenant detail view and immediately see the latest stored verification results, without the page performing external provider calls during rendering.

**Why this priority**: This is the primary operational entry-point and must be fast, safe, and predictable.

**Independent Test**: Can be fully tested by starting verification from the tenant detail view, asserting a run record exists, and asserting the embedded viewer renders using stored data.

**Acceptance Scenarios**:

1. **Given** a tenant with an eligible provider connection, **When** I click “Verify configuration”, **Then** a verification run is started or deduped, and the tenant page renders the report viewer using stored data only.
2. **Given** a tenant where verification cannot proceed (e.g., missing consent/credentials), **When** I click “Verify configuration”, **Then** a completed “blocked” run exists and the embedded viewer shows a stub/preflight report (not an “unavailable” state).



### User Story 2 - Onboarding verify access behaves identically (Priority: P2)

As a workspace member with onboarding verification capability, I can start onboarding verification and receive the same run, dedupe/busy, blocked-report, and canonical link behavior as the tenant verification surfaces.

**Why this priority**: Removes confusion and reduces operational variance between onboarding and day-2 operations.

**Independent Test**: Can be tested by starting verification in onboarding and asserting identical run outcomes and viewer behavior to the tenant surface.

**Acceptance Scenarios**:

1. **Given** onboarding verification is started while another verification run is already active for the same target, **When** I start verification again, **Then** I receive a busy/deduped result that points to the existing active run.

---

### User Story 3 - Use canonical run links everywhere (Priority: P3)

As a workspace member, I can open the canonical run viewer link from any verification surface and it consistently resolves to the same “tenantless” run route.

**Why this priority**: Improves supportability and prevents broken/ambiguous deep links.

**Independent Test**: Can be tested by starting verification, then asserting all “View run” links point to the canonical run route and the page is accessible only to authorized members.

**Acceptance Scenarios**:

1. **Given** a verification run exists, **When** I click “View run”, **Then** I am taken to the canonical run viewer route for that run.

---

### Edge Cases
- Verification is started while an existing run is queued/running for the same target (dedupe/busy behavior must be consistent across surfaces).
- Verification cannot proceed due to missing consent/credentials (a completed blocked run must still have a schema-valid report).
- Viewer is opened by a non-member (deny-as-not-found behavior).
- Stored report data is present but incomplete/invalid (viewer must fail safe with a clear non-leaky message and no external calls).

## Non-Functional Requirements

- **NFR-001 (DB-only render)**: Tenant detail, onboarding verification display, and canonical run viewer rendering MUST be DB-only, with no external provider or Graph calls during mount/render/poll/refresh interactions.
- **NFR-002 (start path latency)**: Verification start interactions (`started`, `deduped`, `scope_busy`, `blocked`) SHOULD complete request handling in under 1 second under normal local/staging conditions because they only authorize, create/dedupe run state, enqueue, and notify.
- **NFR-003 (refresh/polling discipline)**: Verification UI refresh behavior MUST read persisted `OperationRun` state only and MUST NOT trigger inventory refresh or Graph permission reconciliation during display refresh.

## Requirements *(mandatory)*

**Constitution alignment (required):** If this feature introduces any Microsoft Graph calls, any write/change behavior,
or any long-running/queued/scheduled work, the spec MUST describe contract registry updates, safety gates
(preview/confirmation/audit), tenant isolation, run observability (`OperationRun` type/identity/visibility), and tests.
If security-relevant DB-only actions intentionally skip `OperationRun`, the spec MUST describe `AuditLog` entries.

**Constitution alignment (RBAC-UX):** If this feature introduces or changes authorization behavior, the spec MUST:
- state which authorization plane(s) are involved (tenant `/admin/t/{tenant}` vs platform `/system`),
- ensure any cross-plane access is deny-as-not-found (404),
- explicitly define 404 vs 403 semantics:
  - non-member / not entitled to tenant scope → 404 (deny-as-not-found)
  - member but missing capability → 403
- describe how authorization is enforced server-side (Gates/Policies) for every mutation/operation-start/credential change,
- reference the canonical capability registry (no raw capability strings; no role-string checks in feature code),
- ensure global search is tenant-scoped and non-member-safe (no hints; inaccessible results treated as 404 semantics),
- ensure destructive-like actions require confirmation (`->requiresConfirmation()`),
- include at least one positive and one negative authorization test, and note any RBAC regression tests added/updated.

**Constitution alignment (OPS-EX-AUTH-001):** OIDC/SAML login handshakes may perform synchronous outbound HTTP (e.g., token exchange)
on `/auth/*` endpoints without an `OperationRun`. This MUST NOT be used for Monitoring/Operations pages.

**Constitution alignment (BADGE-001):** If this feature changes status-like badges (status/outcome/severity/risk/availability/boolean),
the spec MUST describe how badge semantics stay centralized (no ad-hoc mappings) and which tests cover any new/changed values.

**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.
If the contract is not satisfied, the spec MUST include an explicit exemption with rationale.

<!--
  ACTION REQUIRED: The content in this section represents placeholders.
  Fill them out with the right functional requirements.
-->

### Functional Requirements

- **FR-001**: System MUST provide a single, unified verification start mechanism used by both the tenant detail “Verify configuration” and onboarding “Verify access” surfaces.
- **FR-002**: Starting verification MUST create (or dedupe to) a single “verification run” record for the target, and surface a stable link to view that run.
- **FR-003**: When a verification run cannot proceed due to missing prerequisites, the system MUST finalize the run as completed “blocked” and persist a schema-valid stub/preflight verification report.
- **DB-only render invariant**: Verification viewers are read-only projections of persisted run/report data; they MUST NOT perform provider/Graph calls and MUST NOT persist permission inventory updates.
- **FR-004**: For any verification run that is completed (including blocked), the embedded/onboarding viewers MUST render the verification report using stored data only.
- **FR-004a**: The tenant detail embedded viewer MUST select the latest verification run attempt for the tenant and verification type; if that run is active (queued/running) and no report is yet available, the UI MUST render a DB-only “in progress” state.
- **FR-004b**: If no verification run exists yet for the tenant and verification type, the tenant detail embedded section MUST show a DB-only empty state with a “Start verification” CTA.
- **FR-005**: UI page rendering (including mount/load/summary components) MUST NOT trigger external provider calls directly or indirectly.
- **FR-006**: Dedupe rules MUST ensure at most one active run (queued/running) exists per target and verification type; repeated starts during an active run MUST return a busy/deduped outcome.
- **FR-007**: The system MUST persist any permissions inventory updates only as part of the verification job’s execution, and MUST NOT persist these updates during page rendering.
- **FR-008**: All “View run” links exposed by verification surfaces MUST use the canonical tenantless run viewer route.
- **FR-009**: Authorization MUST be enforced server-side:
  - missing workspace membership OR missing tenant entitlement MUST be deny-as-not-found (404) for tenant-scoped routes/actions and tenantless canonical views of tenant-associated records,
  - members lacking the required capability to start verification MUST see the action visible-but-disabled with helper text, and MUST receive a forbidden response (403) if invoked.
- **FR-010**: The system MUST emit run observability sufficient for operations (run type, outcome, timestamps, target scope) and MUST be test-covered.

### Assumptions & Dependencies

- This change unifies surfaces and report availability; it does not expand the set of verification checks beyond what is already produced today.
- For tenant verification surfaces (`ViewTenant` header action, tenant embedded CTA, and tenant list verify action), “eligible provider connection” means the resolved **default** provider connection for provider `microsoft`.
- Onboarding verification continues to use the session-selected provider connection, and still runs through the same unified operation type and run orchestration.
- Verification reports are stored with the verification run record and are treated as the sole source for UI rendering.
- External provider calls are permitted only as part of explicit user-triggered verification runs and their execution (never during page rendering).
- Existing authorization capabilities and membership rules remain the source of truth; this feature standardizes how they apply across surfaces.

## UI Action Matrix *(mandatory when Filament is changed)*

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?),
RBAC gating (capability + enforcement helper), and whether the mutation writes an audit log.

| 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 |
|---|---|---|---|---|---|---|---|---|---|---|
| Tenant detail view | Tenant admin area | Verify configuration | Embedded viewer + View run link | n/a | n/a | Start verification (empty state) | n/a | n/a | Yes | DB-only render; starts/dupes run; if missing capability: visible but disabled with helper |
| Tenant list (Tenants table) | Tenant admin area | n/a | Clickable row + View action | Verify configuration (grouped action) | grouped | n/a | n/a | n/a | Yes | Uses same unified start path and canonical run links as tenant detail |
| Onboarding verification step | Onboarding wizard | Start verification | Embedded viewer + View run link | n/a | n/a | n/a | n/a | n/a | Yes | Same semantics as tenant surface |
| Tenantless run viewer | Operations area | n/a | n/a | n/a | n/a | n/a | n/a | n/a | Yes | Requires workspace membership + tenant entitlement; otherwise 404 |

### Key Entities *(include if feature involves data)*

- **Verification Run**: An immutable operational record representing one attempt to verify access/configuration for a target scope. It captures status/outcome and a canonical link for viewing.
- **Verification Report**: A schema-valid, stored report attached to a verification run. It is always present for completed runs, including blocked runs (stub/preflight).

## Success Criteria *(mandatory)*
### Measurable Outcomes

- **SC-001**: 100% of completed blocked verification runs display a usable stub report (no "report unavailable" state for completed blocked runs).
- **SC-002**: Tenant detail pages render without any external provider calls; verification-related external calls occur only after an explicit start action.
- **SC-003**: When a verification run is already active for the same target and type, repeated starts return a busy/deduped response in under 1 second.
- **SC-004**: All verification surfaces provide a canonical "View run" link, and support can use that single URL to review outcomes.
