TenantAtlas/specs/283-provider-capability-registry/spec.md
ahmido 1debe40ced feat: implement provider capability registry (#342)
## Summary
- implement the provider capability registry and derived capability evaluation flow
- update provider connections, onboarding, required-permissions diagnostics, and provider blocker translation to use capability-first summaries
- add bounded unit, feature, and browser test coverage plus the prepared Spec 283 artifacts

## Notes
- branch: `283-provider-capability-registry`
- commit: `74e75c3e`
- no additional validation commands were run in this git/PR flow step

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #342
2026-05-08 21:17:05 +00:00

372 lines
48 KiB
Markdown

# Feature Specification: Provider Capability Registry
**Feature Branch**: `283-provider-capability-registry`
**Created**: 2026-05-08
**Status**: Ready
**Input**: User description: "Use the next-best-prep workflow with explicit manual promotion for reserved slot `283` and prepare the `Provider Capability Registry v1` package without implementing application code."
## Spec Candidate Check
- **Problem**: TenantPilot already has provider connection health checks, required-permissions diagnostics, onboarding verification clusters, blocked provider-operation outcomes, and support guidance, but those seams still describe the same provider requirement truth in different ways. Operators see Microsoft Graph permission names, cluster titles, reason codes, and blocked-operation prose without one provider-neutral capability contract that says which workflow is actually supported for the current managed environment.
- **Today's failure**: `ProviderOperationStartGate`, `ProviderReasonTranslator`, `TenantPermissionCheckClusters`, `TenantRequiredPermissions`, `ManagedTenantOnboardingWizard`, and `ProviderConnectionResource` all expose permission or prerequisite truth, but the platform still lacks one business-facing capability layer above those details. The same missing grant can read as a raw Graph permission on one surface, an Intune RBAC blocker on another, and a generic provider failure in run context.
- **User-visible improvement**: Operators get one stable capability vocabulary for provider-backed workflows such as provider connection checks, inventory sync, compliance snapshot, restore execution, directory group sync, and directory role-definition sync. Provider-specific remediation hints and raw Graph permission names remain available, but they become secondary evidence instead of primary operator truth.
- **Smallest enterprise-capable version**: Introduce one derived provider capability registry and evaluation layer over the current provider connection, permission-cluster, onboarding, and provider-operation seams. Reuse the existing required-permissions page, provider-connections resource, onboarding wizard, provider reason translation, and operation-start gate. Do not add a provider-capability table, no new RBAC capability family, no new provider implementation, and no generic workflow engine.
- **Explicit non-goals**: No new persisted provider-capability ledger, no dedicated provider-profile table, no user RBAC rewrite, no broader provider-neutral artifact taxonomy, no routing cutover from Spec `280`, no provider-connection identity extraction from Spec `281`, no copy or localization neutralization from Spec `286`, no no-legacy enforcement pack from Spec `287`, and no AWS, Google, or Okta provider implementation.
- **Permanent complexity imported**: One bounded registry of provider capability definitions, one derived capability-status family, one evaluator or presenter path that maps existing permission and provider-state truth to capability results, and focused unit, feature, and browser proof. No new persisted truth is imported.
- **Why now**: The workspace-first cutover pack already moved core environment identity in Spec `279`, prepared the route shell in Spec `280`, and prepared provider identity or target-scope neutralization in Spec `281`. The next remaining provider boundary gap is workflow capability truth. Without it, later artifact taxonomy, copy, and quality-gate work would still inherit raw Microsoft permission language and ad hoc prerequisite logic.
- **Why not local**: The gap is shared. A page-local rename on provider-connections or onboarding would leave `ProviderOperationStartGate`, support diagnostics, blocked-operation messaging, and the required-permissions diagnostic matrix out of sync. The capability contract has to sit above the current shared seams, not inside one UI page.
- **Approval class**: Core Enterprise
- **Red flags triggered**: New abstraction, new derived state family, and a cross-cutting interaction contract. Defense: current repo truth already has multiple consumers and multiple conflicting explanations for the same provider prerequisite state. One bounded registry plus evaluator is the narrowest correct answer and explicitly rejects new persistence, a provider framework, or wider cutover work.
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 2 | Wiederverwendung: 2 | **Gesamt: 11/12**
- **Decision**: approve
## Spec Scope Fields
- **Scope**: workspace
- **Primary Routes**:
- `/admin/provider-connections`
- `/admin/provider-connections/{record}`
- `/admin/provider-connections/{record}/edit`
- `/admin/workspaces/{workspace}/environments/{managed_environment}/required-permissions`
- named onboarding routes `admin.onboarding` and `admin.onboarding.draft`
- provider-backed start actions that already enqueue `provider.connection.check`, `inventory.sync`, `compliance.snapshot`, `restore.execute`, `directory.groups.sync`, and `directory.role_definitions.sync`
- **Data Ownership**:
- `ProviderConnection` remains the existing workspace-owned, managed-environment-scoped binding record
- current required-permissions snapshots, provider verification state, consent state, and operation-start context remain the underlying source inputs
- provider capability definitions and evaluated capability results remain derived runtime truth in this slice and MUST NOT create a new persisted table or artifact
- `OperationRun` remains execution truth and may carry derived capability context, but not a second persisted capability ledger
- **RBAC**:
- workspace membership remains the first access boundary
- managed-environment entitlement remains the second access boundary
- existing user capability gates such as `PROVIDER_VIEW`, `PROVIDER_MANAGE`, `PROVIDER_MANAGE_DEDICATED`, `PROVIDER_RUN`, `TENANT_MANAGE`, and `TENANT_SYNC` remain unchanged and MUST NOT be conflated with provider application capabilities
## Canonical Initial Capability Inventory
The initial provider capability registry is intentionally limited to current repo workflows only.
| Capability Key | Operator Label | Current Operation Types | Initial Provider Requirement Keys |
|---|---|---|---|
| `provider_connection_check` | Provider connection check | `provider.connection.check` | `permissions.admin_consent` |
| `inventory_read` | Inventory read | `inventory.sync` | `permissions.intune_configuration`, `permissions.intune_apps` |
| `configuration_read` | Configuration read | `compliance.snapshot` | `permissions.intune_configuration` |
| `restore_execute` | Restore execute | `restore.execute` | `permissions.intune_configuration`, `permissions.intune_rbac_assignments` |
| `directory_groups_read` | Directory groups read | `directory.groups.sync` | `permissions.directory_groups` |
| `directory_role_definitions_read` | Directory role definitions read | `directory.role_definitions.sync` | `provider.directory_role_definitions`, `permissions.admin_consent` |
This bounded inventory is authoritative for Spec `283`. Any broader capability family belongs to follow-up work and MUST NOT be added silently in this slice.
Capability evaluation may additionally inspect provider connection lifecycle, consent, and verification state when resolving `blocked`, `unknown`, or `supported`, but those state inputs are not promoted into new top-level requirement keys.
## Cross-Cutting / Shared Pattern Reuse
- **Cross-cutting feature?**: yes
- **Interaction class(es)**: status messaging, blocked-operation guidance, onboarding readiness summaries, provider-connection summaries, required-permissions diagnostics, related links, and support-diagnostic translations
- **Systems touched**:
- `ProviderOperationRegistry`
- `ProviderOperationStartGate`
- `ProviderReasonTranslator`
- `ProviderNextStepsRegistry`
- `TenantPermissionCheckClusters`
- `TenantRequiredPermissionsViewModelBuilder`
- `TenantRequiredPermissions`
- `ManagedTenantOnboardingWizard`
- `ProviderConnectionResource`
- `RequiredPermissionsLinks`
- contextual-help and support-diagnostic consumers of provider reason translation
- **Existing pattern(s) to extend**: required-permissions diagnostics, provider reason translation, provider-operation start gating, provider-connection surface summaries, and onboarding verification assists
- **Shared contract / presenter / builder / renderer to reuse**: `ProviderOperationRegistry`, `ProviderOperationStartGate`, `ProviderReasonTranslator`, `TenantPermissionCheckClusters`, `TenantRequiredPermissionsViewModelBuilder`, `ProviderConnectionSurfaceSummary`, `RequiredPermissionsLinks`, and the existing Filament resource or page surface contracts
- **Why the existing shared path is sufficient or insufficient**: the existing seams already gather the right provider, permission, and workflow evidence. What is insufficient is that each seam names or groups that evidence differently. The feature should normalize those consumers around one capability contract, not build another workflow surface.
- **Allowed deviation and why**: none. Provider-specific remediation detail may remain nested inside provider-owned help, consent, or permission evidence, but that is part of the shared contract design rather than a surface-level exception.
- **Consistency impact**: provider-connections, onboarding, required-permissions diagnostics, blocked-operation messaging, contextual help, and support diagnostics must all use the same capability key, status, and primary explanation before showing provider-specific raw permission detail.
- **Review focus**: reviewers must verify that no second mapping path survives on onboarding, provider-connections, or required-permissions summaries; that capability results remain derived; and that raw Graph permission names are demoted to secondary evidence rather than primary operator truth.
## OperationRun UX Impact
- **Touches OperationRun start/completion/link UX?**: yes
- **Shared OperationRun UX contract/layer reused**: `ProviderOperationStartGate`, `ProviderOperationStartResultPresenter`, `OperationUxPresenter`, `ProviderReasonTranslator`, and the existing `OperationRunService` lifecycle path
- **Delegated start/completion UX behaviors**: blocked-versus-started outcomes, queued intent messaging, run link generation, provider-specific remediation guidance, dedupe-or-busy behavior, and provider-safe URL resolution stay on the existing shared start path
- **Local surface-owned behavior that remains**: `ProviderConnectionResource` and `ManagedTenantOnboardingWizard` keep only initiation inputs, summary placement, and capability-assist entry points
- **Queued DB-notification policy**: `N/A` - unchanged shared policy
- **Terminal notification path**: existing central lifecycle mechanism
- **Exception required?**: none
## Provider Boundary / Platform Core Check
- **Shared provider/platform boundary touched?**: yes
- **Boundary classification**: mixed
- **Seams affected**:
- platform-core: provider capability definitions, capability evaluation, operation-to-capability mapping, blocked-operation context, shared reason translation labels, shared required-permissions grouping
- provider-owned: Microsoft Graph permission names, consent URLs, admin portal links, Intune RBAC remediation details, and provider-specific troubleshooting hints
- mixed UI bridge: provider-connections, onboarding readiness, required-permissions diagnostics, and support guidance
- **Neutral platform terms preserved or introduced**: `provider capability`, `capability key`, `capability status`, `target workflow`, `provider requirement`, `provider connection`, `managed environment`, `required capability`, and `remediation hint`
- **Provider-specific semantics retained and why**: raw Graph permission names, Intune RBAC-specific prerequisite text, consent steps, and required-permissions URLs remain necessary for the current Microsoft provider implementation and operator troubleshooting. They stay nested under provider-owned remediation or evidence sections rather than defining the shared capability vocabulary.
- **Why this does not deepen provider coupling accidentally**: the slice moves the shared operator contract away from raw Graph permission names and cluster-specific labels. Provider-specific details remain explicit nested evidence and do not define the platform-core capability keys.
- **Follow-up path**: Spec `284` for broader provider-neutral artifact taxonomy, Spec `285` for workspace-first RBAC scoping, Spec `286` for broader copy neutralization, and Spec `287` for no-legacy enforcement
## UI / Surface Guardrail Impact
| Surface / Change | Operator-facing surface change? | Native vs Custom | Shared-Family Relevance | State Layers Touched | Exception Needed? | Low-Impact / `N/A` Note |
|---|---|---|---|---|---|---|
| Provider connections resource family | yes | Native Filament resource plus shared summary helpers | provider summary, blocked guidance, operation entry points | page, table, detail, modal, Livewire state | no | Reuses the existing resource and action family; the slice changes the summary and prerequisite contract only |
| Onboarding provider readiness and capability assist | yes | Native Filament custom wizard using existing onboarding shell | readiness summary, assist modal, supporting links | page, wizard, session, Livewire state | no | Reuses the current onboarding shell and required-permissions assist instead of creating a new workflow page |
| Required permissions diagnostic page | yes | Native Filament page with inline diagnostic matrix | diagnostic grouping, supporting links, filter state | page, table, URL-query | no | Keeps the page diagnostic-first and read-only; capability group headings and summary become the new primary explanation layer |
## Decision-First Surface Role
| Surface | Decision Role | Human-in-the-loop Moment | Immediately Visible for First Decision | On-Demand Detail / Evidence | Why This Is Primary or Why Not | Workflow Alignment | Attention-load Reduction |
|---|---|---|---|---|---|---|---|
| Provider connections resource family | Primary Decision Surface | Operator decides whether one provider connection is ready for the target workflow | provider, target workflow capability status, blocking reason, one next action | consent detail, raw Graph permissions, provider profile detail, and run follow-up stay secondary | Primary because this is where operators decide whether the connection is usable now | Matches the existing integrations workflow | Removes the need to reconstruct readiness from separate permission pages and blocked-operation prose |
| Onboarding provider readiness and capability assist | Primary Decision Surface | Operator decides whether onboarding can continue or whether one capability blocker must be resolved first | selected connection, missing capability, one recommended next step | detailed permission matrix, provider-specific remediation, and support detail stay secondary | Primary because onboarding cannot continue safely until the capability gap is understood | Keeps the decision inside the existing onboarding flow | Prevents operators from leaving onboarding just to decode provider prerequisites |
| Required permissions diagnostic page | Secondary Context Surface | Operator validates why a capability is missing and which exact grants or provider requirements back that result | capability group status, freshness, one next diagnostic or remediation action | raw Graph permission keys, cluster rows, and provider-specific detail stay deeper in the matrix | Secondary because it proves and explains an already identified blocker instead of owning the first workflow decision | Preserves the page as the canonical diagnostic deep dive | Prevents every other surface from duplicating the full permission matrix |
## Audience-Aware Disclosure
| Surface | Audience Modes In Scope | Decision-First Default-Visible Content | Operator Diagnostics | Support / Raw Evidence | One Dominant Next Action | Hidden / Gated By Default | Duplicate-Truth Prevention |
|---|---|---|---|---|---|---|---|
| Provider connections resource family | operator-MSP, support-platform | capability label, status, blocking reason, next action, target scope | consent posture, verification freshness, provider check outcome | raw Graph permission names, portal links, provider profile identifiers | `Check connection`, `Open required permissions`, or existing primary provider action depending on status | provider-specific profile detail and raw permission lists stay nested | the detail page explains the blocker once through capability language and uses nested evidence for the rest |
| Onboarding provider readiness and capability assist | operator-MSP, support-platform | selected connection, missing capability, short explanation, continue-or-fix decision | capability freshness, blocked reason, readiness details | raw permission list, provider-specific remediation, support detail | `Open required permissions` or `Continue` depending on status | provider-specific details stay in the assist modal or downstream page | onboarding uses the same capability labels as provider-connections rather than a second vocabulary |
| Required permissions diagnostic page | operator-MSP, support-platform | capability groups, group status, freshness, top-level explanation | grouped permission rows, cluster-specific evidence, verification timing | raw provider-specific links and technical detail stay lower in the page | `Re-run verification` or `Manage provider connection` depending on state | raw permission rows stay below the capability summary, not in the header | the page introduces capability truth once, then uses the row matrix as supporting evidence |
## UI/UX Surface Classification
| Surface | Action Surface Class | Surface Type | Likely Next Operator Action | 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 / Justification |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Provider connections resource family | List / Detail / Integrations | CRUD / List-first Resource | Open one connection, verify it, or inspect the missing capability | clickable row to View | required | grouped under `More` plus the existing primary view/header affordances | grouped under `More` and confirmation-protected where dangerous | `/admin/provider-connections` | `/admin/provider-connections/{record}` and `/admin/provider-connections/{record}/edit` | workspace context, managed environment filter, provider, target scope | Provider connection | target workflow capability and blocking state | none |
| Onboarding provider readiness and capability assist | Workflow Hub / Wizard / Readiness | workflow-step selector plus diagnostic assist | resolve the missing capability or continue onboarding | in-step selection and explicit assist action | forbidden | supporting links and secondary diagnostics stay in the assist modal or helper area | none introduced by this slice | named onboarding routes `admin.onboarding` and `admin.onboarding.draft` | same wizard step or draft route | current workspace, current managed environment, selected provider connection | Provider capability | missing capability and one next step | none |
| Required permissions diagnostic page | List / Diagnostic / Read-only | diagnostic matrix page | inspect the capability group that explains the blocker | inline grouped matrix, not a second detail page | forbidden | filter reset, copy flows, and supporting links stay inside the page body | none | `/admin/workspaces/{workspace}/environments/{managed_environment}/required-permissions` | same page | current workspace, current managed environment | Required permissions / Provider capability | capability group status and freshness | existing page-level action-surface exemptions remain valid |
## Operator Surface Contract
| Surface | Primary Persona | Decision / Operator Action Supported | Surface Type | Primary Operator Question | Default-visible Information | Diagnostics-only Information | Status Dimensions Used | Mutation Scope | Primary Actions | Dangerous Actions |
|---|---|---|---|---|---|---|---|---|---|---|
| Provider connections resource family | Workspace operator | Decide whether this provider connection is ready for the workflow they want to run | List/detail integration resource | Is this provider connection capable of running the workflow I need? | capability status, target workflow, target scope, short reason, one next step | consent detail, raw permissions, provider profile detail, run history | capability status, verification freshness, consent posture, lifecycle | `TenantPilot only` for connection metadata changes; provider operations keep their existing mutation scope semantics | Open, Check connection, Open required permissions, existing provider actions | existing dangerous provider-connection mutations only |
| Onboarding provider readiness and capability assist | Workspace operator | Decide whether onboarding can continue or which prerequisite must be resolved first | Wizard step plus assist modal | What exact provider capability blocks activation or the selected bootstrap action? | selected connection, missing capability, short explanation, one next step | grouped permission evidence, provider-specific remediation, support detail | capability status, readiness, freshness | onboarding draft state only | Continue, Open required permissions, Create or manage connection | none introduced by this slice |
| Required permissions diagnostic page | Workspace operator | Decide which provider requirement must be fixed after a capability blocker is identified | Read-only diagnostic matrix | Which exact requirement backs the missing capability, and what should I do next? | capability group heading, status, freshness, summary counts | raw permission rows, provider-specific links, technical details | capability status, row-level permission presence, freshness | none | Re-run verification, Manage provider connection, Clear filters | none |
## Proportionality Review
- **New source of truth?**: no
- **New persisted entity/table/artifact?**: no
- **New abstraction?**: yes
- **New enum/state/reason family?**: yes, one bounded derived capability-status family (`supported`, `missing`, `blocked`, `unknown`, `not_applicable`)
- **New cross-domain UI framework/taxonomy?**: no
- **Current operator problem**: provider-backed workflows already depend on permission and provider-precondition truth, but that truth is fragmented across required-permissions diagnostics, onboarding readiness, provider-connection summaries, and blocked-operation messaging.
- **Existing structure is insufficient because**: current structures only describe low-level permission rows, provider connection verification state, or one blocked reason at a time. They do not give operators one stable workflow-capability answer across shared surfaces.
- **Narrowest correct implementation**: one bounded provider capability registry and one derived evaluator over the existing provider connection, permission-cluster, and operation-start seams, with no new persistence and no wider provider framework.
- **Ownership cost**: maintain capability definitions, status mapping, provider-owned remediation evidence, and test alignment across multiple consumers. That cost is contained because all consumers already exist.
- **Alternative intentionally rejected**: page-local labels, a new persisted provider-capability ledger, or a generalized multi-provider policy engine. The first option leaves current drift intact, and the latter two import complexity without a current-release need.
- **Release truth**: current-release truth
### External implementation prerequisite
Spec `281` must already be merged or otherwise present on the implementation branch before `283` runtime work begins. The capability registry is intentionally layered on the provider-neutral target-scope and provider-identity contract prepared there.
### Compatibility posture
This feature assumes a pre-production environment.
Backward compatibility, legacy aliases, migration shims, historical fixtures, and compatibility-specific tests are out of scope unless explicitly required by this spec.
Canonical replacement is preferred over preservation.
## Testing / Lane / Runtime Impact
- **Test purpose / classification**: Unit, Feature, Browser
- **Validation lane(s)**: fast-feedback, confidence, browser
- **Why this classification and these lanes are sufficient**: the registry and evaluator logic are pure derivation and deserve unit proof. Shared blocked-operation, onboarding, provider-connection, and required-permissions behavior need feature coverage, and one browser smoke proves the real operator path from provider connection or onboarding into the capability assist without inventing a broad browser suite.
- **New or expanded test families**: one provider-capability registry unit family, one provider-capability evaluation feature family, one provider-operation capability-gate feature family, one provider-connections summary feature family, one onboarding capability-assist feature family, one required-permissions capability-grouping feature family, and one narrow browser smoke
- **Fixture / helper cost impact**: moderate; proof needs workspace, managed environment, provider connection, permission snapshot or verification data, and representative blocked-operation context without widening shared fixture defaults
- **Heavy-family visibility / justification**: one browser smoke only; no heavy-governance family is justified
- **Special surface test profile**: standard-native-filament, workflow-hub, shared-detail-family
- **Standard-native relief or required special coverage**: standard Filament feature coverage is sufficient for provider-connections and the required-permissions page; onboarding still needs one workflow-hub smoke because the feature crosses wizard state and assist flow
- **Reviewer handoff**: reviewers must verify that capability results remain derived, that no provider-capability table or ledger appears, that `ProviderConnectionResource` stays non-globally-searchable with View and Edit pages intact, that existing destructive actions keep confirmation plus server authorization, that provider registration stays in `apps/platform/bootstrap/providers.php`, that Filament stays v5 on Livewire v4, and that provider-specific raw permission names remain secondary evidence rather than primary capability labels
- **Budget / baseline / trend impact**: contained feature-local increase only
- **Escalation needed**: none
- **Active feature PR close-out entry**: Guardrail
- **Planned validation commands**:
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Unit/Providers/ProviderCapabilityRegistryTest.php tests/Unit/Verification/TenantPermissionCapabilityMappingTest.php)`
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Feature/Providers/ProviderCapabilityEvaluationTest.php tests/Feature/Providers/ProviderOperationCapabilityGateTest.php tests/Feature/Filament/ProviderConnectionCapabilitySummaryTest.php tests/Feature/Onboarding/ManagedTenantOnboardingCapabilityAssistTest.php tests/Feature/RequiredPermissions/RequiredPermissionsCapabilityGroupingTest.php tests/Feature/SupportDiagnostics/ProviderCapabilityReasonTranslationTest.php)`
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Browser/Spec283ProviderCapabilityRegistrySmokeTest.php)`
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail bin pint --dirty --format agent)`
## Candidate Selection Gate Summary
- **Selected candidate**: `283 - Provider Capability Registry v1`
- **Source locations**:
- `docs/product/spec-candidates.md` under the reserved workspace-first / managed-environment cutover pack
- `docs/product/roadmap.md` under the same pack ordering
- **Why selected now**: the active queue is manual-promotion-only, and the user explicitly requested reserved slot `283`. Repo truth confirms that the remaining unspecced gap at this slot is workflow capability truth above the already-prepared provider-connection and target-scope seams.
- **Why close alternatives were deferred**:
- `282` already exists as a separate prepared package for governance artifact retargeting and must not be overwritten
- `284` depends on a stable capability contract and belongs to broader artifact-source taxonomy work
- `285` is about user or environment access scoping, not provider application capability truth
- `286` should follow concrete capability labels rather than invent them through copy-first work
- `287` should harden the finished cutover slices instead of expanding `283`
- **Smallest viable implementation slice**: one derived provider capability registry and evaluation path reused by provider-connections, onboarding, required-permissions diagnostics, blocked-operation translation, and shared provider-operation gating
- **Documented deviations from raw candidate wording**:
- the raw candidate proposed persisted fields such as `provider_capability_key`, `status`, `reason_code`, `provider_requirement_key`, `last_checked_at`, and `metadata`; repo truth narrows this to a derived runtime contract with no new table or independent artifact
- the raw candidate listed broader future-facing example keys such as `identity_access_policy_read`, `evidence_snapshot_write`, and `review_publish`; the current-release slice narrows keys to workflows already present in repo truth
- repo truth already routes provider-start blocking through `ProviderOperationStartGate`, `ProviderReasonTranslator`, and required-permissions diagnostics, so this package standardizes the capability layer above those seams instead of pretending raw Microsoft permission constants are checked directly everywhere
## Completed-Spec Guardrail Result
- `specs/279-workspace-managed-environment-core/` already exists with implementation-close-out history and remains historical prerequisite context only
- `specs/280-workspace-tenancy-environment-routing/` already exists as an adjacent prepared package and remains separate
- `specs/281-provider-connection-scope/` already exists with completed implementation-task markers and remains completed or historical context only; it is not modified by this package
- `specs/282-governance-artifact-retargeting/` already exists as a separate prepared package and is not modified by this package
- the target package `specs/283-provider-capability-registry/` did not exist before this prep run and is the sole new package created here
## Deferred Adjacent Candidates
- `284 - Provider-neutral Artifact Source Taxonomy v1`
- `285 - Workspace-first RBAC & Environment Access Scoping`
- `286 - UI Copy, IA & Localization Neutralization`
- `287 - Cutover Quality Gates & No-Legacy Enforcement`
## User Scenarios & Testing
### User Story 1 - See one provider capability summary before running work (Priority: P1)
As an operator, I want the provider-connections resource to show whether the selected connection supports the workflow I care about without forcing me to decode raw Graph permission names or provider error detail first.
**Why this priority**: this is the first operator-facing decision seam for provider-backed work. If it stays Microsoft-permission-first, the registry does not solve the actual workflow problem.
**Independent Test**: open one provider-connection detail page and confirm the default-visible summary shows the target workflow capability, current status, and one next step while raw provider details stay secondary.
**Acceptance Scenarios**:
1. **Given** a provider connection lacks one or more required prerequisites for `inventory.sync`, **When** the operator opens the connection detail page, **Then** the page shows `Inventory read` or the equivalent workflow capability as missing and offers the correct next step without leading with raw Graph permission names.
2. **Given** a provider connection satisfies the requirements for `provider.connection.check`, **When** the operator opens the connection detail page, **Then** the page shows the capability as supported and does not invent a second identity or capability vocabulary.
---
### User Story 2 - Block or start provider operations with the same capability contract (Priority: P1)
As an operator, I want provider-backed operations to block or start using the same capability keys shown on provider-connections and onboarding so the run outcome and the UI explain the same prerequisite truth.
**Why this priority**: `ProviderOperationStartGate` is the shared execution seam. If it stays on raw permission or reason-only language, later UI consistency will still drift.
**Independent Test**: attempt one blocked provider-backed operation and one allowed provider-backed operation, then confirm both the start outcome and any created run context use the capability key or capability summary rather than raw provider permission terms as primary truth.
**Acceptance Scenarios**:
1. **Given** the current managed environment is missing the capability needed for `directory.groups.sync`, **When** the operator triggers that action, **Then** the blocked result identifies the missing directory-groups capability and links to the required-permissions diagnostic path.
2. **Given** the current managed environment satisfies the capability for `provider.connection.check`, **When** the operator triggers the action, **Then** the shared start path records the capability context and starts the run without inventing a second capability explanation.
---
### User Story 3 - Read the same capability truth inside onboarding and required-permissions diagnostics (Priority: P2)
As an operator, I want onboarding verification and the required-permissions page to use the same workflow capability labels so I can move between the quick summary and the diagnostic evidence without reinterpreting the blocker.
**Why this priority**: onboarding and the required-permissions page already exist and already talk about the same prerequisites. A capability registry only matters if those two surfaces converge.
**Independent Test**: open onboarding verification for a managed environment with missing prerequisites, then open the required-permissions assist and confirm both surfaces use the same capability labels and status meanings.
**Acceptance Scenarios**:
1. **Given** onboarding shows a missing prerequisite for a selected bootstrap action, **When** the operator opens the capability assist, **Then** the assist uses the same capability label and status shown on the required-permissions page.
2. **Given** the required-permissions page groups raw permission rows under one capability heading, **When** the operator returns to onboarding, **Then** onboarding preserves that same capability label as the primary explanation and keeps the row-level detail secondary.
---
### User Story 4 - Translate provider blockers consistently in diagnostics and support surfaces (Priority: P3)
As an operator or support user, I want provider blocker messages and contextual help to name the missing capability first and keep the raw provider requirement detail as supporting evidence so supportability stays consistent across surfaces.
**Why this priority**: the repo already has shared product knowledge and support-diagnostic seams for provider blockers. Leaving those seams on raw permission-first language would keep one of the biggest explanation drifts alive.
**Independent Test**: trigger or simulate a provider blocker caused by missing permissions, then inspect shared help or support-diagnostic output and confirm it uses the same capability vocabulary as the main surfaces.
**Acceptance Scenarios**:
1. **Given** a provider blocker maps to missing Intune RBAC or Graph permissions, **When** contextual help or support diagnostics render the explanation, **Then** they name the missing capability first and keep the required-permissions link plus raw details secondary.
2. **Given** the capability is `unknown` because the permission snapshot is stale or absent, **When** diagnostics render, **Then** the message names the capability state as unknown or stale rather than pretending the capability is definitely missing.
### Edge Cases
- A capability with no current provider binding or no mapped provider requirements must resolve as `not_applicable` rather than `missing`.
- A stale or absent permission snapshot must resolve as `unknown` and must not silently downgrade into a false missing-permission blocker.
- A workflow that depends on both provider permissions and connection-state preconditions must distinguish `missing` from `blocked` instead of collapsing both into one generic failure.
- A provider connection that is disabled, review-required, or consent-revoked must still evaluate capabilities deterministically and surface the connection-state blocker alongside the capability key.
- If multiple capability keys map to the same raw Graph permission row, the system must avoid duplicate top-level blocker cards while still preserving full evidence on the diagnostic page.
- Existing user RBAC capability denials must remain distinct from provider application capability failures and must not be translated through the provider-capability registry.
## Requirements
**Constitution alignment (required):** This slice changes provider-operation gating, provider-connection summaries, onboarding verification assists, required-permissions diagnostics, and shared provider reason translation. It does not add new Graph contract registry entries, new provider implementations, or a new long-running workflow type.
**Constitution alignment (PROP-001 / ABSTR-001 / PROV-001 / BLOAT-001):** The new registry is justified only because the repo already has multiple real consumers and conflicting explanations for the same provider prerequisite truth. No new table, no provider framework, and no broader taxonomy work are in scope.
**Constitution alignment (XCUT-001 / UI-FIL-001 / DECIDE-001):** The feature must reuse `ProviderConnectionResource`, `ManagedTenantOnboardingWizard`, `TenantRequiredPermissions`, and the existing provider-operation start path. It may refine summary and diagnostic language, but it must not create a new provider dashboard, a second required-permissions page, or local status styling.
**Constitution alignment (RBAC-UX):** Workspace and managed-environment membership remain the route boundaries. Existing user capability checks remain server-authorized and distinct from provider application capability evaluation.
**Constitution alignment (TEST-GOV-001 / OPS-UX-START-001):** Proof stays bounded to unit, feature, and one narrow browser smoke. The operation-start path must keep using the shared start gate or presenter contract, with capability evaluation added as shared prerequisite logic instead of feature-local branching.
### Functional Requirements
- **FR-001**: The system MUST introduce one shared provider capability registry that defines business-facing capability keys for workflows already present in repo truth.
- **FR-002**: The initial capability-key inventory MUST stay bounded to current repo workflows and diagnostics and MUST NOT speculate about future provider workflows that are not yet implemented.
- **FR-003**: The initial capability-key inventory MUST cover, at minimum, provider connection checks, inventory sync, compliance snapshot, restore execution, directory group sync, and directory role-definition sync.
- **FR-004**: Capability evaluation MUST remain derived from existing provider connection state, consent state, verification state, required-permissions evidence, and provider-specific requirement mappings; it MUST NOT introduce a provider-capability table or independent persisted artifact.
- **FR-005**: Capability evaluation MUST emit a stable capability status family with the values `supported`, `missing`, `blocked`, `unknown`, and `not_applicable`.
- **FR-006**: Capability evaluation MUST also emit a stable capability key, one provider-owned remediation-hint path, and the provider requirement keys or evidence used to justify the result.
- **FR-007**: Existing provider reason codes remain the blocking reason truth where applicable; the capability contract MUST nest or reference those reason codes rather than creating a second broad reason-code family.
- **FR-008**: `ProviderOperationRegistry` MUST map each current provider-backed operation type to one or more provider capability keys instead of leaving workflow prerequisite semantics implicit.
- **FR-009**: `ProviderOperationStartGate` MUST evaluate required provider capability keys before dispatch and MUST block or start using the shared capability result instead of relying on raw permission language as primary truth.
- **FR-010**: Any created or blocked `OperationRun` context from the touched provider-operation start path MUST include the relevant capability key or capability summary as shared context and MUST keep raw provider requirement details nested as secondary evidence only.
- **FR-011**: `ProviderConnectionResource` MUST show provider capability summaries on its list, view, and edit-adjacent detail surfaces using the shared capability contract.
- **FR-012**: `ProviderConnectionResource` MUST remain non-globally-searchable in this slice and MUST keep its existing View and Edit pages as the canonical inspect destinations.
- **FR-013**: `ManagedTenantOnboardingWizard` MUST use the shared provider capability contract to describe blocked bootstrap actions, readiness, and the required-permissions assist.
- **FR-014**: `TenantRequiredPermissions` and `TenantRequiredPermissionsViewModelBuilder` MUST group or summarize raw permission rows under the shared provider capability contract so the diagnostic page proves the same blocker described by provider-connections and onboarding.
- **FR-015**: `ProviderReasonTranslator`, `ProviderNextStepsRegistry`, and any touched contextual-help or support-diagnostic consumers MUST translate missing-permission and similar provider blockers through the shared capability vocabulary first and keep provider-specific raw requirement detail second.
- **FR-016**: Provider-specific requirement mappings such as raw Graph permission names, Intune RBAC prerequisites, and admin-consent links MUST remain provider-owned metadata or evidence, not new platform-core nouns.
- **FR-017**: The feature MUST NOT introduce a dedicated provider-profile table, a provider-capability ledger, a broader provider-neutral artifact taxonomy, a user RBAC rewrite, or a routing cutover.
- **FR-018**: The feature MUST keep shared capability evaluation reusable by provider-connections, onboarding, required-permissions diagnostics, provider-operation starts, and shared reason translation rather than duplicating mapping logic locally.
### Authorization and Safety Requirements
- **AR-001**: Workspace membership MUST remain the first access boundary for provider-connections, onboarding, and required-permissions diagnostics.
- **AR-002**: Managed-environment entitlement MUST remain the second access boundary for those surfaces and any provider-operation start attempts made from them.
- **AR-003**: Non-members or cross-workspace or cross-environment access attempts MUST resolve as `404`, while in-scope actors missing user capabilities still resolve as `403`.
- **AR-004**: Existing destructive provider-connection actions such as setting default, enabling dedicated override, rotating or deleting dedicated credentials, reverting to platform, and enabling or disabling the connection MUST remain server-authorized and use confirmation where the current action contract already requires it.
- **AR-005**: Navigation-only provider actions such as admin-consent links or required-permissions links MUST remain clearly navigation-only and capability-gated without being misrepresented as mutations.
- **AR-006**: Provider capability evaluation MUST NOT bypass the current user RBAC gates for provider operations or configuration changes.
### Non-Functional Requirements
- **NFR-001**: Filament remains v5 on Livewire v4.
- **NFR-002**: Provider registration remains in `apps/platform/bootstrap/providers.php`; nothing moves to `bootstrap/app.php`.
- **NFR-003**: Asset strategy remains unchanged. No new panel or shared asset registration is expected, and deployment continues to use `cd apps/platform && php artisan filament:assets` only if some later implementation introduces registered assets.
- **NFR-004**: `ProviderConnectionResource` remains non-globally-searchable, and any touched searchable consumer such as `TenantResource` must keep its valid view destination intact.
- **NFR-005**: The feature must remain reviewable as one bounded provider-capability slice and MUST NOT silently absorb work reserved for Specs `284` through `287`.
- **NFR-006**: Default-visible capability summaries on touched operator-facing surfaces must stay Filament-native and avoid page-local badge, card, button, or color systems.
## UI Action Matrix
| Surface | Location | Header Actions | Inspect Affordance (List or Table) | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create or Edit Save+Cancel | Audit log? | Notes / Exemptions |
|---|---|---|---|---|---|---|---|---|---|---|
| Provider connections list | `ProviderConnectionResource` -> `ListProviderConnections` | preserve existing create action | clickable row to View | preserve current `More` group plus existing safe shortcuts | none | preserve current empty-state CTA | `N/A` | `N/A` | preserve current mutation audit behavior | `283` changes summary and prerequisite semantics only |
| Provider connection view and edit surfaces | `ProviderConnectionResource` -> `ViewProviderConnection`, `EditProviderConnection`, `CreateProviderConnection` | preserve `Grant admin consent` and existing `More` grouping | `N/A` | none beyond existing shared group | none | `N/A` | preserve existing header actions | preserve native save or cancel flow | preserve current mutation audit behavior | navigation-only and destructive-action discipline remain unchanged |
| Onboarding provider readiness and capability assist | `ManagedTenantOnboardingWizard` | none beyond current wizard affordances | explicit in-step selection and assist action only | none | none | preserve current create-or-select affordances | `N/A` | preserve wizard continue or back flow | preserve current onboarding audit behavior | the capability assist remains host-owned |
| Required permissions diagnostic page | `TenantRequiredPermissions` | current body-owned filter and reset actions only | inline matrix, no separate inspect destination | none | none | current clear-filters empty-state action | `N/A` | `N/A` | no new audit surface | existing action-surface exemptions remain valid |
All other touched shared help, support, or translation consumers must keep their existing action contracts and only adopt the shared capability vocabulary.
### Key Entities
- **Provider Capability Definition**: one shared registry record or definition that names the business-facing capability key, label, related workflows, and provider-owned requirement mapping for a current-release provider-backed workflow.
- **Provider Capability Result**: the derived result for one managed environment and provider connection, including the capability key, status, blocking reason code when present, provider requirement keys, last-checked or freshness evidence, and one remediation hint.
- **Provider Requirement Evidence**: provider-owned raw evidence such as Graph permission names, Intune RBAC prerequisites, consent posture, and required-permissions URLs that justify the capability result without becoming the primary operator vocabulary.
- **Capability-Aware Operation Gate**: the existing provider-operation start seam extended to require capability evaluation before dispatch or blocked outcome creation.
- **Capability Grouped Diagnostic View**: the required-permissions view model that groups raw permission evidence under capability headings and statuses.
## Success Criteria
### Measurable Outcomes
- **SC-001**: 100% of affected default-visible provider workflow blockers on provider-connections, onboarding, and required-permissions surfaces use the shared capability vocabulary before showing provider-specific raw requirement detail.
- **SC-002**: An operator can move from a blocked provider workflow to the required-permissions diagnostic path and see the same capability label and status in 3 interactions or fewer.
- **SC-003**: 100% of affected provider-operation blocked outcomes include the shared capability key or capability summary in context instead of relying on raw Graph permission names as the primary explanation.
- **SC-004**: The implementation introduces no provider-capability table or other new persisted provider ledger.