## Summary - retire the remaining tenant-scoped provider-connection legacy routes and update canonical verification and link behavior - complete the provider target-scope fallback cleanup so neutral shared scope data falls back to the managed environment when the raw connection tenant identifier is blank - stop mirroring workspace roles into managed-environment scope persistence and cut the targeted admin-panel test helpers over to the post-cutover context path - add and update the Spec 287 artifact package and targeted regression coverage for route retirement, provider-core neutralization, workspace-first RBAC, and helper cutover ## Validation - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections/LegacyRedirectTest.php tests/Feature/ProviderConnections/TenantlessListRouteTest.php tests/Feature/ProviderConnections/TenantlessListScopingTest.php tests/Feature/Auth/WorkspaceFirstManagedEnvironmentAccessTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php tests/Feature/Reviews/CustomerReviewWorkspaceLaunchLinksTest.php tests/Feature/Rbac/TriageReviewStateAuthorizationTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php` - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` ## Notes - Filament remains on Livewire v4 and provider registration stays unchanged in `apps/platform/bootstrap/providers.php`. - No new asset registration or deployment-step changes are included in this slice. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #346
269 lines
32 KiB
Markdown
269 lines
32 KiB
Markdown
# Feature Specification: Cutover Prerequisite Completion
|
|
|
|
**Feature Branch**: `287-cutover-prerequisite-completion`
|
|
**Created**: 2026-05-10
|
|
**Status**: Ready
|
|
**Input**: User description: "We need to re-scope the active Spec 287 so it completes the remaining runtime and test-harness prerequisites that currently block Quality Gates / No-Legacy Enforcement."
|
|
|
|
## Spec Candidate Check *(mandatory - SPEC-GATE-001)*
|
|
|
|
- **Problem**: The reserved cutover hardening slot cannot honestly become the quality-gates / no-legacy package yet because the branch still contains unfinished runtime and test-harness seams. Repo truth still shows legacy provider-connection route aliases, Microsoft-shaped provider target-scope core fields, environment-scope membership persistence that still mirrors workspace roles, and tenant-panel test helpers that boot the retired panel in test context.
|
|
- **Today's failure**: `apps/platform/routes/web.php` still serves `/admin/tenants/{tenant:slug}/provider-connections` redirect routes, provider-core seams still rely on Microsoft-shaped identity and target-scope fields such as `entra_tenant_id` and related `tenantContext` payloads, shared access cleanup is incomplete while `ManagedEnvironmentMembership` persistence still carries copied role values, and `apps/platform/tests/Pest.php` plus targeted test files still depend on `setTenantPanelContext()` and other tenant-panel-era helpers. If `287` stayed a guard package, it would either fail immediately for the wrong reason or silently absorb unfinished runtime work anyway.
|
|
- **User-visible improvement**: Operators keep the already-approved workspace-first, provider-neutral admin baseline because the remaining prerequisite seams are completed directly. After this slice, Spec `288` can focus purely on quality gates and no-legacy enforcement instead of finishing live runtime behavior.
|
|
- **Smallest enterprise-capable version**: complete only the remaining prerequisite seams: retire the legacy provider-connection route family, finish provider target-scope core neutralization on the shared provider seams, clean environment-scope role persistence so workspace membership remains the only role-bearing truth, replace tenant-panel test helpers with admin/workspace context helpers, and prove those seams with targeted feature and browser validation only. Do not add a global guard suite, a full-suite baseline, a new product workflow, or a new abstraction framework.
|
|
- **Explicit non-goals**: no no-legacy guard suite, no full-suite baseline, no global quality gates, no package execution, no guided operations, no UI copy cleanup, no provider capability expansion, no new provider implementation, no new panel, no new migration-only compatibility shim, and no broad repo-wide wording sweep.
|
|
- **Permanent complexity imported**: one bounded runtime seam inventory, a small targeted test-support helper replacement, focused regression tests for the changed seams, and one explicit handoff to Spec `288`. No new persisted truth, no new role family, and no new governance or lint subsystem are introduced.
|
|
- **Why now**: the user has explicitly re-scoped Spec `287` so the remaining prerequisites land before the follow-up enforcement package. Without this step, Spec `288` would either be blocked or would be forced to violate scope by finishing runtime work under the label of quality gates.
|
|
- **Why not local**: the remaining drift is not isolated to one page or one class. It spans route ownership, shared provider-core contracts, environment-scope persistence semantics, and the common test harness. A local patch would leave the cutover baseline inconsistent and would not give Spec `288` a stable runtime foundation.
|
|
- **Approval class**: Cleanup
|
|
- **Red flags triggered**: cross-cutting runtime seam completion, shared provider/platform boundary cleanup, and test-harness migration risk. Defense: the slice is bounded to the five named prerequisite areas, explicitly forbids global guard work and adjacent product features, and hands enforcement to Spec `288`.
|
|
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 1 | Wiederverwendung: 2 | **Gesamt: 10/12**
|
|
- **Decision**: approve
|
|
|
|
## Review Outcome
|
|
|
|
- **Outcome class**: acceptable-special-case
|
|
- **Workflow outcome**: keep
|
|
- **Test-governance outcome**: keep
|
|
- **Reason**: the package is cross-cutting, but it remains implementation-ready because it completes only explicit prerequisite seams and keeps proof scoped to targeted validation rather than a global enforcement layer.
|
|
- **Workflow result**: Ready for implementation as the last runtime/test-harness completion slice before Spec `288`.
|
|
|
|
## Spec Scope Fields *(mandatory)*
|
|
|
|
- **Scope**: workspace
|
|
- **Primary Routes**:
|
|
- `/admin/provider-connections`
|
|
- `/admin/provider-connections/create`
|
|
- `/admin/provider-connections/{record}`
|
|
- `/admin/provider-connections/{record}/edit`
|
|
- legacy provider-connection aliases currently mounted below `/admin/tenants/{tenant:slug}/provider-connections`, which are in scope for retirement
|
|
- existing workspace-scoped managed-environment pages or launch points that deep-link into provider connections or provider-backed run follow-up
|
|
- **Data Ownership**:
|
|
- `ProviderConnection` remains the existing workspace-owned, managed-environment-scoped provider binding record
|
|
- provider target-scope and identity outputs remain derived shared contracts; Microsoft-specific profile data stays provider-owned nested metadata only where current-release consent or diagnostics actually need it
|
|
- `workspace_memberships` remain the only role-bearing access truth
|
|
- `managed_environment_memberships` or their in-place successor remain a narrowing-only access-scope overlay and must not persist an independent role-bearing truth
|
|
- no new persisted entity, table, or ledger is introduced
|
|
- **RBAC**:
|
|
- workspace membership remains the first entitlement boundary and the only role-bearing authority
|
|
- managed-environment scope may narrow visibility only
|
|
- non-members or out-of-scope actors remain `404`
|
|
- in-scope actors missing capability remain `403`
|
|
|
|
## Cross-Cutting / Shared Pattern Reuse *(mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, navigation entry points, alerts, evidence/report viewers, or any other existing shared operator interaction family; otherwise write `N/A - no shared interaction family touched`)*
|
|
|
|
- **Cross-cutting feature?**: yes
|
|
- **Interaction class(es)**: provider-connection navigation entry points, provider target-scope summaries, provider-backed run context, workspace-first access evaluation, and shared test-harness context setup
|
|
- **Systems touched**:
|
|
- `apps/platform/routes/web.php`
|
|
- `apps/platform/app/Services/Providers/ProviderConnectionResolver.php`
|
|
- `apps/platform/app/Services/Providers/ProviderIdentityResolver.php`
|
|
- `apps/platform/app/Services/Providers/ProviderIdentityResolution.php`
|
|
- `apps/platform/app/Services/Providers/PlatformProviderIdentityResolver.php`
|
|
- `apps/platform/app/Services/Providers/ProviderOperationStartGate.php`
|
|
- `apps/platform/app/Support/Providers/TargetScope/ProviderConnectionTargetScopeNormalizer.php`
|
|
- `apps/platform/app/Support/Providers/TargetScope/ProviderConnectionTargetScopeDescriptor.php`
|
|
- `apps/platform/app/Services/Auth/TenantMembershipManager.php`
|
|
- `apps/platform/app/Services/Auth/ManagedEnvironmentAccessScopeResolver.php`
|
|
- `apps/platform/tests/Pest.php`
|
|
- targeted provider-connection, auth, RBAC, and browser tests that still depend on the old route or panel helper seams
|
|
- **Existing pattern(s) to extend**: current workspace-first provider-connection routing, existing target-scope normalizer and descriptor path, existing workspace-first access resolver path, and current shared test-support helper style in `tests/Pest.php`
|
|
- **Shared contract / presenter / builder / renderer to reuse**: `ProviderConnectionTargetScopeNormalizer`, `ProviderConnectionTargetScopeDescriptor`, `ProviderIdentityResolution`, `ProviderOperationStartGate`, existing workspace access resolver seams, and `setAdminPanelContext()`-style test support
|
|
- **Why the existing shared path is sufficient or insufficient**: the repo already has the right shared seams, but those seams still carry incomplete cutover behavior. Extending them is sufficient; building a new guard framework or a second helper layer would be wider than necessary.
|
|
- **Allowed deviation and why**: bounded provider-owned Microsoft profile detail may remain where current consent or diagnostics genuinely need it. No other deviation is allowed.
|
|
- **Consistency impact**: provider-connection routes, provider-core target-scope outputs, workspace-first access resolution, and test harness setup must all describe the same post-cutover truth so later enforcement can be declarative instead of compensating for runtime drift.
|
|
- **Review focus**: reviewers must verify that `287` completes only the named runtime and test-harness seams, does not introduce a global guard family, and leaves Spec `288` as the explicit follow-up for no-legacy enforcement.
|
|
|
|
## OperationRun UX Impact *(mandatory when the feature creates, queues, deduplicates, resumes, blocks, completes, or deep-links to an `OperationRun`; otherwise write `N/A - no OperationRun start or link semantics touched`)*
|
|
|
|
- **Touches OperationRun start/completion/link UX?**: yes
|
|
- **Shared OperationRun UX contract/layer reused**: `ProviderOperationStartGate`, existing `OperationRun` context resolution, and canonical operation links
|
|
- **Delegated start/completion UX behaviors**: existing queued, blocked, and run-link behavior remains on the shared provider-operation and OperationRun paths; this slice only completes the underlying target-scope and route truth they depend on
|
|
- **Local surface-owned behavior that remains**: provider-connection surfaces and existing launch points still own only the initiation inputs and local follow-up affordances
|
|
- **Queued DB-notification policy**: `N/A` - unchanged
|
|
- **Terminal notification path**: existing central lifecycle mechanism
|
|
- **Exception required?**: none
|
|
|
|
## Provider Boundary / Platform Core Check *(mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write `N/A - no shared provider/platform boundary touched`)*
|
|
|
|
- **Shared provider/platform boundary touched?**: yes
|
|
- **Boundary classification**: mixed
|
|
- **Seams affected**: provider-connection route ownership, provider target-scope descriptors, provider identity resolution payloads, provider-backed run context, and managed-environment scoped provider launch surfaces
|
|
- **Neutral platform terms preserved or introduced**: `provider connection`, `target scope`, `scope kind`, `scope identifier`, `scope display name`, `provider profile`, `workspace`, and `managed environment`
|
|
- **Provider-specific semantics retained and why**: Microsoft tenant/profile identifiers, consent links, and Graph-specific diagnostics may remain nested provider-owned data because current-release support and consent workflows still require them
|
|
- **Why this does not deepen provider coupling accidentally**: the slice removes Microsoft-shaped assumptions from the shared platform-core contract and leaves provider detail only in explicitly provider-owned metadata
|
|
- **Follow-up path**: Spec `288` owns quality gates and no-legacy enforcement once these runtime seams are complete
|
|
|
|
## UI / Surface Guardrail Impact *(mandatory when operator-facing surfaces are changed; otherwise write `N/A`)*
|
|
|
|
| Surface / Change | Operator-facing surface change? | Native vs Custom | Shared-Family Relevance | State Layers Touched | Exception Needed? | Low-Impact / `N/A` Note |
|
|
|---|---|---|---|---|---|---|
|
|
| Provider connections route and launch path completion | yes | Native Filament resource plus existing route helpers | navigation entry points, record links, launch flow continuity | route, page, detail, URL/query | no | existing resource family only; no new operator-facing feature |
|
|
| Shared provider target-scope summaries and provider-backed run context | yes | Existing shared presenter or resolver path | provider summaries, operation launch context, supporting disclosure | page, modal, detail, run context | no | summary contract cleanup only; no UI copy expansion |
|
|
| Test-harness helper cutover | no | N/A | none | test support only | no | `N/A - repository workflow only` |
|
|
|
|
## Decision-First Surface Role *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
| 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 route and launch path completion | Primary Decision Surface | Operator decides whether to open, manage, or launch from an existing provider connection | canonical provider-connection route, current managed-environment context, and existing record truth | full provider detail and downstream operation detail remain on existing surfaces | Primary because the route contract must stop forcing operators through legacy aliases | preserves the existing provider-connection workflow while removing route ambiguity | removes fallback redirects and stale path language from the live flow |
|
|
| Shared provider target-scope summaries and provider-backed run context | Secondary Context Surface | Operator confirms the connection or launch target before acting | neutral target-scope summary and current surface context | nested provider-owned profile detail and run evidence remain secondary | Secondary because it supports an existing decision surface rather than creating a new one | keeps current launch and summary flows intact while correcting the shared contract | removes the need to infer platform meaning from Microsoft-only fields |
|
|
|
|
## Audience-Aware Disclosure *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
| 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 route and launch path completion | operator-MSP, support-platform | canonical provider-connection route and current environment context | existing provider status and authorization detail | nested provider-owned profile detail and raw diagnostics | `Open provider connection` or the existing primary launch action | raw/provider-owned detail remains secondary | the route and summary state the canonical scope once and do not add a second fallback path |
|
|
| Shared provider target-scope summaries and provider-backed run context | operator-MSP, support-platform | neutral target-scope summary and current launch scope | launch blockers and provider-operation follow-up stay on shared existing surfaces | provider-owned raw identifiers stay nested | existing primary launch or follow-up action | raw/provider-owned identifiers remain secondary | one shared target-scope summary is reused instead of page-local reinterpretations |
|
|
|
|
## UI/UX Surface Classification *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
| 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 route and launch path completion | List / Detail / Integrations | CRUD / List-first Resource | Open the canonical provider-connection record or start the existing provider workflow | full-row open to the existing provider-connection detail surface | required | existing grouped secondary actions only | unchanged existing destructive actions only | `/admin/provider-connections` | `/admin/provider-connections/{record}` | workspace and managed-environment context | Provider connection | canonical route and current target scope | none |
|
|
| Shared provider target-scope summaries and provider-backed run context | Record / Detail / Action | Action-supporting detail | Confirm scope and continue on the existing provider flow | existing summary and launch affordance | n/a | existing secondary provider detail remains nested | none introduced by this slice | inherited current collection route | inherited current detail route | current workspace, current managed environment, target scope | Target scope | neutral shared scope summary | provider-owned nested detail only |
|
|
|
|
## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)*
|
|
|
|
| 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 route and launch path completion | Workspace operator | Decide whether to inspect or use an existing provider connection on the canonical route | Existing provider-connection list and detail surfaces | Am I on the canonical provider-connection path for this environment and can I continue safely? | current environment context, canonical route, and existing provider-connection truth | provider-owned profile detail and lower-level diagnostics | lifecycle, authorization, target-scope truth | existing provider connection only | existing open, manage, and launch actions | unchanged existing dangerous actions only |
|
|
| Shared provider target-scope summaries and provider-backed run context | Workspace operator | Decide whether the current connection or launch target is the right scope | Existing launch and supporting summary surfaces | What exact target scope will this action use? | neutral shared target-scope summary and current managed-environment context | provider-owned identifiers and nested run detail | target-scope truth, launch readiness | none beyond the existing provider-backed mutation | existing launch action | none added by this slice |
|
|
|
|
## Proportionality Review *(mandatory when structural complexity is introduced)*
|
|
|
|
- **New source of truth?**: no
|
|
- **New persisted entity/table/artifact?**: no
|
|
- **New abstraction?**: no
|
|
- **New enum/state/reason family?**: no
|
|
- **New cross-domain UI framework/taxonomy?**: no
|
|
- **Current operator problem**: the quality-gates follow-up is blocked because the live runtime and test harness still carry unfinished cutover seams that enforcement should not have to complete.
|
|
- **Existing structure is insufficient because**: the repo already has the intended workspace-first and provider-neutral direction, but the remaining seams still encode old route aliases, Microsoft-shaped shared target-scope truth, copied environment-scope roles, and tenant-panel helper assumptions.
|
|
- **Narrowest correct implementation**: complete only the five named prerequisite seams and validate them with focused tests instead of introducing a new no-legacy framework or widening into adjacent product work.
|
|
- **Ownership cost**: bounded runtime seam cleanup, targeted helper migration, and focused regression coverage.
|
|
- **Alternative intentionally rejected**: leaving the runtime seams in place and moving straight to a guard suite. That would force the enforcement package to encode unfinished behavior instead of guarding the final truth.
|
|
- **Release truth**: current-release truth
|
|
|
|
### Compatibility posture
|
|
|
|
This feature assumes a pre-production environment.
|
|
|
|
Backward compatibility, legacy aliases kept for convenience, broad migration shims, and compatibility-specific test lanes are out of scope.
|
|
|
|
Canonical replacement is preferred over preservation.
|
|
|
|
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
|
|
|
|
- **Test purpose / classification**: Feature, Browser
|
|
- **Validation lane(s)**: fast-feedback, confidence, browser
|
|
- **Why this classification and these lanes are sufficient**: the package completes concrete runtime seams and the shared test harness, so focused feature coverage plus a narrow browser smoke are sufficient. A guard lane or full-suite baseline would exceed scope.
|
|
- **New or expanded test families**: targeted provider-connection route and scope tests, targeted workspace-first access persistence tests, targeted helper-cutover coverage, and one narrow browser smoke proving the canonical provider-connection launch path still works after helper and route completion
|
|
- **Fixture / helper cost impact**: moderate. The main cost is replacing the tenant-panel helper path with a post-cutover admin/workspace helper and updating the proof-command consumer tests `tests/Feature/Reviews/CustomerReviewWorkspaceLaunchLinksTest.php` and `tests/Feature/Rbac/TriageReviewStateAuthorizationTest.php`.
|
|
- **Heavy-family visibility / justification**: one narrow browser smoke only. No heavy-governance or broad browser family is justified.
|
|
- **Special surface test profile**: standard-native-filament, global-context-shell
|
|
- **Standard-native relief or required special coverage**: ordinary feature coverage is sufficient for most seams; one narrow browser smoke is required to prove the canonical provider-connection route and launch flow after the helper cutover
|
|
- **Reviewer handoff**: reviewers must verify that Filament remains v5 on Livewire v4, provider registration stays in `apps/platform/bootstrap/providers.php`, any touched provider-connection destructive actions retain confirmation and server authorization, no asset registration or deployment step is introduced, the proof commands stay targeted to the changed seams, and no new global guard family or full-suite baseline is introduced
|
|
- **Budget / baseline / trend impact**: contained feature-local increase only
|
|
- **Escalation needed**: document-in-feature
|
|
- **Active feature PR close-out entry**: RuntimePrerequisite
|
|
- **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/Feature/ProviderConnections/LegacyRedirectTest.php tests/Feature/ProviderConnections/TenantlessListRouteTest.php tests/Feature/ProviderConnections/TenantlessListScopingTest.php tests/Feature/Auth/WorkspaceFirstManagedEnvironmentAccessTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php tests/Feature/Reviews/CustomerReviewWorkspaceLaunchLinksTest.php tests/Feature/Rbac/TriageReviewStateAuthorizationTest.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/Spec281ProviderConnectionScopeSmokeTest.php tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.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)`
|
|
|
|
## User Scenarios & Testing *(mandatory)*
|
|
|
|
### User Story 1 - Retire provider-connection legacy routes (Priority: P1)
|
|
|
|
As an operator, I want provider-connection entry points to resolve only through the canonical admin route family so the live flow no longer depends on legacy tenant-first redirects.
|
|
|
|
**Why this priority**: route retirement is the most visible unfinished prerequisite and it blocks later enforcement from distinguishing real regressions from known legacy fallbacks.
|
|
|
|
**Independent Test**: Can be fully tested by hitting the canonical provider-connection routes, the retired legacy aliases, and the current launch-point inventory in `apps/platform/app/Providers/Filament/AdminPanelProvider.php`, `apps/platform/app/Filament/Resources/TenantResource.php`, `apps/platform/app/Filament/Pages/TenantRequiredPermissions.php`, `apps/platform/app/Support/OperationRunLinks.php`, `apps/platform/app/Support/Providers/ProviderReasonTranslator.php`, and `apps/platform/app/Support/Verification/VerificationLinkBehavior.php`, then proving only the canonical path remains valid.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** an operator opens a provider-connection launch point after the cutover, **When** the route resolves, **Then** it lands on the canonical `/admin/provider-connections...` path instead of a legacy tenant alias.
|
|
2. **Given** a legacy `/admin/tenants/{tenant:slug}/provider-connections` alias is requested after completion, **When** the request executes, **Then** it no longer acts as an accepted runtime fallback.
|
|
|
|
---
|
|
|
|
### User Story 2 - Neutralize provider target-scope core seams (Priority: P1)
|
|
|
|
As an operator and reviewer, I want shared provider target-scope and identity contracts to use platform-neutral fields so provider-backed runtime and follow-up do not depend on Microsoft-shaped core truth.
|
|
|
|
**Why this priority**: this is the runtime provider-boundary prerequisite that must be complete before a no-legacy guard package can enforce it.
|
|
|
|
**Independent Test**: Can be fully tested by exercising the provider target-scope descriptor, the shared provider-backed launch or run context, and the existing provider-connection summary surfaces without relying on Microsoft-only shared fields.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a provider connection is summarized on a shared surface, **When** the target scope is rendered, **Then** the shared contract uses neutral target-scope fields while provider-owned Microsoft detail stays nested.
|
|
2. **Given** a provider-backed run or start gate uses provider context, **When** it records the shared scope payload, **Then** it does not require Microsoft-only core keys such as `target_scope.entra_tenant_id` to express the shared truth.
|
|
|
|
---
|
|
|
|
### User Story 3 - Clean environment-scope role persistence (Priority: P1)
|
|
|
|
As a workspace owner or reviewer, I want environment scope persistence to narrow access only so workspace membership remains the single role-bearing authority.
|
|
|
|
**Why this priority**: workspace-first RBAC cannot be treated as complete while environment-scope persistence still mirrors or persists a second role-bearing truth.
|
|
|
|
**Independent Test**: Can be fully tested by creating workspace membership plus managed-environment scope combinations and proving authorization still derives role authority from workspace membership while environment scope only narrows visibility.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** a workspace member is granted managed-environment scope, **When** the scope is persisted, **Then** it does not establish an independent role-bearing truth separate from workspace membership.
|
|
2. **Given** a workspace member loses access to one environment, **When** a scoped surface is resolved, **Then** the system treats that as a narrowing-only access outcome rather than a second role matrix.
|
|
|
|
---
|
|
|
|
### User Story 4 - Cut over tenant-panel test helpers (Priority: P2)
|
|
|
|
As a maintainer, I want the shared test harness to stop booting the retired tenant panel so targeted seam tests can prove the post-cutover runtime honestly.
|
|
|
|
**Why this priority**: the helper cutover is necessary to validate the runtime changes without relying on a panel context that the cutover is removing.
|
|
|
|
**Independent Test**: Can be fully tested by updating the shared helper, `apps/platform/tests/Feature/Reviews/CustomerReviewWorkspaceLaunchLinksTest.php`, and `apps/platform/tests/Feature/Rbac/TriageReviewStateAuthorizationTest.php`, then running the targeted seam tests and browser smoke without `setTenantPanelContext()`.
|
|
|
|
**Acceptance Scenarios**:
|
|
|
|
1. **Given** `CustomerReviewWorkspaceLaunchLinksTest.php` or `TriageReviewStateAuthorizationTest.php` needs managed-environment context after the cutover, **When** it boots test state, **Then** it uses the post-cutover admin/workspace helper path instead of `setTenantPanelContext()`.
|
|
2. **Given** the targeted browser or feature validation runs, **When** it exercises the changed seams, **Then** it passes without reintroducing the retired tenant panel as a test-only crutch.
|
|
|
|
### Edge Cases
|
|
|
|
- What happens when a legacy provider-connection alias is requested by a stale bookmark immediately after the canonical route retirement?
|
|
- How does the shared provider target-scope contract preserve provider-owned Microsoft profile detail without letting it leak back into platform-core truth?
|
|
- What happens when a workspace member remains entitled to the workspace but is narrowed away from one managed environment after persistence cleanup?
|
|
- How do targeted tests that still need managed-environment context keep working after the tenant-panel helper is removed?
|
|
|
|
## Requirements *(mandatory)*
|
|
|
|
**Constitution alignment (required):** This slice introduces no new Graph integration surface, no new queue workflow, no new persisted entity, and no new operator product flow. It completes the remaining runtime and test-harness seams that must be true before a separate enforcement spec can guard them.
|
|
|
|
**Constitution alignment (PROP-001 / ABSTR-001 / PERSIST-001 / STATE-001 / BLOAT-001):** The feature must stay completion-focused. It may update existing route, provider-core, access-scope, and test-support seams, but it must not introduce a new guard framework, new persistence, a new role family, or a new taxonomy layer.
|
|
|
|
**Constitution alignment (XCUT-001 / PROV-001):** The package must reuse existing provider-connection routing, target-scope normalization, access resolution, and test-support paths. It may finish their cutover behavior, but it must not create a parallel provider-core or enforcement subsystem.
|
|
|
|
### Functional Requirements
|
|
|
|
- **FR-001**: The package MUST retire the legacy provider-connection route family currently mounted below `/admin/tenants/{tenant:slug}/provider-connections` and leave the canonical provider-connection runtime on `/admin/provider-connections...`.
|
|
- **FR-002**: Canonical provider-connection deep links and the current launch-point inventory in `apps/platform/app/Providers/Filament/AdminPanelProvider.php`, `apps/platform/app/Filament/Resources/TenantResource.php`, `apps/platform/app/Filament/Pages/TenantRequiredPermissions.php`, `apps/platform/app/Support/OperationRunLinks.php`, `apps/platform/app/Support/Providers/ProviderReasonTranslator.php`, and `apps/platform/app/Support/Verification/VerificationLinkBehavior.php` MUST resolve through the post-cutover admin route family only.
|
|
- **FR-003**: Shared provider target-scope and identity contracts MUST stop depending on Microsoft-only core keys such as `entra_tenant_id`, `tenantContext`, or `target_scope.entra_tenant_id` to express platform-core truth.
|
|
- **FR-004**: Provider-owned Microsoft profile or consent details MAY remain nested where current-release diagnostics or consent workflows need them, but they MUST NOT remain the shared primary target-scope contract.
|
|
- **FR-005**: Workspace membership MUST remain the only role-bearing authority on the completed seams.
|
|
- **FR-006**: Environment-scope persistence MUST narrow visibility only and MUST NOT persist or restore an independent role-bearing truth.
|
|
- **FR-007**: Shared services or managers that currently copy workspace role values into environment-scope persistence MUST be completed to the narrowing-only contract.
|
|
- **FR-008**: `apps/platform/tests/Pest.php` MUST replace tenant-panel-era setup with a post-cutover admin or workspace context helper path suitable for the changed seams.
|
|
- **FR-009**: The targeted proof-command consumers `apps/platform/tests/Feature/Reviews/CustomerReviewWorkspaceLaunchLinksTest.php` and `apps/platform/tests/Feature/Rbac/TriageReviewStateAuthorizationTest.php` that still depend on `setTenantPanelContext()` or equivalent retired tenant-panel setup MUST be cut over as part of this slice.
|
|
- **FR-010**: Validation in `287` MUST remain targeted to the changed seams only and MUST NOT become a global no-legacy guard suite or a full-suite baseline.
|
|
- **FR-011**: Spec `288` MUST remain the follow-up package for quality gates and no-legacy enforcement; `287` must not absorb that work.
|
|
|
|
### Non-Functional Requirements
|
|
|
|
- **NFR-001**: Filament remains v5 on Livewire v4, and provider registration remains in `apps/platform/bootstrap/providers.php`.
|
|
- **NFR-002**: The package introduces no new asset registration and no new deployment step.
|
|
- **NFR-003**: Proof remains bounded to targeted feature tests, targeted browser validation, and formatting. No full-suite baseline is required in this slice.
|
|
- **NFR-004**: No new global guard family or repository-wide lint subsystem may be introduced under this spec.
|
|
- **NFR-005**: The package must remain reviewable as one bounded prerequisite-completion slice that directly precedes the Spec `288` enforcement package. |