spec: add environment-owned surface routing contract #377
@ -0,0 +1 @@
|
||||
Spec 319 browser verification screenshots are saved here during implementation.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 99 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 7.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
@ -0,0 +1,75 @@
|
||||
# Specification Quality Checklist: Environment-Owned Surface Routing & Shell Context Contract
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before implementation
|
||||
**Created**: 2026-05-16
|
||||
**Feature**: [spec.md](/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/319-environment-owned-surface-routing-shell-context-contract/spec.md)
|
||||
|
||||
## Candidate Selection Gate
|
||||
|
||||
- [x] Explicit user-provided Spec 319 request was selected as the source of truth for this preparation pass.
|
||||
- [x] Completed-spec guardrail checked that no existing `specs/319-*` package was present before generation.
|
||||
- [x] Specs 313, 314, 315, 316, 317, and 318 were treated as dependency/historical context, not rewritten.
|
||||
- [x] Roadmap/spec-candidate queue was reviewed; active auto-prep queue is empty, so this package proceeds only because the user directly supplied/promoted Spec 319.
|
||||
- [x] Close alternatives were deferred to follow-up specs 320, 321, and 322.
|
||||
- [x] The selected slice is Baseline Compare Environment-owned route/shell hardening only.
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] Problem statement is operator-visible and tied to route/shell/copy mismatch.
|
||||
- [x] User value is clear: self-sufficient Environment-owned Baseline Compare with no hidden fallback.
|
||||
- [x] Scope is bounded to Baseline Compare, with related pages inspect-only.
|
||||
- [x] Hard cutover/no compatibility posture is explicit.
|
||||
- [x] No unresolved `[NEEDS CLARIFICATION]` markers remain.
|
||||
- [x] Mandatory Spec Candidate Check is complete.
|
||||
- [x] Spec Scope Fields are complete.
|
||||
- [x] Shared pattern, OperationRun, provider boundary, UI/surface, testing, acceptance, and browser sections are complete.
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] Functional requirements are testable and unambiguous.
|
||||
- [x] Requirements cover canonical Environment route, old route rejection, cross-workspace protection, CTA URL generation, shell/copy, reload, back/forward, and Decision Register regression.
|
||||
- [x] Non-goals prevent Spec 320/321/322 scope creep.
|
||||
- [x] Edge cases are identified.
|
||||
- [x] Assumptions and risks are documented.
|
||||
- [x] Success criteria are measurable.
|
||||
- [x] Open questions do not block implementation.
|
||||
|
||||
## Plan Quality
|
||||
|
||||
- [x] Laravel, Filament, Livewire, Pest, PostgreSQL, Sail, and Dokploy context is recorded.
|
||||
- [x] Livewire v4.0+ compliance is explicitly noted through Livewire 4.1.4.
|
||||
- [x] Laravel 12 panel provider location remains `apps/platform/bootstrap/providers.php`.
|
||||
- [x] Global search impact is assessed as unchanged unless a Resource is touched.
|
||||
- [x] Destructive/high-impact action handling is addressed for existing Compare Now.
|
||||
- [x] Asset strategy is assessed as no new Filament assets/no new `filament:assets` step.
|
||||
- [x] No migration, seeder, package, env var, queue, scheduler, storage, or deployment asset change is planned.
|
||||
- [x] Existing repo seams are named.
|
||||
- [x] Test strategy and browser verification plan are concrete.
|
||||
|
||||
## Task Quality
|
||||
|
||||
- [x] Tasks are ordered from guardrails/tests through runtime changes, browser verification, and final validation.
|
||||
- [x] Tests are required before or alongside implementation.
|
||||
- [x] Task IDs follow the required checkbox format.
|
||||
- [x] File paths are concrete where repo surfaces are known.
|
||||
- [x] Non-tasks explicitly prevent compatibility layers, query alias support, and follow-up-spec scope creep.
|
||||
- [x] Browser screenshot paths are specified.
|
||||
- [x] Validation commands are specified.
|
||||
|
||||
## Constitution Alignment
|
||||
|
||||
- [x] Workspace and Environment isolation are covered.
|
||||
- [x] Cross-workspace Environment access is 404/safe no-access.
|
||||
- [x] No new persisted truth is introduced.
|
||||
- [x] No new abstraction/framework/taxonomy is planned.
|
||||
- [x] OperationRun semantics are preserved for existing Compare Now behavior.
|
||||
- [x] Audit/authorization/confirmation expectations for high-impact action remain explicit.
|
||||
- [x] Test governance lane impact is explicit.
|
||||
- [x] Provider/platform boundary is explicit.
|
||||
|
||||
## Readiness Result
|
||||
|
||||
- [x] Candidate Selection Gate passes.
|
||||
- [x] Spec Readiness Gate passes.
|
||||
- [x] Ready for separate implementation loop.
|
||||
- [x] No application implementation was performed during this preparation step.
|
||||
@ -0,0 +1,403 @@
|
||||
# Implementation Plan: Environment-Owned Surface Routing & Shell Context Contract
|
||||
|
||||
**Branch**: `319-environment-owned-surface-routing-shell-context-contract` | **Date**: 2026-05-16 | **Spec**: [spec.md](/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/319-environment-owned-surface-routing-shell-context-contract/spec.md)
|
||||
**Input**: Feature specification from `/specs/319-environment-owned-surface-routing-shell-context-contract/spec.md`
|
||||
|
||||
**Preparation status**: Specification artifacts only. No runtime implementation has been performed by this preparation step.
|
||||
|
||||
## Summary
|
||||
|
||||
Spec 319 hard-cuts Baseline Compare from an ambiguous workspace-style Filament page into an explicit Environment-owned admin surface:
|
||||
|
||||
```text
|
||||
Environment-owned Baseline Compare
|
||||
-> Workspace + Environment route
|
||||
-> Workspace + Environment shell
|
||||
-> copy/breadcrumb/header aligned
|
||||
-> no clean workspace-only route
|
||||
-> no ?environment_id filtered hub model
|
||||
-> no remembered Environment fallback
|
||||
```
|
||||
|
||||
The implementation must make Baseline Compare self-sufficient through the existing Environment route family, update all Environment Dashboard and Environment-owned entry points, reject cross-workspace Environment access, and keep Decision Register/workspace hub contracts from Specs 314-316 green.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: PHP 8.4.15, Laravel 12.52.0
|
||||
**Primary Dependencies**: Filament 5.2.1, Livewire 4.1.4, Laravel Sail, Laravel Socialite, Laravel MCP
|
||||
**Storage**: PostgreSQL; no schema changes planned
|
||||
**Testing**: Pest 4.3.1 / PHPUnit 12.5.4; focused browser smoke for shell/copy/URL behavior
|
||||
**Validation Lanes**: fast-feedback, confidence, browser
|
||||
**Target Platform**: Laravel admin application under `apps/platform`, local development through Sail, staging/production through Dokploy
|
||||
**Project Type**: Web application, Laravel/Filament admin panel
|
||||
**Performance Goals**: No material performance change. Route-bound Environment resolution should reuse existing Workspace/Environment model binding and shell resolution.
|
||||
**Constraints**: No migrations, seeders, packages, env vars, queues, scheduler, storage, compatibility redirects, legacy query aliases, or broad UI redesign.
|
||||
**Scale/Scope**: Focused route/shell/context hardening for Baseline Compare, with inspect-only handling for adjacent Environment-owned pages if they show the same mismatch.
|
||||
|
||||
## UI / Surface Guardrail Plan
|
||||
|
||||
- **Guardrail scope**: Baseline Compare route/shell/copy/navigation contract and Environment Dashboard CTA URL generation.
|
||||
- **Native vs custom classification summary**: Existing Filament Page/Blade view and existing Environment Dashboard/Widget links. No new styling system.
|
||||
- **Shared-family relevance**: Navigation, dashboard CTA/action links, shell context, breadcrumbs, and OperationRun action links.
|
||||
- **State layers in scope**: Route params, shell context, Filament Page access, page copy, browser reload/history, CTA URL query.
|
||||
- **Audience modes in scope**: Operator-MSP and support-platform.
|
||||
- **Decision/diagnostic/raw hierarchy plan**: Baseline Compare remains a decision-support Environment posture page. Diagnostics/evidence details remain on existing page sections.
|
||||
- **Raw/support gating plan**: No raw/support evidence exposure change.
|
||||
- **One-primary-action / duplicate-truth control**: Environment route + shell become the single ownership truth; no hidden query/session fallback.
|
||||
- **Handling modes by drift class or surface**: Hard-stop for workspace-style Baseline Compare render; review-mandatory for any adjacent Environment-owned page touched.
|
||||
- **Repository-signal treatment**: Spec 318 browser evidence is the starting signal; implementation must produce tests and focused browser evidence.
|
||||
- **Special surface test profiles**: global-context-shell.
|
||||
- **Required tests or manual smoke**: route/classification tests, CTA URL tests, remembered-fallback rejection, cross-workspace rejection, Decision Register regression, browser smoke.
|
||||
- **Exception path and spread control**: If old URL redirect is unavoidable, it must be explicitly justified, validate Workspace/Environment relationship, emit no legacy alias support, and be covered by tests. Preferred path is no route/404.
|
||||
- **Active feature PR close-out entry**: Guardrail and Smoke Coverage.
|
||||
|
||||
## Shared Pattern & System Fit
|
||||
|
||||
- **Cross-cutting feature marker**: yes.
|
||||
- **Systems touched**: `BaselineCompareLanding`, `AdminPanelProvider` page registration, route definitions if explicit page route is needed, `AdminSurfaceScope`, `WorkspaceScopedEnvironmentRoutes`, `WorkspaceSidebarNavigation`, `ManagedEnvironmentLinks`, `OperateHubShell`, Environment Dashboard summary/actions/widgets, Baseline Compare tests, workspace hub regression tests.
|
||||
- **Shared abstractions reused**: Existing Environment route pattern under `/admin/workspaces/{workspace}/environments/{environment}/...`, `WorkspaceScopedEnvironmentRoutes` where practical, `ManagedEnvironmentLinks`, existing `OperateHubShell`, existing OperationRun UX helpers.
|
||||
- **New abstraction introduced? why?**: none planned.
|
||||
- **Why the existing abstraction was sufficient or insufficient**: Existing Environment-bound pages work correctly; Baseline Compare bypasses them by using `/admin/baseline-compare-landing` plus `environment_id`/remembered context.
|
||||
- **Bounded deviation / spread control**: Any helper added must replace the current query-based Baseline Compare URL path, not add a second supported path.
|
||||
|
||||
## OperationRun UX Impact
|
||||
|
||||
- **Touches OperationRun start/completion/link UX?**: yes, existing Baseline Compare action is high-impact but no new OperationRun lifecycle is introduced.
|
||||
- **Central contract reused**: `OperationUxPresenter`, `OpsUxBrowserEvents`, `OperationRunLinks`, existing Baseline Compare service behavior.
|
||||
- **Delegated UX behaviors**: queued toast, `Open operation` URL, run-enqueued browser event, tenant/workspace-safe URL resolution.
|
||||
- **Surface-owned behavior kept local**: Compare initiation button and Baseline Compare page state remain local.
|
||||
- **Queued DB-notification policy**: N/A.
|
||||
- **Terminal notification path**: Existing central lifecycle behavior.
|
||||
- **Exception path**: none.
|
||||
|
||||
## Provider Boundary & Portability Fit
|
||||
|
||||
- **Shared provider/platform boundary touched?**: yes.
|
||||
- **Provider-owned seams**: Microsoft/Intune compare details and provider tenant identity remain unchanged.
|
||||
- **Platform-core seams**: Workspace/Environment route ownership, shell classification, and query/fallback rejection.
|
||||
- **Neutral platform terms / contracts preserved**: Workspace, Environment, Environment-owned page, Workspace hub, Environment filter.
|
||||
- **Retained provider-specific semantics and why**: Existing baseline compare content still compares Microsoft/Intune-governed subjects because that is the current provider implementation.
|
||||
- **Bounded extraction or follow-up path**: Workspace-owned baseline analysis pages are deferred to Spec 320.
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before implementation. Re-check after runtime changes.*
|
||||
|
||||
- Inventory-first: no inventory/snapshot truth change.
|
||||
- Read/write separation: no new write behavior. Existing Compare Now remains confirmation + authorization + audit/OperationRun governed.
|
||||
- Graph contract path: no new Graph calls; page render must remain DB-only.
|
||||
- Deterministic capabilities: existing capability checks remain; tests must cover route/access boundaries.
|
||||
- RBAC-UX: non-member / not entitled Workspace or Environment access returns 404/safe no-access; member missing capability follows existing behavior.
|
||||
- Workspace isolation: route model must validate Environment belongs to Workspace.
|
||||
- Tenant isolation: no cross-workspace Environment leakage; no provider tenant ID lookup.
|
||||
- Run observability: existing Baseline Compare run behavior remains observable through OperationRun.
|
||||
- Test governance: lane, fixture cost, browser coverage, and reviewer handoff are explicit in spec/plan/tasks.
|
||||
- Proportionality: no new persisted truth or broad abstraction; route replacement is the narrowest correct fix.
|
||||
- No premature abstraction: reuse existing route/shell helpers.
|
||||
- Persisted truth: no tables/entities/artifacts added.
|
||||
- Behavioral state: no new state/status/reason family.
|
||||
- UI semantics: route/shell/copy direct mapping only.
|
||||
- Shared pattern first: reuse Environment route family and shared OperationRun helpers.
|
||||
- Provider boundary: route identity uses platform Environment, not provider tenant ID.
|
||||
- V1 explicitness / few layers: hard cutover, no compatibility layer.
|
||||
- Filament-native UI: no ad-hoc styling or published internals.
|
||||
- Filament v5 / Livewire v4: Livewire 4.1.4 satisfies Filament v5 requirement; no Livewire v3 APIs.
|
||||
- Provider registration: Laravel 12 panel providers remain in `apps/platform/bootstrap/providers.php`; this spec should not register panel providers in `bootstrap/app.php`.
|
||||
- Global search: no globally searchable resource behavior should change. If a touched Resource is affected, verify View/Edit/global-search status remains valid or disabled.
|
||||
- Destructive actions: no destructive action is added. Existing Compare Now high-impact action must keep `->action(...)`, `->requiresConfirmation()`, capability authorization, OperationRun UX, and audit behavior.
|
||||
- Asset strategy: no Filament assets planned; no new `filament:assets` deployment requirement.
|
||||
|
||||
## Test Governance Check
|
||||
|
||||
- **Test purpose / classification by changed surface**: Unit for classifier/registry paths; Feature/Livewire for route/access/render/action URL contracts; Browser for integrated URL/shell/copy/reload/history behavior.
|
||||
- **Affected validation lanes**: fast-feedback, confidence, browser.
|
||||
- **Why this lane mix is the narrowest sufficient proof**: The defect spans code classification and browser-visible shell/copy; both must be proven.
|
||||
- **Narrowest proving command(s)**:
|
||||
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=BaselineCompare`
|
||||
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=AdminSurfaceScope`
|
||||
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=WorkspaceHubRegistry`
|
||||
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=DecisionRegister`
|
||||
- focused browser smoke for Spec 319
|
||||
- `cd apps/platform && ./vendor/bin/sail pint --test`
|
||||
- `git diff --check`
|
||||
- **Fixture / helper / factory / seed / context cost risks**: Existing workspace/environment/member setup plus baseline assignment/snapshot/run fixtures. Keep setup local to the new tests and avoid broad shared defaults.
|
||||
- **Expensive defaults or shared helper growth introduced?**: no.
|
||||
- **Heavy-family additions, promotions, or visibility changes**: Focused browser smoke only. Durable browser no-drift family is Spec 322.
|
||||
- **Surface-class relief / special coverage rule**: global-context-shell requires browser verification.
|
||||
- **Closing validation and reviewer handoff**: Reviewers must verify old URL invalidation, no query alias support, no remembered fallback, cross-workspace 404, and Decision Register regression.
|
||||
- **Budget / baseline / trend follow-up**: none expected.
|
||||
- **Review-stop questions**: Does any Baseline Compare path still render from `/admin/baseline-compare-landing`? Does any CTA still emit `environment_id`? Does any code path use remembered Environment to render Baseline Compare? Are Baselines/Baseline Snapshots accidentally pulled into this spec?
|
||||
- **Escalation path**: follow-up-spec for 320/321/322 only; update this spec if implementation reveals a route architecture blocker.
|
||||
- **Active feature PR close-out entry**: Guardrail and Smoke Coverage.
|
||||
- **Why no dedicated follow-up spec is needed**: Spec 319 is the dedicated Baseline Compare Environment-owned route fix.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/
|
||||
|-- spec.md
|
||||
|-- plan.md
|
||||
|-- tasks.md
|
||||
|-- checklists/
|
||||
| `-- requirements.md
|
||||
`-- artifacts/
|
||||
`-- screenshots/
|
||||
```
|
||||
|
||||
No `research.md`, `data-model.md`, `quickstart.md`, or `contracts/` artifact is required for preparation because this feature introduces no new data model, external API contract, or standalone workflow API.
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
Likely runtime files to inspect or update during implementation:
|
||||
|
||||
```text
|
||||
apps/platform/routes/web.php
|
||||
apps/platform/app/Providers/Filament/AdminPanelProvider.php
|
||||
apps/platform/app/Filament/Pages/BaselineCompareLanding.php
|
||||
apps/platform/app/Filament/Concerns/UsesAdminEnvironmentFilterQueryParameter.php
|
||||
apps/platform/app/Filament/Concerns/WorkspaceScopedEnvironmentRoutes.php
|
||||
apps/platform/app/Support/Navigation/AdminSurfaceScope.php
|
||||
apps/platform/app/Support/Navigation/WorkspaceHubRegistry.php
|
||||
apps/platform/app/Support/Navigation/WorkspaceSidebarNavigation.php
|
||||
apps/platform/app/Support/ManagedEnvironmentLinks.php
|
||||
apps/platform/app/Support/OperateHub/OperateHubShell.php
|
||||
apps/platform/app/Support/Middleware/EnsureEnvironmentContextSelected.php
|
||||
apps/platform/app/Filament/Pages/EnvironmentDashboard.php
|
||||
apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.php
|
||||
apps/platform/app/Filament/Widgets/ManagedEnvironment/BaselineCompareCoverageBanner.php
|
||||
apps/platform/app/Filament/Widgets/Dashboard/BaselineCompareNow.php
|
||||
apps/platform/app/Filament/Widgets/Dashboard/NeedsAttention.php
|
||||
apps/platform/app/Filament/Pages/BaselineCompareMatrix.php
|
||||
apps/platform/resources/views/filament/pages/baseline-compare-landing.blade.php
|
||||
apps/platform/tests/Unit/Tenants/AdminSurfaceScopeTest.php
|
||||
apps/platform/tests/Feature/Navigation/WorkspaceHubRegistryTest.php
|
||||
apps/platform/tests/Feature/Workspaces/GlobalContextShellContractTest.php
|
||||
apps/platform/tests/Feature/Filament/PanelNavigationSegregationTest.php
|
||||
apps/platform/tests/Feature/Filament/BaselineCompareLandingAdminTenantParityTest.php
|
||||
apps/platform/tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php
|
||||
apps/platform/tests/Feature/Governance/DecisionRegisterWorkspaceHubContractTest.php
|
||||
apps/platform/tests/Feature/Navigation/WorkspaceHubEnvironmentFilterContractTest.php
|
||||
apps/platform/tests/Feature/Navigation/WorkspaceHubClearFilterContractTest.php
|
||||
apps/platform/tests/Browser/
|
||||
```
|
||||
|
||||
Related pages to inspect, not automatically rewrite:
|
||||
|
||||
```text
|
||||
apps/platform/app/Filament/Pages/EnvironmentRequiredPermissions.php
|
||||
apps/platform/app/Filament/Pages/EnvironmentDiagnostics.php
|
||||
apps/platform/app/Filament/Pages/InventoryCoverage.php
|
||||
apps/platform/app/Filament/Resources/InventoryItemResource.php
|
||||
apps/platform/app/Filament/Resources/BackupScheduleResource.php
|
||||
apps/platform/app/Filament/Resources/BackupSetResource.php
|
||||
apps/platform/app/Filament/Resources/RestoreRunResource.php
|
||||
apps/platform/app/Filament/Resources/FindingResource.php
|
||||
apps/platform/app/Filament/Resources/FindingExceptionResource.php
|
||||
```
|
||||
|
||||
Explicitly out-of-scope unless analysis proves Environment ownership:
|
||||
|
||||
```text
|
||||
apps/platform/app/Filament/Resources/BaselineProfileResource.php
|
||||
apps/platform/app/Filament/Resources/BaselineSnapshotResource.php
|
||||
apps/platform/app/Filament/Pages/BaselineCompareMatrix.php
|
||||
apps/platform/app/Filament/Pages/CrossEnvironmentComparePage.php
|
||||
apps/platform/app/Filament/Pages/Monitoring/AuditLog.php
|
||||
apps/platform/app/Filament/Pages/Monitoring/Alerts.php
|
||||
apps/platform/app/Filament/Resources/Alert*
|
||||
```
|
||||
|
||||
**Structure Decision**: Laravel/Filament platform app under `apps/platform`; any runtime changes stay inside existing Page, Support, route, view, and test locations.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|---|---|---|
|
||||
| None planned | Route ownership can use existing Environment route/shell mechanisms | New compatibility adapters, query resolvers, or route frameworks are explicitly rejected |
|
||||
|
||||
## Proportionality Review
|
||||
|
||||
- **Current operator problem**: Baseline Compare renders Environment-specific copy/data through hidden context instead of explicit route ownership.
|
||||
- **Existing structure is insufficient because**: `/admin/baseline-compare-landing` cannot self-sufficiently establish Environment context after clear/reload and should not use `environment_id` as a workspace hub filter.
|
||||
- **Narrowest correct implementation**: Make Baseline Compare route-bound to Workspace + Environment, update links, and reject old access.
|
||||
- **Ownership cost created**: Focused tests and browser evidence for a high-risk page.
|
||||
- **Alternative intentionally rejected**: Supporting both old and new routes, redirecting old URLs by default, or accepting `environment_id` as canonical page context.
|
||||
- **Release truth**: Current-release hardening before production.
|
||||
|
||||
## Phase 0: Discovery Completed During Preparation
|
||||
|
||||
Repository facts confirmed before authoring this plan:
|
||||
|
||||
- Current branch before Spec Kit creation was `platform-dev`, clean, at `1c27af4f spec: add admin surface scope shell context audit (#373)`.
|
||||
- No existing `319-*` branch or `specs/319-*` package was present.
|
||||
- Spec Kit script created branch `319-environment-owned-surface-routing-shell-context-contract` and `specs/319-environment-owned-surface-routing-shell-context-contract/spec.md`.
|
||||
- Spec 318 is analysis-only and does not have plan/tasks files; it provides `mismatch-findings.md`, `audit-report.md`, `recommended-fixes.md`, `page-matrix.md`, screenshots, and state captures.
|
||||
- Spec 318 finding M1: Baseline Compare URLs are not self-sufficient. Direct clean and direct `environment_id` URLs return 403 after clearing Environment context; environment sidebar works only with remembered context.
|
||||
- Spec 318 recommended fix: route-bound Environment URL under `/admin/workspaces/{workspace}/environments/{environment}/baseline-compare`.
|
||||
- `BaselineCompareLanding` currently extends `Page`, is registered in `AdminPanelProvider`, uses `ResolvesPanelTenantContext` and `UsesAdminEnvironmentFilterQueryParameter`, and loads stats through `BaselineCompareStats::forTenant()`.
|
||||
- `BaselineCompareLanding::canAccess()` returns false without `ManagedEnvironment` from `resolveTenantContextForCurrentPanel()`.
|
||||
- `UsesAdminEnvironmentFilterQueryParameter` appends `environment_id` to the unbound page URL when `tenant` is provided.
|
||||
- `EnvironmentDashboardSummaryBuilder`, `BaselineCompareCoverageBanner`, `BaselineCompareNow`, `NeedsAttention`, and `BaselineCompareMatrix` currently generate Baseline Compare links via `BaselineCompareLanding::getUrl(tenant: $tenant)`.
|
||||
- `WorkspaceHubRegistry` does not list Baseline Compare; this is correct and must remain true.
|
||||
- `AdminSurfaceScope` currently treats `/admin/workspaces/{workspace}/environments/{environment}/...` as `EnvironmentBound`.
|
||||
- `EnsureEnvironmentContextSelected` already configures environment navigation for environment surfaces and workspace sidebar for workspace surfaces.
|
||||
- Existing test `BaselineCompareLandingAdminTenantParityTest` asserts access from remembered admin tenant; this likely asserts now-invalid behavior and must be replaced/updated.
|
||||
|
||||
## Technical Approach
|
||||
|
||||
### 1. Establish canonical Environment route
|
||||
|
||||
Preferred route shape:
|
||||
|
||||
```text
|
||||
/admin/workspaces/{workspace}/environments/{environment}/baseline-compare
|
||||
```
|
||||
|
||||
Use the repo's existing route-bound Environment pattern. The route should:
|
||||
|
||||
- run through admin panel middleware and workspace membership checks;
|
||||
- use existing `workspace` route binding;
|
||||
- use `{environment:slug}` or the established ManagedEnvironment route key;
|
||||
- validate Environment belongs to Workspace;
|
||||
- fail safe with 404/safe no-access on mismatch or missing entitlement;
|
||||
- produce `AdminSurfaceScope::EnvironmentBound`.
|
||||
|
||||
Implementation should prefer one canonical route and remove/disable the old unbound page route. If Filament Page auto-registration cannot be moved directly, wrap or override route generation narrowly without creating a compatibility layer.
|
||||
|
||||
### 2. Update Baseline Compare URL generation
|
||||
|
||||
Replace query-based Baseline Compare URL generation with route-owned URL generation for:
|
||||
|
||||
- Environment Dashboard summary/action payloads;
|
||||
- managed-environment Baseline Compare coverage banner;
|
||||
- dashboard Baseline Compare widget;
|
||||
- Needs Attention widget;
|
||||
- Baseline Compare Matrix per-Environment links;
|
||||
- any direct `BaselineCompareLanding::getUrl(tenant: $tenant)` call that opens the Environment-owned page.
|
||||
|
||||
The generated URL must not include:
|
||||
|
||||
```text
|
||||
environment_id
|
||||
tenant
|
||||
tenant_id
|
||||
managed_environment_id
|
||||
tenant_scope
|
||||
tableFilters
|
||||
```
|
||||
|
||||
### 3. Remove remembered fallback for Baseline Compare
|
||||
|
||||
Baseline Compare must render only when route context resolves an Environment. Implementation must not:
|
||||
|
||||
- rely on `WorkspaceContext::rememberedEnvironment()`;
|
||||
- rely on `Filament::getTenant()` as fallback for old URL;
|
||||
- infer from provider tenant identifiers;
|
||||
- treat `environment_id` as page context;
|
||||
- silently switch Workspace.
|
||||
|
||||
If `BaselineCompareLanding` keeps `ResolvesPanelTenantContext`, its route/category must force the context to come from the route.
|
||||
|
||||
### 4. Classification and navigation
|
||||
|
||||
Baseline Compare should classify as Environment-owned through the Environment route. Tests must prove:
|
||||
|
||||
- new canonical path is `AdminSurfaceScope::EnvironmentBound`;
|
||||
- old path is not a workspace hub and does not render;
|
||||
- `WorkspaceHubRegistry` does not include Baseline Compare;
|
||||
- workspace sidebar does not show Baseline Compare as a workspace-wide hub;
|
||||
- environment sidebar/action placement remains Environment-owned if present.
|
||||
|
||||
### 5. Cross-workspace and no-access protection
|
||||
|
||||
Route/model resolution must enforce:
|
||||
|
||||
```php
|
||||
(int) $environment->workspace_id === (int) $workspace->getKey()
|
||||
```
|
||||
|
||||
Invalid combinations return 404/safe no-access. Do not leak Environment existence, switch workspace, or fallback to remembered Environment.
|
||||
|
||||
### 6. Shell, breadcrumb, copy
|
||||
|
||||
The valid page must show:
|
||||
|
||||
- selected Workspace;
|
||||
- selected Environment;
|
||||
- Baseline Compare header/title;
|
||||
- breadcrumb or equivalent ownership signal;
|
||||
- "this environment" copy only with active Environment shell.
|
||||
|
||||
When Environment context is missing, the page should not render.
|
||||
|
||||
### 7. Regression scope
|
||||
|
||||
Keep these contracts unchanged:
|
||||
|
||||
- Decision Register clean workspace hub route;
|
||||
- Decision Register `environment_id` filtered workspace hub route with visible chip;
|
||||
- clear filter behavior from Spec 316;
|
||||
- legacy tenant cleanup from Spec 317;
|
||||
- workspace hubs from Specs 314-316.
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
1. Guardrail and discovery: re-check branch/status, confirm exact current route names, inspect affected Baseline Compare links, and record the old route behavior.
|
||||
2. Tests first/alongside: add classification, access, route, CTA, remembered fallback, cross-workspace, copy/shell, and Decision Register regression tests.
|
||||
3. Route/link implementation: make canonical Environment route authoritative and update Baseline Compare URL generators.
|
||||
4. Shell/copy/navigation cleanup: remove query/remembered fallback assumptions and ensure breadcrumbs/shell align.
|
||||
5. Related page inspection: only fix pages with the same proven Environment-owned mismatch.
|
||||
6. Validation: focused Pest, browser smoke, formatting, `git diff --check`, and implementation close-out.
|
||||
|
||||
## Migration / Data / Deployment Impact
|
||||
|
||||
- **Migrations**: none planned.
|
||||
- **Seeders**: none planned.
|
||||
- **Packages**: none planned.
|
||||
- **Env vars**: none planned.
|
||||
- **Queues/scheduler/storage**: no changes planned.
|
||||
- **Filament assets**: no new assets planned; no new `filament:assets` deployment step.
|
||||
- **Dokploy/Sail**: ordinary code deployment only if implementation changes runtime files.
|
||||
|
||||
## Browser Verification Plan
|
||||
|
||||
Use the in-app browser or the repository's browser smoke workflow against local Sail once runtime changes exist.
|
||||
|
||||
Required screenshots:
|
||||
|
||||
```text
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/environment-cta--baseline-compare.png
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/direct-clean--baseline-compare--rejected.png
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/direct-filtered--baseline-compare--rejected.png
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/baseline-compare--after-reload.png
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/baseline-compare--back-forward.png
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/decision-register--regression.png
|
||||
```
|
||||
|
||||
If a route is fully absent and cannot be screenshotted, document route absence in the close-out and capture the nearest browser proof if useful.
|
||||
|
||||
## Risks and Controls
|
||||
|
||||
- **Risk**: Old tests assert remembered Environment fallback.
|
||||
**Control**: Replace them with no-remembered-fallback and canonical route tests.
|
||||
- **Risk**: Filament auto page registration keeps old slug alive.
|
||||
**Control**: Use the narrowest supported page route override or explicit Laravel route pattern and test old URL invalidation.
|
||||
- **Risk**: Link helpers spread query-based Baseline Compare URLs.
|
||||
**Control**: `rg` all `BaselineCompareLanding::getUrl`, `baseline-compare-landing`, and `environment_id` occurrences and update only in-scope Baseline Compare links.
|
||||
- **Risk**: Workspace-owned baseline pages get pulled into scope.
|
||||
**Control**: Keep Baselines/Baseline Snapshots/Matrix out unless proven Environment-owned; record follow-up 320.
|
||||
- **Risk**: Browser flow depends on local fixture data.
|
||||
**Control**: Use existing local fixture environment from Spec 318 where possible or create test data through normal app factories/tests; document browser blockers.
|
||||
|
||||
## Readiness Gate
|
||||
|
||||
Spec 319 is implementation-ready when:
|
||||
|
||||
- `spec.md`, `plan.md`, `tasks.md`, and `checklists/requirements.md` exist.
|
||||
- The scope is Baseline Compare-first and bounded.
|
||||
- No open question blocks implementation.
|
||||
- Required tests and browser flows are named.
|
||||
- No application implementation has happened during prep.
|
||||
- Candidate Selection Gate and Spec Readiness Gate pass.
|
||||
@ -0,0 +1,489 @@
|
||||
# Feature Specification: Environment-Owned Surface Routing & Shell Context Contract
|
||||
|
||||
**Feature Branch**: `319-environment-owned-surface-routing-shell-context-contract`
|
||||
**Created**: 2026-05-16
|
||||
**Status**: Completed
|
||||
**Input**: User supplied Spec 319 draft: Baseline Compare and similar Environment-owned pages must route through explicit Workspace + Environment ownership, with no legacy workspace-style access, no `environment_id` filter model, and no remembered Environment fallback.
|
||||
|
||||
## Spec Candidate Check *(mandatory - SPEC-GATE-001)*
|
||||
|
||||
- **Problem**: Baseline Compare behaves as an Environment-owned page but currently uses an unbound workspace-style Filament page URL, so route, shell, breadcrumb, copy, and access semantics can disagree.
|
||||
- **Today's failure**: Operators can see "this environment" copy only because remembered Environment state happens to exist; after context clear, direct clean and direct `environment_id` URLs fail or behave inconsistently instead of being self-sufficient route-owned Environment pages.
|
||||
- **User-visible improvement**: Baseline Compare is opened from an Environment route, reloads safely, shows Workspace + Environment shell context, rejects cross-workspace access, and no longer looks like a workspace hub or hidden filter state.
|
||||
- **Smallest enterprise-capable version**: Hard-cut Baseline Compare to a canonical route-bound Environment page and update its entry points, classification, shell/breadcrumb/copy, and regression coverage. Inspect adjacent Environment-owned pages only for the same mismatch.
|
||||
- **Explicit non-goals**: No workspace-wide Baseline Compare, no `environment_id` filter support for Baseline Compare, no compatibility redirects, no legacy query aliases, no Spec 320 workspace-owned analysis fixes, no Spec 321 Alerts/Audit filter decision, no durable browser infrastructure from Spec 322.
|
||||
- **Permanent complexity imported**: No new persisted entities, tables, enum families, status families, broad registries, or cross-domain frameworks. Expected complexity is route/classification/link/test updates over existing Filament/Laravel structures.
|
||||
- **Why now**: Spec 318 identified Baseline Compare as the highest-risk remaining shell/context mismatch after Specs 314-317 stabilized workspace hubs and legacy cleanup.
|
||||
- **Why not local**: A copy-only or CTA-only fix would leave direct URL, reload, cross-workspace, shell, and remembered-fallback risks unresolved.
|
||||
- **Approval class**: Cleanup / Consolidation.
|
||||
- **Red flags triggered**: "Many surfaces, little user value" is avoided by making Baseline Compare required and keeping other pages inspect-only unless the same mismatch is proven. No new axis or framework is introduced.
|
||||
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitat: 2 | Produktnahe: 2 | Wiederverwendung: 1 | **Gesamt: 11/12**
|
||||
- **Decision**: approve.
|
||||
|
||||
## Spec Scope Fields *(mandatory)*
|
||||
|
||||
- **Scope**: workspace + environment route-owned admin surface.
|
||||
- **Primary Routes**: Baseline Compare, canonical Environment Dashboard Baseline Compare CTA/action, relevant Environment sidebar/navigation entry if present.
|
||||
- **Data Ownership**: Existing workspace-owned Baseline Profile/Snapshot truth and Environment-owned compare/assignment/result state only. No schema changes.
|
||||
- **RBAC**: Workspace membership plus Environment entitlement. Non-member or cross-workspace Environment access returns 404/safe no-access. Member missing capability follows existing capability behavior.
|
||||
|
||||
For canonical-view specs:
|
||||
|
||||
- **Default filter behavior when tenant-context is active**: Not a canonical workspace view. Baseline Compare must not use active/remembered Environment as fallback.
|
||||
- **Explicit entitlement checks preventing cross-tenant leakage**: Environment route resolution must validate `managed_environments.workspace_id === workspaces.id` before rendering or revealing Environment existence.
|
||||
|
||||
## Cross-Cutting / Shared Pattern Reuse *(mandatory)*
|
||||
|
||||
- **Cross-cutting feature?**: yes.
|
||||
- **Interaction class(es)**: navigation entry points, shell/context bar, breadcrumbs, dashboard CTAs, route helpers, page copy, action links.
|
||||
- **Systems touched**: `AdminSurfaceScope`, `WorkspaceHubRegistry`, `WorkspaceSidebarNavigation`, `WorkspaceScopedEnvironmentRoutes`, `ManagedEnvironmentLinks`, `OperateHubShell`, `BaselineCompareLanding`, Environment Dashboard summary/action builders, relevant widgets, routes, and tests.
|
||||
- **Existing pattern(s) to extend**: Route-bound Environment pattern under `/admin/workspaces/{workspace}/environments/{environment}/...` and existing workspace/environment shell resolution.
|
||||
- **Shared contract / presenter / builder / renderer to reuse**: Reuse `WorkspaceScopedEnvironmentRoutes`/route-bound Environment conventions where possible, `ManagedEnvironmentLinks` for canonical Environment URLs if a helper is needed, and existing Filament navigation/page patterns.
|
||||
- **Why the existing shared path is sufficient or insufficient**: Existing route-bound Environment pages already produce correct shell behavior. Baseline Compare is the outlier because it remains a Filament page on `/admin/baseline-compare-landing` plus query/helper fallback.
|
||||
- **Allowed deviation and why**: None for Baseline Compare. A redirect from old workspace-style URLs is disallowed unless implementation discovers an existing mandatory convention and covers it with tests.
|
||||
- **Consistency impact**: Environment-owned pages must not behave as workspace hubs or filtered workspace hubs. Copy saying "this environment" is valid only with active Environment shell context.
|
||||
- **Review focus**: Verify no compatibility path, query alias, remembered fallback, or workspace hub registry entry makes Baseline Compare render outside route-owned Environment context.
|
||||
|
||||
## OperationRun UX Impact
|
||||
|
||||
- **Touches OperationRun start/completion/link UX?**: yes, existing Baseline Compare "Compare now" action and run links must keep their current UX contract.
|
||||
- **Shared OperationRun UX contract/layer reused**: Existing `OperationUxPresenter`, `OpsUxBrowserEvents`, and `OperationRunLinks`.
|
||||
- **Delegated start/completion UX behaviors**: Existing queued toast, "Open operation" link, tenant/workspace-safe URL resolution, and run-enqueued browser event remain delegated to existing shared helpers.
|
||||
- **Local surface-owned behavior that remains**: Baseline Compare page still owns initiation inputs and page state.
|
||||
- **Queued DB-notification policy**: N/A - no new notification policy.
|
||||
- **Terminal notification path**: Existing OperationRun lifecycle only.
|
||||
- **Exception required?**: none.
|
||||
|
||||
## Provider Boundary / Platform Core Check
|
||||
|
||||
- **Shared provider/platform boundary touched?**: yes.
|
||||
- **Boundary classification**: platform-core route/shell contract; provider-specific Tenant identity remains provider-owned only.
|
||||
- **Seams affected**: route shape, navigation helpers, page classification, shell resolution, query key handling, and visible Workspace/Environment copy.
|
||||
- **Neutral platform terms preserved or introduced**: `Workspace`, `Environment`, `Environment-owned page`, `Workspace hub`, `filtered workspace hub`, `Baseline Compare`.
|
||||
- **Provider-specific semantics retained and why**: Existing Microsoft/Intune baseline compare domain behavior remains unchanged. Provider tenant IDs must not become route or fallback identifiers for this page.
|
||||
- **Why this does not deepen provider coupling accidentally**: The canonical route uses platform Workspace + Managed Environment route identity, not Microsoft tenant IDs or Graph payload identity.
|
||||
- **Follow-up path**: Specs 320, 321, and 322 handle adjacent workspace analysis, Alerts/Audit decisions, and durable browser guards.
|
||||
|
||||
## 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 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| Baseline Compare | yes | Existing Filament Page + Blade view | navigation, shell, breadcrumb, action links | route, shell, page, copy | no | Route/shell hardening only; no redesign. |
|
||||
| Environment Dashboard Baseline Compare CTA | yes | Existing Filament/Blade summary/action | dashboard CTA, navigation | URL generation | no | Must emit Environment-owned route, not `environment_id`. |
|
||||
| Decision Register regression | yes | Existing Filament Page | workspace hub/filter contract | URL query, shell, chip | no | Regression only; behavior must not change. |
|
||||
|
||||
## 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 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| Baseline Compare | Secondary Context | Operator decides whether the selected Environment has baseline assignment/result work to run or review | Environment identity, assignment state, compare posture, next action | run detail, findings, evidence gaps, compare matrix | It is Environment governance context, not workspace-wide triage | Opened from Environment Dashboard/governance posture | Removes hidden context reconstruction and broken direct links. |
|
||||
| Environment Dashboard Baseline Compare CTA | Primary Decision Link | Operator follows Environment posture finding to compare posture | Baseline compare status/action | Baseline Compare page | Link must preserve Environment ownership | Environment Dashboard -> Environment-owned Baseline Compare | One click to the correct scoped page. |
|
||||
| Decision Register | Primary Decision Surface | Operator reviews workspace governance decisions | workspace shell, optional Environment filter chip if filtered | finding/exception/evidence links | Regression only | Existing workspace hub | Prevents accidental shell/filter drift. |
|
||||
|
||||
## 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 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| Baseline Compare | operator-MSP, support-platform | Environment, assignment state, compare posture, next action | coverage, evidence gaps, run links | raw Graph payloads remain out of scope/default-hidden | Assign baseline, compare now, or review results depending on state | raw payloads/debug details | Shell and copy must say the same Environment truth once. |
|
||||
| Environment Dashboard CTA | operator-MSP | Baseline compare card/action | none | none | Open Baseline Compare | N/A | CTA URL itself carries Environment ownership. |
|
||||
|
||||
## 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 |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| Baseline Compare | Workflow / Page | Environment-owned governance posture page | Open compare, compare now, view run/findings | Page-level Environment route | N/A | Header/actions or existing page sections | Existing Compare Now confirmation stays header/action | N/A | `/admin/workspaces/{workspace}/environments/{environment}/baseline-compare` | Workspace + Environment shell | Baseline Compare | selected Environment, baseline assignment/result state | none |
|
||||
| Decision Register | List / Hub | Workspace hub / filtered workspace hub | Review decisions | existing page/table | existing behavior | existing behavior | existing behavior | `/admin/governance/decisions` | existing detail links | Workspace shell, optional filter chip | Decision register | workspace-wide or filtered decision state | regression only |
|
||||
|
||||
## 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 |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| Baseline Compare | Workspace operator / manager | Decide whether to assign baseline, run compare, or inspect compare outcome for one Environment | Environment-owned posture page | What is this Environment's baseline compare posture? | Environment shell, assignment state, compare status, next action | evidence gaps, run detail links, compare matrix | assignment, compare state, data completeness, governance result | TenantPilot operation queue and Microsoft read/sync behavior as already implemented | Compare now, view findings/run, open matrix | Existing Compare Now is high-impact and must keep confirmation + authorization. |
|
||||
|
||||
## Proportionality Review *(mandatory when structural complexity is introduced)*
|
||||
|
||||
- **New source of truth?**: no.
|
||||
- **New persisted entity/table/artifact?**: no.
|
||||
- **New abstraction?**: no planned abstraction; reuse existing route/shell helpers.
|
||||
- **New enum/state/reason family?**: no.
|
||||
- **New cross-domain UI framework/taxonomy?**: no.
|
||||
- **Current operator problem**: Environment-owned Baseline Compare is not route-owned and can show environment copy only because hidden context exists.
|
||||
- **Existing structure is insufficient because**: The current unbound Filament page URL and `environment_id` query helper cannot reliably establish shell/context after environment context is cleared.
|
||||
- **Narrowest correct implementation**: Put Baseline Compare on the existing Environment route family, update links/classification, and remove invalid workspace-style access.
|
||||
- **Ownership cost**: Focused route/link/page tests and browser smoke for a high-risk page.
|
||||
- **Alternative intentionally rejected**: Accept `environment_id` query or remembered session fallback for Baseline Compare; both preserve ambiguity and conflict with Specs 314-317.
|
||||
- **Release truth**: Current-release cleanup before production.
|
||||
|
||||
### Compatibility posture
|
||||
|
||||
This feature assumes pre-production hard cutover.
|
||||
|
||||
Backward compatibility, legacy aliases, old workspace-style Baseline Compare routes, redirects, migration shims, and compatibility-specific tests are out of scope.
|
||||
|
||||
Canonical replacement is preferred over preservation.
|
||||
|
||||
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
|
||||
|
||||
- **Test purpose / classification**: Unit for classifier/registry helpers; Feature/Livewire for route/access/page rendering and CTA URL generation; Browser for shell/copy/reload/back-forward verification.
|
||||
- **Validation lane(s)**: fast-feedback, confidence, browser.
|
||||
- **Why this classification and these lanes are sufficient**: Unit/feature tests prove route and authorization contracts; browser smoke is required because the issue is visible shell/copy/navigation drift.
|
||||
- **New or expanded test families**: Focused Spec 319 route/shell tests. Browser screenshots under this spec folder. No durable browser framework.
|
||||
- **Fixture / helper cost impact**: Existing Workspace, ManagedEnvironment, membership/capability, baseline assignment/snapshot/run factories. Avoid new global seeders or broad helpers.
|
||||
- **Heavy-family visibility / justification**: Browser smoke is explicit and limited to Baseline Compare plus Decision Register regression.
|
||||
- **Special surface test profile**: global-context-shell.
|
||||
- **Standard-native relief or required special coverage**: Special coverage required for route/shell/copy consistency.
|
||||
- **Reviewer handoff**: Verify no app code can render Baseline Compare from clean workspace-only URL, filtered workspace-style URL, remembered Environment, or cross-workspace Environment.
|
||||
- **Budget / baseline / trend impact**: none expected.
|
||||
- **Escalation needed**: none for 319; adjacent surfaces deferred to 320/321/322.
|
||||
- **Active feature PR close-out entry**: Guardrail and Smoke Coverage.
|
||||
- **Planned validation commands**:
|
||||
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=BaselineCompare`
|
||||
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=AdminSurfaceScope`
|
||||
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=WorkspaceHubRegistry`
|
||||
- `cd apps/platform && ./vendor/bin/sail artisan test --filter=DecisionRegister`
|
||||
- focused browser smoke for Spec 319 flows
|
||||
- `cd apps/platform && ./vendor/bin/sail pint --test`
|
||||
- `git diff --check`
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Open Baseline Compare from Environment context (Priority: P1)
|
||||
|
||||
As an operator on an Environment Dashboard, I can open Baseline Compare through an Environment-owned URL and see Workspace + Environment shell context, so the page's "this environment" copy is truthful.
|
||||
|
||||
**Why this priority**: This fixes the highest-risk Spec 318 mismatch and makes the main Environment Dashboard CTA safe.
|
||||
|
||||
**Independent Test**: From an authorized Workspace A / Environment A context, click the Baseline Compare CTA and assert route, shell, header, copy, and data scope all point to Environment A.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** Workspace A and Environment A, **When** the operator opens Baseline Compare from Environment Dashboard, **Then** the URL includes Workspace A and Environment A route identity and no `environment_id` query.
|
||||
2. **Given** Environment A has no assigned baseline, **When** Baseline Compare renders, **Then** the shell shows Workspace A + Environment A and copy may say "this environment does not have an assigned baseline yet."
|
||||
3. **Given** the operator reloads the page, **When** the browser refreshes, **Then** the same Workspace + Environment shell and copy remain aligned without session fallback.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Reject invalid workspace-style access (Priority: P1)
|
||||
|
||||
As a security reviewer, I need workspace-only and workspace-style filtered Baseline Compare URLs to fail safely, so hidden remembered Environment state cannot render Environment-specific pages.
|
||||
|
||||
**Why this priority**: The old URL model is the root of the shell/context ambiguity.
|
||||
|
||||
**Independent Test**: Clear remembered Environment context, open old clean and filtered Baseline Compare URLs, and assert the page does not render.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** remembered Environment state exists, **When** it is cleared and the old clean Baseline Compare URL is opened, **Then** the page returns 404/safe no-access or no route and does not render Baseline Compare.
|
||||
2. **Given** a workspace-style Baseline Compare URL includes `?environment_id=...`, **When** it is opened, **Then** it does not render as canonical Baseline Compare and does not use the query as a filter.
|
||||
3. **Given** Workspace A and Environment B from Workspace B, **When** a URL combines them, **Then** the response is 404/safe no-access and does not reveal Environment B.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Preserve workspace hub behavior (Priority: P2)
|
||||
|
||||
As an operator using Decision Register and other workspace hubs, I need Spec 319 not to regress the clean workspace hub, filtered workspace hub, and clear-filter contracts from Specs 314-316.
|
||||
|
||||
**Why this priority**: Baseline Compare must move out of ambiguous workspace-style handling without destabilizing the workspace hub model.
|
||||
|
||||
**Independent Test**: Open Decision Register clean and filtered URLs and verify shell/filter behavior still matches Specs 314-316.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the operator opens Decision Register from workspace sidebar, **When** the page loads, **Then** shell has Workspace only and no active Environment.
|
||||
2. **Given** the operator opens Decision Register with `environment_id`, **When** the page loads, **Then** it shows a visible Environment filter chip and shell remains Workspace only.
|
||||
3. **Given** the operator clears the Decision Register filter, **When** the page reloads, **Then** URL and state return to the clean workspace hub.
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- Environment route contains an Environment from another Workspace.
|
||||
- Environment exists but the actor is not entitled to it.
|
||||
- Workspace context is missing but the route contains a valid Environment.
|
||||
- Environment has no baseline assignment.
|
||||
- Environment has assignment but no usable active snapshot.
|
||||
- Environment has a running, failed, partially succeeded, or stale compare run.
|
||||
- Browser back/forward moves between Environment-owned Baseline Compare and workspace-owned Decision Register.
|
||||
- A legacy query includes `tenant`, `tenant_id`, `managed_environment_id`, `tenant_scope`, `environment`, or `tableFilters`.
|
||||
- Existing Compare Now action is rendered after the route change and still has confirmation, capability gating, and OperationRun UX.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
**Constitution alignment (required):** This feature introduces no Graph calls, no new write behavior, and no new long-running/queued work. Existing Baseline Compare run behavior remains in place and must keep `OperationRun` observability, authorization, confirmation, and tests.
|
||||
|
||||
**Constitution alignment (PROP-001 / ABSTR-001 / PERSIST-001 / STATE-001 / BLOAT-001):** The spec introduces no new persistence, no new state family, no new broad abstraction, and no new taxonomy. It replaces ambiguous routing with existing Environment route ownership.
|
||||
|
||||
**Constitution alignment (XCUT-001):** Baseline Compare links and shell state reuse existing route, navigation, shell, and OperationRun helper paths rather than adding a parallel local context mechanism.
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: Baseline Compare MUST be classified as an Environment-owned page.
|
||||
- **FR-002**: Baseline Compare MUST NOT be listed in `WorkspaceHubRegistry` or treated as a workspace hub.
|
||||
- **FR-003**: Baseline Compare MUST NOT use `WorkspaceHubEnvironmentFilter` or `environment_id` as its primary access model.
|
||||
- **FR-004**: Baseline Compare MUST have a canonical Environment-owned route that includes Workspace and Environment identity.
|
||||
- **FR-005**: The canonical route MUST validate that the Environment belongs to the Workspace before rendering.
|
||||
- **FR-006**: Cross-workspace Environment route access MUST return 404/safe no-access without workspace switching or existence leakage.
|
||||
- **FR-007**: Clean workspace-only Baseline Compare URL MUST NOT render the page.
|
||||
- **FR-008**: Workspace-style Baseline Compare URL with `?environment_id=...` MUST NOT render as canonical Baseline Compare.
|
||||
- **FR-009**: Baseline Compare MUST NOT resolve Environment from remembered Environment, last Environment, Filament tenant fallback, provider tenant ID, or session fallback.
|
||||
- **FR-010**: Valid canonical Baseline Compare route MUST show Workspace + active Environment shell context.
|
||||
- **FR-011**: Baseline Compare breadcrumbs/header/copy MUST indicate Environment ownership and align with shell context.
|
||||
- **FR-012**: Copy saying "this environment" MUST NOT render without active Environment shell context.
|
||||
- **FR-013**: Environment Dashboard Baseline Compare CTA/action MUST use the canonical Environment-owned route.
|
||||
- **FR-014**: Environment Dashboard Baseline Compare CTA/action MUST emit no `environment_id`, `tenant`, `tenant_id`, `managed_environment_id`, `tenant_scope`, or `tableFilters`.
|
||||
- **FR-015**: Environment sidebar/navigation entry for Baseline Compare, if present, MUST be visibly Environment-owned and route-bound.
|
||||
- **FR-016**: Baseline Compare MUST not appear as a workspace-wide sidebar hub.
|
||||
- **FR-017**: Existing Compare Now action MUST preserve `->action(...)`, `->requiresConfirmation()`, server-side authorization/capability enforcement, OperationRun start UX, and audit behavior.
|
||||
- **FR-018**: Direct route/browser reload MUST keep shell and copy aligned without session fallback.
|
||||
- **FR-019**: Browser back/forward between Baseline Compare and Decision Register MUST preserve Environment shell for Baseline Compare and workspace shell for Decision Register.
|
||||
- **FR-020**: Decision Register MUST remain a workspace hub and optional filtered workspace hub.
|
||||
- **FR-021**: Specs 314, 315, 316, and 317 regression contracts MUST remain green.
|
||||
- **FR-022**: Required related Environment-owned pages MUST be inspected and fixed only if the same mismatch is proven: Required Permissions, Provider Readiness/Diagnostics, Inventory/Coverage, Backup/Restore Environment-owned views, Drift/Findings Environment-owned pages, and Environment-owned baseline drilldowns.
|
||||
- **FR-023**: Workspace-owned baseline analysis/library surfaces such as Baselines and Baseline Snapshots MUST remain out of scope for Spec 319 unless repo analysis proves they are actually Environment-owned.
|
||||
- **FR-024**: Alerts and Audit Log Environment filter decisions MUST remain out of scope for Spec 321.
|
||||
- **FR-025**: No migrations, seeders, packages, env vars, queues, scheduler, storage, or deployment asset changes are allowed unless implementation proves the route fix is impossible without one and the spec is updated first.
|
||||
|
||||
### Non-Functional Requirements
|
||||
|
||||
- **NFR-001**: Access failures must use deny-as-not-found semantics for membership and cross-workspace isolation.
|
||||
- **NFR-002**: Page render must not make Graph calls.
|
||||
- **NFR-003**: Route/link changes must not add measurable query overhead beyond existing scoped model resolution.
|
||||
- **NFR-004**: Tests must use the narrowest honest lane and keep browser coverage focused.
|
||||
- **NFR-005**: Filament v5 / Livewire v4 compliance must be preserved.
|
||||
- **NFR-006**: Laravel 12 panel provider registration remains in `apps/platform/bootstrap/providers.php`.
|
||||
- **NFR-007**: No new Filament assets are planned; deployment `filament:assets` requirement does not change.
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **Workspace**: Primary platform context and route owner.
|
||||
- **ManagedEnvironment**: Secondary operational context inside a Workspace; route-bound for Environment-owned pages.
|
||||
- **BaselineProfile**: Workspace-owned baseline definition.
|
||||
- **BaselineTenantAssignment**: Existing Environment assignment to a baseline profile.
|
||||
- **BaselineSnapshot**: Existing immutable baseline artifact.
|
||||
- **OperationRun**: Existing observable run truth for Baseline Compare execution.
|
||||
|
||||
## Current Repo Findings To Preserve
|
||||
|
||||
- Spec 318 classified Baseline Compare as "Environment page implemented on unbound URL" with high risk.
|
||||
- `BaselineCompareLanding` is registered in `AdminPanelProvider` as a Filament Page and currently uses `UsesAdminEnvironmentFilterQueryParameter`.
|
||||
- `BaselineCompareLanding::canAccess()` requires `resolveTenantContextForCurrentPanel()` to produce a `ManagedEnvironment`.
|
||||
- `BaselineCompareStats::forTenant()` makes Baseline Compare behavior Environment-specific.
|
||||
- Environment Dashboard summary and widgets currently call `BaselineCompareLanding::getUrl(tenant: $tenant)`, which produces `/admin/baseline-compare-landing?environment_id=...`.
|
||||
- `OperateHubShell::resolveQueryTenantHint()` currently resolves `tenant` and `managed_environment_id`, not canonical `environment_id`.
|
||||
- `WorkspaceHubRegistry` does not include Baseline Compare, which is correct and must remain true.
|
||||
- Direct clean and direct `environment_id` Baseline Compare URLs fail after context clear, proving the current URL is not self-sufficient.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Decision Register behavior changes beyond regression coverage.
|
||||
- Workspace hub behavior changes from Specs 314-316.
|
||||
- `environment_id` filter support for Baseline Compare.
|
||||
- Workspace-wide Baseline Compare.
|
||||
- Spec 320 workspace-owned analysis page registration and shell cutover.
|
||||
- Spec 321 Alerts/Audit Log Environment filter decision.
|
||||
- Spec 322 durable browser no-drift regression infrastructure.
|
||||
- Baseline feature redesign.
|
||||
- Baseline assignment semantic changes except where route correctness requires link/access updates.
|
||||
- Migrations, seeders, packages, env vars, queues, scheduler, storage, or deployment asset changes.
|
||||
- Compatibility redirects, dual routes, legacy aliases, or remembered fallback support.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
### Baseline Compare Classification
|
||||
|
||||
- [x] Baseline Compare is classified as Environment-owned.
|
||||
- [x] Baseline Compare is not in `WorkspaceHubRegistry`.
|
||||
- [x] Baseline Compare is not treated as a filtered workspace hub.
|
||||
- [x] Baseline Compare does not use `environment_id` as primary access contract.
|
||||
- [x] Baseline Compare does not use remembered Environment fallback.
|
||||
|
||||
### Baseline Compare Route Contract
|
||||
|
||||
- [x] Canonical Baseline Compare route includes Environment ownership.
|
||||
- [x] Environment belongs to Workspace.
|
||||
- [x] Cross-workspace Environment is rejected.
|
||||
- [x] Clean workspace-only Baseline Compare route is removed, invalid, or safe no-access.
|
||||
- [x] Workspace-style `?environment_id=...` Baseline Compare route is removed, invalid, or non-canonical.
|
||||
- [x] No legacy query params are accepted.
|
||||
|
||||
### Shell / Breadcrumb / Copy
|
||||
|
||||
- [x] Baseline Compare shell shows Workspace + Environment.
|
||||
- [x] Breadcrumbs indicate Environment ownership.
|
||||
- [x] Header/copy agrees with Environment ownership.
|
||||
- [x] "This environment" copy never appears without active Environment shell context.
|
||||
- [x] Reload keeps shell/copy aligned.
|
||||
- [x] Browser back/forward keeps shell/copy aligned.
|
||||
|
||||
### Navigation / CTA
|
||||
|
||||
- [x] Environment Dashboard Baseline Compare CTA uses Environment-owned route.
|
||||
- [x] CTA emits no `environment_id`.
|
||||
- [x] CTA emits no `tenant`.
|
||||
- [x] CTA emits no `tenant_id`.
|
||||
- [x] CTA emits no `managed_environment_id`.
|
||||
- [x] CTA emits no `tenant_scope`.
|
||||
- [x] CTA emits no `tableFilters`.
|
||||
- [x] Baseline Compare does not appear as workspace-wide sidebar hub.
|
||||
|
||||
### Related Environment Pages
|
||||
|
||||
- [x] Any touched Environment-owned page keeps Environment shell context.
|
||||
- [x] No touched Environment-owned page becomes workspace hub by accident.
|
||||
- [x] No touched Environment-owned page uses remembered Environment fallback.
|
||||
|
||||
### Regression
|
||||
|
||||
- [x] Decision Register remains workspace hub.
|
||||
- [x] Workspace hub clean entry from Spec 314 remains green.
|
||||
- [x] Environment CTA `environment_id` contract from Spec 315 remains green for workspace hubs.
|
||||
- [x] Clear filter contract from Spec 316 remains green.
|
||||
- [x] Legacy Tenant cleanup from Spec 317 remains green.
|
||||
- [x] Spec 318 mismatch is resolved for Baseline Compare.
|
||||
|
||||
### Tests / Browser
|
||||
|
||||
- [x] Required tests added.
|
||||
- [x] Existing tests updated only if they asserted broken old behavior.
|
||||
- [x] No broad rebaseline.
|
||||
- [x] Focused browser verification completed.
|
||||
- [x] Screenshots saved where useful.
|
||||
- [x] `git diff --check` passes.
|
||||
- [x] Formatting passes.
|
||||
|
||||
## Browser Verification Required
|
||||
|
||||
### Flow A - Environment Dashboard CTA
|
||||
|
||||
1. Open Environment Dashboard.
|
||||
2. Click Baseline Compare CTA/action.
|
||||
3. Verify URL is Environment-owned route.
|
||||
4. Verify URL has no `environment_id` or legacy params.
|
||||
5. Verify shell shows Workspace + Environment.
|
||||
6. Verify breadcrumb/header/copy align.
|
||||
7. Capture screenshot:
|
||||
|
||||
```text
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/environment-cta--baseline-compare.png
|
||||
```
|
||||
|
||||
### Flow B - Direct Clean Workspace URL
|
||||
|
||||
1. Open old/clean workspace-only Baseline Compare URL if route exists.
|
||||
2. Verify page does not render as valid Baseline Compare.
|
||||
3. Verify no remembered Environment fallback.
|
||||
4. Capture screenshot or document route absence:
|
||||
|
||||
```text
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/direct-clean--baseline-compare--rejected.png
|
||||
```
|
||||
|
||||
### Flow C - Direct Workspace Filtered URL
|
||||
|
||||
1. Open workspace-style Baseline Compare URL with `?environment_id=...` if route exists.
|
||||
2. Verify this is not canonical and does not render valid Baseline Compare.
|
||||
3. Capture screenshot or document route absence:
|
||||
|
||||
```text
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/direct-filtered--baseline-compare--rejected.png
|
||||
```
|
||||
|
||||
### Flow D - Reload
|
||||
|
||||
1. Open canonical Environment Baseline Compare route.
|
||||
2. Reload.
|
||||
3. Verify shell remains Workspace + Environment.
|
||||
4. Verify no fallback/session mismatch.
|
||||
5. Capture screenshot:
|
||||
|
||||
```text
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/baseline-compare--after-reload.png
|
||||
```
|
||||
|
||||
### Flow E - Back/Forward
|
||||
|
||||
1. Environment Dashboard -> Baseline Compare.
|
||||
2. Navigate to Decision Register.
|
||||
3. Browser back.
|
||||
4. Verify Baseline Compare has Environment shell.
|
||||
5. Browser forward.
|
||||
6. Verify Decision Register has Workspace shell and no active Environment unless filtered.
|
||||
7. Capture screenshots where useful:
|
||||
|
||||
```text
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/baseline-compare--back-forward.png
|
||||
specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/decision-register--regression.png
|
||||
```
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
- **SC-001**: 100% of Baseline Compare entry points generated by Environment Dashboard and related Environment widgets use the canonical Environment-owned route.
|
||||
- **SC-002**: 0 valid Baseline Compare renders occur from clean workspace-only URLs or workspace-style `environment_id` URLs.
|
||||
- **SC-003**: Cross-workspace Environment route attempts return 404/safe no-access in focused tests.
|
||||
- **SC-004**: Browser verification shows shell/copy consistency for CTA, reload, and back/forward flows.
|
||||
- **SC-005**: Existing workspace hub regression tests for Decision Register and Specs 314-316 remain green.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- The canonical route should follow the repo's existing Environment route family, preferably `/admin/workspaces/{workspace}/environments/{environment}/baseline-compare` unless implementation analysis finds a closer established route name.
|
||||
- `ManagedEnvironment` route key remains the current slug route key used by other Environment routes.
|
||||
- Existing Baseline Compare data, stats, Compare Now action, and OperationRun behavior are correct and need route/shell hardening only.
|
||||
- There is no production data and no external consumer requiring old URLs.
|
||||
|
||||
## Risks
|
||||
|
||||
- Existing tests may assert remembered Environment fallback for Baseline Compare and must be updated because that behavior is now explicitly invalid.
|
||||
- Filament Page registration may require an explicit route override instead of a simple trait; implementation must use the narrowest repo-consistent path.
|
||||
- Environment navigation may currently mix workspace-owned baseline surfaces with Environment-owned Baseline Compare; implementation must not pull Baselines/Baseline Snapshots into this spec.
|
||||
- Browser screenshots may require a running Sail/Vite/browser setup; if deterministic browser setup is blocked, document the blocker and capture available proof.
|
||||
|
||||
## Open Questions
|
||||
|
||||
None blocking implementation. If implementation discovers that Baseline Compare cannot be placed on the existing Environment route family without a new route helper or page registration pattern, update `plan.md` before coding.
|
||||
|
||||
## Follow-Up Spec Candidates
|
||||
|
||||
- **320 - Workspace-Owned Analysis Surface Registration & Shell Cutover**: Baselines, Baseline Snapshots, and workspace-owned analysis pages that inherit Environment shell context.
|
||||
- **321 - Alerts / Audit Log Environment Filter Contract Decision**: decide whether to support `environment_id` with visible chip/clear or reject it.
|
||||
- **322 - Browser No-Drift Regression Guard**: durable browser regression coverage for workspace hubs, Environment-owned pages, filtered hubs, clear/reload/back behavior, and no legacy alias resurrection.
|
||||
|
||||
## Required Final Report
|
||||
|
||||
Implementation close-out must report:
|
||||
|
||||
```text
|
||||
Spec 319 completed.
|
||||
|
||||
Changed behavior:
|
||||
...
|
||||
|
||||
Baseline Compare classification:
|
||||
...
|
||||
|
||||
Canonical route:
|
||||
...
|
||||
|
||||
Removed/invalidated routes:
|
||||
...
|
||||
|
||||
Files changed:
|
||||
...
|
||||
|
||||
Tests:
|
||||
- command:
|
||||
- result:
|
||||
|
||||
Browser verification:
|
||||
...
|
||||
|
||||
Remaining follow-ups:
|
||||
- 320:
|
||||
- 321:
|
||||
- 322:
|
||||
|
||||
No migrations were created.
|
||||
No seeders were changed.
|
||||
No packages, env vars, queues, scheduler, storage, or deployment asset changes were made.
|
||||
No backwards compatibility layer was introduced.
|
||||
No legacy query alias support was added.
|
||||
```
|
||||
|
||||
Also include whether Baseline Compare was removed from workspace hub handling, whether Environment Dashboard CTA was updated, how cross-workspace Environment access is handled, whether clean workspace-only URL is removed or returns safe no-access, screenshot paths if generated, and known unrelated residual test failures.
|
||||
@ -0,0 +1,174 @@
|
||||
# Tasks: Environment-Owned Surface Routing & Shell Context Contract
|
||||
|
||||
**Input**: Design documents from `/specs/319-environment-owned-surface-routing-shell-context-contract/`
|
||||
**Prerequisites**: `plan.md`, `spec.md`
|
||||
**Tests**: Required. This is a runtime route/shell/access contract change.
|
||||
|
||||
## Test Governance Checklist
|
||||
|
||||
- [x] Lane assignment is named and is the narrowest sufficient proof for route, shell, copy, CTA, cross-workspace, remembered fallback, and browser behavior.
|
||||
- [x] New or changed tests stay in the smallest honest family; browser additions are explicit.
|
||||
- [x] Shared helpers, factories, seeds, fixtures, and context defaults stay cheap by default.
|
||||
- [x] Planned validation commands cover the change without pulling in unrelated lane cost.
|
||||
- [x] The declared surface test profile `global-context-shell` is explicit.
|
||||
- [x] Any material budget, baseline, trend, or escalation note is recorded in the implementation close-out.
|
||||
|
||||
## Phase 1: Guardrails and Repo Verification
|
||||
|
||||
**Purpose**: Confirm current repo truth before runtime edits.
|
||||
|
||||
- [x] T001 Verify the implementation starts from branch `319-environment-owned-surface-routing-shell-context-contract` and the worktree has no unrelated user changes.
|
||||
- [x] T002 Re-read Specs 313-318, especially `specs/318-admin-surface-scope-shell-context-audit/mismatch-findings.md`, `audit-report.md`, `recommended-fixes.md`, and `page-matrix.md`.
|
||||
- [x] T003 Confirm Laravel/Filament/Livewire/Pest versions through Laravel Boost `application_info`.
|
||||
- [x] T004 Confirm no migration, seeder, package, env var, queue, scheduler, storage, or deployment asset change is required.
|
||||
- [x] T005 Inventory current Baseline Compare route names, URLs, page registration, shell resolution, and old URL behavior in `apps/platform/app/Providers/Filament/AdminPanelProvider.php`, `apps/platform/routes/web.php`, and `apps/platform/app/Filament/Pages/BaselineCompareLanding.php`.
|
||||
- [x] T006 Inventory all Baseline Compare link generators with `rg "BaselineCompareLanding::getUrl|baseline-compare-landing|Baseline Compare" apps/platform/app apps/platform/resources apps/platform/tests`.
|
||||
- [x] T007 Confirm `WorkspaceHubRegistry` does not include Baseline Compare and record it as a must-preserve fact.
|
||||
- [x] T008 Confirm the canonical route shape to use from existing Environment routes under `/admin/workspaces/{workspace}/environments/{environment}/...`.
|
||||
- [x] T009 Identify any existing test that asserts remembered Environment fallback for Baseline Compare and mark it for replacement rather than preservation.
|
||||
|
||||
## Phase 2: Tests First / Contract Coverage
|
||||
|
||||
**Purpose**: Add failing or alongside tests that define the new contract.
|
||||
|
||||
- [x] T010 Add/update a unit test in `apps/platform/tests/Unit/Tenants/AdminSurfaceScopeTest.php` proving `/admin/workspaces/{workspace}/environments/{environment}/baseline-compare` is `AdminSurfaceScope::EnvironmentBound`.
|
||||
- [x] T011 Add/update `apps/platform/tests/Feature/Navigation/WorkspaceHubRegistryTest.php` proving Baseline Compare is not a workspace hub and remains excluded from workspace hub handling.
|
||||
- [x] T012 Add a feature test proving the canonical Baseline Compare Environment route opens for an authorized user and renders the Baseline Compare page with Workspace + Environment shell context.
|
||||
- [x] T013 Add a feature test proving the old clean workspace-only Baseline Compare URL does not render the page after remembered Environment context is cleared.
|
||||
- [x] T014 Add a feature test proving the old workspace-style Baseline Compare URL with `?environment_id=...` does not render as canonical Baseline Compare.
|
||||
- [x] T015 Add a feature test proving remembered Environment state alone does not allow Baseline Compare to render from the old clean URL.
|
||||
- [x] T016 Add a feature test proving Workspace A + Environment B from Workspace B is rejected as 404/safe no-access with no workspace switch.
|
||||
- [x] T017 Add a Livewire or feature test proving Baseline Compare "this environment" copy only appears when active Environment shell context exists.
|
||||
- [x] T018 Add a feature test proving Environment Dashboard Baseline Compare CTA/action URL uses the canonical Environment route.
|
||||
- [x] T019 Add CTA URL assertions that no `environment_id`, `tenant`, `tenant_id`, `managed_environment_id`, `tenant_scope`, or `tableFilters` appears.
|
||||
- [x] T020 Replace or update `apps/platform/tests/Feature/Filament/BaselineCompareLandingAdminTenantParityTest.php` so it no longer expects remembered admin tenant fallback.
|
||||
- [x] T021 Add/keep a test proving existing Compare Now action still uses confirmation, action execution, capability authorization, and OperationRun UX after route hardening.
|
||||
- [x] T022 Add/keep Decision Register regression coverage proving clean workspace URL remains workspace hub with no active Environment shell.
|
||||
- [x] T023 Add/keep Decision Register regression coverage proving `?environment_id=...` remains a filtered workspace hub with visible chip and no active Environment shell.
|
||||
- [x] T024 Add/keep Spec 314-316 regression coverage for workspace hub clean entry, Environment CTA filter, and clear filter behavior.
|
||||
- [x] T025 Add/keep Spec 317 regression coverage proving legacy Tenant aliases are not resurrected.
|
||||
|
||||
## Phase 3: Canonical Route Implementation
|
||||
|
||||
**Purpose**: Make Baseline Compare route-owned by Workspace + Environment.
|
||||
|
||||
- [x] T026 Implement the canonical Baseline Compare Environment route in `apps/platform/routes/web.php` or the narrowest repo-consistent Filament page route mechanism.
|
||||
- [x] T027 Ensure the route uses the established Workspace route binding and ManagedEnvironment route key pattern (`{environment:slug}` if consistent with existing routes).
|
||||
- [x] T028 Ensure route/model resolution validates `environment.workspace_id === workspace.id` before rendering.
|
||||
- [x] T029 Ensure invalid Workspace/Environment combinations return 404/safe no-access without revealing the foreign Environment.
|
||||
- [x] T030 Ensure the canonical route flows through admin panel middleware, workspace membership checks, and Environment-bound context handling.
|
||||
- [x] T031 Disable, remove, or invalidate the old unbound `/admin/baseline-compare-landing` render path without adding a compatibility layer.
|
||||
- [x] T032 Ensure old URLs with `environment_id` do not become compatibility redirects unless a documented existing convention makes redirect unavoidable.
|
||||
- [x] T033 If redirect is unavoidable, validate Workspace/Environment relationship, redirect only to canonical route, emit no legacy alias support, and cover with tests.
|
||||
- [x] T034 Ensure `AdminSurfaceScope` classification for the canonical path is Environment-bound without adding a new broad scope enum unless unavoidable.
|
||||
|
||||
## Phase 4: Baseline Compare Page and Shell Context
|
||||
|
||||
**Purpose**: Remove hidden context reliance from the page.
|
||||
|
||||
- [x] T035 Update `apps/platform/app/Filament/Pages/BaselineCompareLanding.php` so valid rendering requires route-owned Environment context.
|
||||
- [x] T036 Remove `UsesAdminEnvironmentFilterQueryParameter` from Baseline Compare if it remains a query-based access path.
|
||||
- [x] T037 Ensure `canAccess()` cannot pass from remembered Environment, last Environment, provider tenant ID, or `environment_id` query on an old URL.
|
||||
- [x] T038 Ensure `mount()` and `refreshStats()` only operate when canonical route Environment context is active.
|
||||
- [x] T039 Ensure missing Environment context returns safe no-access or never reaches render.
|
||||
- [x] T040 Ensure page breadcrumbs/header/title/copy align with active Environment ownership.
|
||||
- [x] T041 Ensure `getFindingsUrl()`, `getRunUrl()`, and `openCompareMatrixUrl()` still generate safe links from canonical Environment context.
|
||||
- [x] T042 Ensure Compare Now still uses existing `BaselineCompareService`, `OperationUxPresenter`, `OpsUxBrowserEvents`, and `OperationRunLinks`.
|
||||
|
||||
## Phase 5: Entry Points and Navigation
|
||||
|
||||
**Purpose**: Update all in-scope links to the canonical Environment route.
|
||||
|
||||
- [x] T043 Update `apps/platform/app/Support/EnvironmentDashboard/EnvironmentDashboardSummaryBuilder.php` Baseline Compare action URL.
|
||||
- [x] T044 Update `apps/platform/app/Filament/Widgets/ManagedEnvironment/BaselineCompareCoverageBanner.php` Baseline Compare landing URL.
|
||||
- [x] T045 Update `apps/platform/app/Filament/Widgets/Dashboard/BaselineCompareNow.php` Baseline Compare landing URL.
|
||||
- [x] T046 Update `apps/platform/app/Filament/Widgets/Dashboard/NeedsAttention.php` Baseline Compare action URL.
|
||||
- [x] T047 Update `apps/platform/app/Filament/Pages/BaselineCompareMatrix.php` per-Environment Baseline Compare links if they remain in scope.
|
||||
- [x] T048 Add or update `apps/platform/app/Support/ManagedEnvironmentLinks.php` with a narrow Baseline Compare Environment URL helper only if this reduces repeated route generation.
|
||||
- [x] T049 Ensure Environment Dashboard CTA/action emits no `environment_id`, `tenant`, `tenant_id`, `managed_environment_id`, `tenant_scope`, or `tableFilters`.
|
||||
- [x] T050 Ensure Baseline Compare appears only as Environment-owned navigation/action when an active Environment context exists.
|
||||
- [x] T051 Ensure workspace sidebar remains free of Baseline Compare as a workspace-wide hub.
|
||||
- [x] T052 Ensure `WorkspaceSidebarNavigation` and `WorkspaceHubRegistry` do not gain Baseline Compare as a workspace hub entry.
|
||||
|
||||
## Phase 6: Related Environment-Owned Page Inspection
|
||||
|
||||
**Purpose**: Fix only same-class mismatches found during implementation.
|
||||
|
||||
- [x] T053 Inspect Required Permissions, Provider Readiness/Diagnostics, Environment Diagnostics, Inventory/Coverage, Backup/Restore Environment-owned views, Findings/Risk Exceptions, Evidence, Environment Reviews, Stored Reports, and Review Packs for route/shell/copy mismatch.
|
||||
- [x] T054 If a touched related page has the same mismatch, update it using the same Environment-owned route/shell rule and add focused tests.
|
||||
- [x] T055 If a related page is already correct or belongs to Spec 320/321, document it in the implementation close-out and do not modify it.
|
||||
- [x] T056 Confirm Baselines, Baseline Snapshots, Baseline Compare Matrix, Cross-environment Compare, Alerts, and Audit Log are not changed under Spec 319 unless repo analysis proves direct Baseline Compare dependency.
|
||||
|
||||
## Phase 7: Browser Verification
|
||||
|
||||
**Purpose**: Prove visible route/shell/copy behavior.
|
||||
|
||||
- [x] T057 Start local platform stack using Sail or the repo platform dev command.
|
||||
- [x] T058 Browser Flow A: Environment Dashboard -> Baseline Compare CTA, verify canonical Environment URL, no legacy query params, Workspace + Environment shell, aligned breadcrumb/header/copy.
|
||||
- [x] T059 Save Flow A screenshot to `specs/319-environment-owned-surface-routing-shell-context-contract/artifacts/screenshots/environment-cta--baseline-compare.png`.
|
||||
- [x] T060 Browser Flow B: open old clean workspace-only Baseline Compare URL if route exists and verify rejection/no render/no remembered fallback.
|
||||
- [x] T061 Save Flow B screenshot or route-absence note as `direct-clean--baseline-compare--rejected.png`.
|
||||
- [x] T062 Browser Flow C: open old workspace-style `?environment_id=...` Baseline Compare URL if route exists and verify rejection/non-canonical behavior.
|
||||
- [x] T063 Save Flow C screenshot or route-absence note as `direct-filtered--baseline-compare--rejected.png`.
|
||||
- [x] T064 Browser Flow D: reload canonical Baseline Compare route and verify shell/copy remains Workspace + Environment.
|
||||
- [x] T065 Save Flow D screenshot to `baseline-compare--after-reload.png`.
|
||||
- [x] T066 Browser Flow E: Environment Dashboard -> Baseline Compare -> Decision Register -> back -> forward, verify Baseline Compare Environment shell and Decision Register workspace shell.
|
||||
- [x] T067 Save Flow E screenshots to `baseline-compare--back-forward.png` and `decision-register--regression.png` where useful.
|
||||
- [x] T068 If browser setup cannot be made deterministic, document exact blocker and available alternate proof in the implementation close-out.
|
||||
|
||||
## Phase 8: Final Validation and Close-Out
|
||||
|
||||
**Purpose**: Finish with tests, formatting, and implementation report.
|
||||
|
||||
- [x] T069 Run focused Baseline Compare tests: `cd apps/platform && ./vendor/bin/sail artisan test --filter=BaselineCompare`.
|
||||
- [x] T070 Run classifier/registry tests: `cd apps/platform && ./vendor/bin/sail artisan test --filter=AdminSurfaceScope` and `cd apps/platform && ./vendor/bin/sail artisan test --filter=WorkspaceHubRegistry`.
|
||||
- [x] T071 Run Decision Register regression tests: `cd apps/platform && ./vendor/bin/sail artisan test --filter=DecisionRegister`.
|
||||
- [x] T072 Run relevant WorkspaceHub regression tests for Specs 314-316.
|
||||
- [x] T073 Run relevant LegacyTenantPlatformContextCleanup/Spec 317 regression tests.
|
||||
- [x] T074 Run formatting for touched PHP files, including `cd apps/platform && ./vendor/bin/sail pint --test` or a scoped Pint command.
|
||||
- [x] T075 Run `git diff --check`.
|
||||
- [x] T076 Confirm no migrations, seeders, package files, env vars, queues, scheduler, storage, or deployment asset files changed.
|
||||
- [x] T077 Confirm no backwards compatibility layer, old route redirect, dual route model, or legacy query alias support was introduced.
|
||||
- [x] T078 Prepare final implementation report with changed behavior, classification, canonical route, removed/invalidated routes, files changed, tests, browser verification, screenshots, follow-ups 320/321/322, and any unrelated residual failures.
|
||||
|
||||
## Non-Tasks / Scope Guards
|
||||
|
||||
- [x] NT001 Do not implement Spec 320 workspace-owned analysis shell cutover.
|
||||
- [x] NT002 Do not implement Spec 321 Alerts/Audit Log filter decision.
|
||||
- [x] NT003 Do not implement Spec 322 durable browser no-drift infrastructure.
|
||||
- [x] NT004 Do not add `environment_id` filter support to Baseline Compare.
|
||||
- [x] NT005 Do not make Baseline Compare workspace-wide.
|
||||
- [x] NT006 Do not add compatibility redirects, aliases, dual-param support, or remembered fallback.
|
||||
- [x] NT007 Do not create migrations, seeders, packages, env vars, queues, scheduler, storage, or Filament assets.
|
||||
|
||||
## Dependencies
|
||||
|
||||
```text
|
||||
Phase 1 -> Phase 2 -> Phase 3 -> Phase 4 -> Phase 5 -> Phase 6 -> Phase 7 -> Phase 8
|
||||
```
|
||||
|
||||
Route tests (T010-T016) should be in place before route implementation. Entry point tests (T018-T019) should be in place before link updates. Browser verification runs after runtime implementation.
|
||||
|
||||
## Parallel Opportunities
|
||||
|
||||
- T010-T024 can be split by test file after the canonical route shape is agreed.
|
||||
- T043-T047 can be updated in parallel because they touch separate entry-point files.
|
||||
- T069-T073 can run independently after implementation, subject to Sail/test environment availability.
|
||||
|
||||
## MVP Scope
|
||||
|
||||
The MVP is Baseline Compare canonical Environment route, invalid old URL behavior, Environment Dashboard CTA update, cross-workspace rejection, no remembered fallback, and Decision Register regression. Related Environment-owned pages are inspect-only unless the same mismatch is confirmed.
|
||||
|
||||
## Implementation Evidence
|
||||
|
||||
- Canonical route registered: `/admin/workspaces/{workspace}/environments/{environment}/baseline-compare`.
|
||||
- Old `/admin/baseline-compare-landing` and `/admin/baseline-compare-landing?environment_id=...` return Not Found; no redirect or compatibility alias was added.
|
||||
- Browser smoke artifacts saved under `artifacts/screenshots/`.
|
||||
- Focused validation passed:
|
||||
- `./vendor/bin/sail artisan test` on Baseline Compare route/component/navigation/authorization contract files: 112 tests, 345 assertions.
|
||||
- `./vendor/bin/sail artisan test tests/Feature/Governance/DecisionRegisterWorkspaceHubContractTest.php`
|
||||
- `./vendor/bin/sail artisan test tests/Feature/Navigation/WorkspaceHubEnvironmentFilterContractTest.php tests/Feature/Navigation/WorkspaceHubClearFilterContractTest.php`
|
||||
- `./vendor/bin/sail artisan test tests/Feature/Guards/LegacyTenantPlatformContextCleanupTest.php`
|
||||
- scoped Pint on touched PHP files.
|
||||
- `git diff --check`
|
||||
- Broader `./vendor/bin/sail artisan test --filter=DecisionRegister` surfaced an existing unrelated failure in `FindingExceptionDecisionRegisterNavigationTest` where the expected back URL still includes `managed_environment_id`; no Spec 319 files or Decision Register code were changed for that.
|
||||
Loading…
Reference in New Issue
Block a user