# Implementation Plan: Commercial Entitlements and Billing-State Maturity **Branch**: `251-commercial-entitlements-billing-state` | **Date**: 2026-04-28 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/251-commercial-entitlements-billing-state/spec.md` **Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/251-commercial-entitlements-billing-state/spec.md` **Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts. ## Summary - Layer one bounded workspace commercial lifecycle overlay on top of the already-real Spec 247 entitlement substrate, not beside it. The existing `WorkspaceEntitlementResolver` remains canonical for plan/default/override truth, and the new slice adds one explicit lifecycle state plus action-family outcomes for onboarding activation, review-pack start, and preserved read-only history access. - Keep mutation narrow and platform-owned: persist lifecycle state through the existing workspace settings infrastructure, expose inspection plus state change from the existing system workspace detail surface, and keep `/admin` limited to contextual allow, warn, or block messaging on onboarding and review-pack surfaces. - Preserve current review/evidence/download truth while suspended. New lifecycle blocking must stop future onboarding activation and future review-pack starts before any tenant mutation, `ReviewPack`, or `OperationRun` creation, while leaving already-generated history and evidence consumption under current RBAC intact. ## Technical Context **Language/Version**: PHP 8.4 (Laravel 12) **Primary Dependencies**: Filament v5 + Livewire v4, existing workspace settings stack (`SettingsRegistry`, `SettingsResolver`, `SettingsWriter`), `WorkspaceEntitlementResolver`, `ReviewPackService`, system directory detail page **Storage**: PostgreSQL via existing `workspace_settings` rows plus existing audit log records; no new table or billing/account model **Testing**: Pest unit and feature tests via Laravel Sail **Validation Lanes**: fast-feedback, confidence **Target Platform**: Monorepo Laravel web application in `apps/platform`, using existing Filament admin and system panels **Project Type**: web **Performance Goals**: Reuse existing settings reads and current workspace aggregates only, add no new external calls during render, keep review-pack dedupe and shared run UX unchanged when allowed, and short-circuit blocked review-pack starts before any `ReviewPack` or `OperationRun` write **Constraints**: One commercial lifecycle overlay only, four bounded states, two real gated behavior families, preserved authorized read-only history/evidence/download access while suspended, explicit `/admin` vs `/system` separation, no payment provider/invoice/checkout/website/broad billing-engine scope **Scale/Scope**: One bounded lifecycle resolver, one system-plane mutation surface, one platform capability addition, one onboarding gate, one review-pack action-family gate, and focused lifecycle/read-only test coverage ## Filament v5 / Panel Notes - **Livewire v4.0+ compliance**: The slice stays inside existing Filament v5 pages, widgets, resources, and Livewire-backed actions. No Livewire v3 assumptions or compatibility work are introduced. - **Provider registration location**: No panel/provider registration changes are planned. Existing Laravel 12 + Filament provider registration remains in `bootstrap/providers.php`. - **Global search**: No new globally searchable resource is introduced. Current global-search behavior remains unchanged. - **Destructive and high-impact actions**: The future `Change commercial state` action on the system workspace detail page must use `->requiresConfirmation()`, require platform authorization, and write audit history. The `Suspended / read-only` transition is the only high-risk path in scope. Review-pack and onboarding blocks remain non-destructive business-state responses, not hidden authorization failures. - **Asset strategy**: No new panel or shared assets are planned. Deployment remains unchanged, including `cd apps/platform && php artisan filament:assets` when registered Filament assets are deployed elsewhere in the product. ## UI / Surface Guardrail Plan - **Guardrail scope**: changed surfaces - **Native vs custom classification summary**: mixed - **Shared-family relevance**: system detail controls, status messaging, onboarding helper text, review-pack action gating, review/evidence viewer messaging - **State layers in scope**: page, detail - **Audience modes in scope**: operator-MSP, support-platform, customer/read-only - **Decision/diagnostic/raw hierarchy plan**: decision-first on the system workspace detail surface and on the immediate onboarding/review-pack action context; diagnostics-second via the existing entitlement substrate and review/run/history context; no new raw/support payload surface is planned - **Raw/support gating plan**: capability-gated system-plane inspection only; customer/read-only surfaces remain calm and evidence-first - **One-primary-action / duplicate-truth control**: `/system/directory/workspaces/{workspace}` remains the only mutation surface; onboarding and review-pack surfaces show only the local lifecycle consequence required for the immediate action; suspended read-only history pages do not restate the whole commercial profile - **Handling modes by drift class or surface**: review-mandatory because one lifecycle vocabulary must stay consistent across system, onboarding, review-pack, and read-only history surfaces - **Repository-signal treatment**: review-mandatory - **Special surface test profiles**: standard-native-filament, shared-detail-family, monitoring-state-page - **Required tests or manual smoke**: functional-core, state-contract - **Exception path and spread control**: no second admin-plane commercial mutation surface, no page-local lifecycle labels, and no broad suspension sweep across unrelated mutable surfaces - **Active feature PR close-out entry**: Guardrail ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes - **Systems touched**: `SettingsRegistry`, `SettingsResolver`, `SettingsWriter`, existing workspace-setting audit path, `WorkspaceEntitlementResolver`, `WorkspaceSettings` as the current entitlement substrate reference, `App\Filament\System\Pages\Directory\ViewWorkspace`, `ManagedTenantOnboardingWizard`, `ReviewPackService`, `TenantReviewPackCard`, `ReviewRegister`, `TenantReviewResource`, `ReviewPackResource`, `CustomerReviewWorkspace`, `EvidenceSnapshotResource`, and `WorkspaceEntitlementBlockedException` - **Shared abstractions reused**: `WorkspaceEntitlementResolver`, `WorkspacePlanProfileCatalog`, `SettingsResolver`, `SettingsWriter`, current workspace audit logging, `ReviewPackService`, `OperationUxPresenter`, `OperationRunLinks`, `Capabilities`, `PlatformCapabilities`, and existing Filament action/resource surfaces - **New abstraction introduced? why?**: one bounded `WorkspaceCommercialLifecycleResolver` is justified because the existing entitlement resolver answers per-key entitlement truth but does not express one workspace-wide lifecycle posture with action-family outcomes, preserved read-only semantics, or system/admin messaging - **Why the existing abstraction was sufficient or insufficient**: Spec 247 already provides canonical entitlement substrate truth and must remain the foundation. It is insufficient for `trial`, `grace`, `active_paid`, and `suspended_read_only` because those states cut across more than one entitlement key and need one central business-state explanation - **Bounded deviation / spread control**: no page-local lifecycle conditionals and no second exception taxonomy by default; prefer reusing the existing blocked decision payload/catch path for review-pack actions unless implementation proves that the current class name or payload cannot carry lifecycle metadata cleanly ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: yes - **Central contract reused**: existing shared review-pack OperationRun start UX through `ReviewPackService`, `OperationUxPresenter`, and `OperationRunLinks` - **Delegated UX behaviors**: queued toast, run link, run-enqueued browser event, dedupe messaging, and existing terminal notifications remain unchanged when review-pack generation is allowed; lifecycle-blocked starts create no `OperationRun`, no queued DB notification, and no terminal notification - **Surface-owned behavior kept local**: onboarding completion helper text, review-pack tooltips/disabled state, and suspended read-only explanation on history surfaces remain local projections of the central lifecycle decision - **Queued DB-notification policy**: unchanged explicit opt-in only - **Terminal notification path**: unchanged central lifecycle mechanism for existing review-pack runs only - **Exception path**: none planned; lifecycle blocking must happen before `ReviewPackService` creates or reuses a `ReviewPack` or `OperationRun`, and the preferred later implementation is to extend the current blocked-decision payload rather than invent a second parallel business-state exception family ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: no - **Provider-owned seams**: N/A - **Platform-core seams**: workspace commercial lifecycle vocabulary, lifecycle rationale, action-family outcomes, system/admin messaging, and audit semantics - **Neutral platform terms / contracts preserved**: `workspace`, `trial`, `grace`, `active paid`, `suspended / read-only`, `commercial state`, `review pack`, `managed tenant activation` - **Retained provider-specific semantics and why**: none; review-pack generation stays provider-backed operationally, but the new lifecycle vocabulary remains platform-core and provider-neutral - **Bounded extraction or follow-up path**: none ## Constitution Check *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* - Inventory-first: PASS - the slice adds workspace-owned business state, not new inventory or backup truth. - Read/write separation: PASS - the only new write is a confirmation-protected, audited system-plane lifecycle mutation using existing workspace settings persistence. - Graph contract path: PASS - no new Microsoft Graph path is introduced. - Deterministic capabilities: PASS - admin-plane capabilities remain unchanged, and any new platform capability stays registry-backed. - RBAC-UX: PASS - `/admin` and `/system` remain separated; wrong-plane and non-member access stay 404; member-without-capability stays 403; otherwise-authorized actors get a business-state block or warning instead of authorization failure. - Workspace isolation: PASS - admin-plane contextual behavior still requires established workspace context. - RBAC-UX destructive confirmation: PASS - the future system-plane state-change action must require confirmation and rationale. - RBAC-UX global search: PASS - no new searchable resource or search scope is introduced. - Tenant isolation: PASS - onboarding, review-pack, review history, evidence, and download surfaces remain tenant-safe. - Run observability: PASS - review-pack generation keeps the existing `OperationRun` path when allowed, and blocked starts stop before run creation. - OperationRun start UX: PASS - the plan preserves shared review-pack start UX and inserts lifecycle blocking before run creation. - Ops-UX 3-surface feedback: PASS - existing feedback stays toast + progress surfaces + terminal notification only when a run exists. - Ops-UX lifecycle: PASS - no new `OperationRun` lifecycle contract is introduced. - Ops-UX summary counts: N/A - no `summary_counts` shape change is planned. - Ops-UX guards: N/A - no new run guard family is planned in the planning slice. - Ops-UX system runs: N/A - initiator-null behavior is unchanged. - Automation: N/A - no new queued or scheduled workflow family is introduced. - Data minimization: PASS - no payment payloads, account records, or provider secrets are introduced. - Test governance (TEST-GOV-001): PASS - the plan stays in focused unit + feature lanes with explicit proof commands and limited fixture growth. - Proportionality (PROP-001): PASS - persistence stays in existing settings rows, and the only new structural element is one bounded lifecycle overlay. - No premature abstraction (ABSTR-001): PASS - no interface, registry, strategy system, or framework is planned; only one local resolver is added because multiple real surfaces already need the same lifecycle decision. - Persisted truth (PERSIST-001): PASS - no new table or durable artifact is introduced. - Behavioral state (STATE-001): PASS - `grace` and `suspended_read_only` create distinct action-family consequences immediately, and `trial` remains justified because it is part of the explicit platform-managed commercial posture and audit workflow even though its two in-scope gated families currently match `active_paid`. - UI semantics (UI-SEM-001): PASS - the plan prefers direct mapping from lifecycle truth to helper text and badges instead of a new presentation framework. - Shared pattern first (XCUT-001): PASS - system detail, onboarding, review-pack, and read-only history surfaces all reuse the existing substrate and shared run path first. - Provider boundary (PROV-001): PASS - the new vocabulary is platform-core, not Microsoft-shaped. - V1 explicitness / few layers (V1-EXP-001, LAYER-001): PASS - one explicit state family plus one thin overlay resolver is the narrowest viable shape. - Spec discipline / bloat check (SPEC-DISC-001, BLOAT-001): PASS - the plan keeps the whole lifecycle overlay in one coherent spec and includes proportionality review below. - Badge semantics (BADGE-001): PASS - any future lifecycle badge must reuse shared badge semantics or stay plain text; no page-local color taxonomy is planned. - Filament-native UI (UI-FIL-001): PASS - the slice extends existing Filament pages, resources, widgets, and the current system Blade page. - Filament-native UI local Blade/Tailwind: PASS - the existing system Blade view remains the only custom-rendered surface in scope and must preserve current Filament visual language. - UI/UX surface taxonomy (UI-CONST-001 / UI-SURF-001): PASS - existing system detail, guided onboarding, action family, and read-only viewer surface types remain intact. - Decision-first operating model (DECIDE-001): PASS - system workspace detail is primary, onboarding/review-pack surfaces stay contextual, and read-only history/evidence pages remain tertiary evidence/diagnostics. - Audience-aware disclosure (DECIDE-AUD-001 / OPSURF-001): PASS - system detail stays platform/support-facing, admin action gates stay operator-first, and suspended read-only pages keep customer-safe history access without raw platform diagnostics. - UI/UX inspect model (UI-HARD-001): PASS - no duplicate inspect affordances are added. - UI/UX action hierarchy (UI-HARD-001 / UI-EX-001): PASS - the plan keeps one system mutation action and existing onboarding/review-pack primary actions in place. - UI/UX scope, truth, and naming (UI-HARD-001 / UI-NAMING-001 / OPSURF-001): PASS - labels remain narrow and billing-provider-free. - UI/UX placeholder ban (UI-HARD-001): PASS - no empty action groups are planned. - UI naming (UI-NAMING-001): PASS - primary labels stay `Change commercial state`, `Complete onboarding`, `Generate pack`, `Regenerate`, and `Export executive pack`. - Operator surfaces (OPSURF-001): PASS - mutation scope remains explicit, and `/admin` surfaces only show contextual lifecycle truth. - Operator surface page contract: PASS - the spec already defines the required surface contracts. - Filament UI Action Surface Contract: PASS - touched surfaces already have contracts or exemptions; the plan preserves them while adding lifecycle truth. - Filament UI UX-001 (Layout & IA): PASS - no new page shell or panel is introduced. - Action-surface discipline (ACTSURF-001 / HDR-001): PASS - one system primary action and existing onboarding/review-pack action families remain the only primary mutations in scope. - UI review workflow: PASS - guardrail, shared-family, and exception posture remain explicit in this plan. ## Test Governance Check - **Test purpose / classification by changed surface**: `Unit` for the bounded lifecycle overlay and behavior matrix; `Feature` for system-plane mutation, onboarding activation gating, review-pack start blocking, and preserved suspended read-only consumption - **Affected validation lanes**: `fast-feedback`, `confidence` - **Why this lane mix is the narrowest sufficient proof**: the business risk is deterministic decision ordering plus existing Filament/Livewire and service entry points. Browser or heavy-governance coverage would add cost without proving additional current-release risk for this bounded overlay. - **Narrowest proving command(s)**: - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Entitlements/WorkspaceCommercialLifecycleResolverTest.php` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/System/ViewWorkspaceEntitlementsTest.php tests/Feature/System/Spec113/AuthorizationSemanticsTest.php tests/Feature/Onboarding/ManagedTenantOnboardingEntitlementTest.php tests/Feature/Onboarding/OnboardingRbacSemanticsTest.php` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ReviewPack/ReviewPackEntitlementEnforcementTest.php tests/Feature/ReviewPack/ReviewPackGenerationTest.php tests/Feature/ReviewPack/ReviewPackDownloadTest.php tests/Feature/Reviews/CustomerReviewWorkspacePageTest.php tests/Feature/Reviews/CustomerReviewWorkspacePackAccessTest.php tests/Feature/Evidence/EvidenceSnapshotResourceTest.php` - **Fixture / helper / factory / seed / context cost risks**: limited to workspace, platform user, workspace member, onboarding draft, tenant, existing review pack, tenant review, and evidence snapshot fixtures - **Expensive defaults or shared helper growth introduced?**: no - implementation should reuse existing factories and opt-in tenant/review/evidence helpers only - **Heavy-family additions, promotions, or visibility changes**: none - **Surface-class relief / special coverage rule**: standard-native relief for system detail and onboarding; monitoring-state-page proof for no new run creation; shared-detail-family proof for preserved view/download access while suspended - **Closing validation and reviewer handoff**: rerun the exact targeted commands above, verify 404 vs 403 vs business-state outcomes separately, verify system detail source labels remain consistent, verify blocked review-pack starts create no new `ReviewPack` or `OperationRun` and emit no queued or terminal notification, verify already queued or running review-pack runs continue unaffected after later suspension, and verify suspended workspaces still allow authorized review/evidence/download access - **Budget / baseline / trend follow-up**: none expected beyond ordinary feature-local growth - **Review-stop questions**: does the state vocabulary stay narrow enough, does the system/admin split remain intact, does suspended read-only coverage avoid broad mutation-sweep scope, and does the blocked-decision transport avoid a second exception framework - **Escalation path**: document-in-feature if only payload wording or helper reuse needs adjustment; follow-up-spec only if the overlay starts pulling unrelated mutable surfaces into suspension logic - **Active feature PR close-out entry**: Guardrail - **Why no dedicated follow-up spec is needed**: the testing cost stays local to one overlay resolver and a small set of existing pages/services/resources; no new browser or heavy-governance harness is justified ## Project Structure ### Documentation (this feature) ```text specs/251-commercial-entitlements-billing-state/ ├── plan.md ├── research.md ├── data-model.md ├── quickstart.md ├── contracts/ │ └── workspace-commercial-lifecycle-overlay.logical.openapi.yaml ├── checklists/ │ └── requirements.md └── tasks.md # Created later by /speckit.tasks, not by this plan step ``` ### Source Code (repository root) ```text apps/platform/ ├── app/ │ ├── Exceptions/Entitlements/WorkspaceEntitlementBlockedException.php │ ├── Filament/ │ │ ├── Pages/ │ │ │ ├── Reviews/CustomerReviewWorkspace.php │ │ │ ├── Reviews/ReviewRegister.php │ │ │ ├── Settings/WorkspaceSettings.php │ │ │ └── Workspaces/ManagedTenantOnboardingWizard.php │ │ ├── Resources/ │ │ │ ├── EvidenceSnapshotResource.php │ │ │ ├── EvidenceSnapshotResource/Pages/ViewEvidenceSnapshot.php │ │ │ ├── ReviewPackResource.php │ │ │ ├── ReviewPackResource/Pages/ViewReviewPack.php │ │ │ ├── TenantReviewResource.php │ │ │ └── TenantReviewResource/Pages/ViewTenantReview.php │ │ ├── System/Pages/Directory/ViewWorkspace.php │ │ └── Widgets/Tenant/TenantReviewPackCard.php │ ├── Models/WorkspaceSetting.php │ ├── Services/ │ │ ├── Entitlements/WorkspaceCommercialLifecycleResolver.php # likely new bounded overlay service │ │ ├── Entitlements/WorkspaceEntitlementResolver.php │ │ ├── ReviewPackService.php │ │ └── Settings/ │ │ ├── SettingsResolver.php │ │ └── SettingsWriter.php │ ├── Support/ │ │ ├── Auth/Capabilities.php │ │ ├── Auth/PlatformCapabilities.php │ │ └── Settings/SettingsRegistry.php ├── resources/views/filament/system/pages/directory/view-workspace.blade.php └── tests/ ├── Feature/ └── Unit/ ``` **Structure Decision**: Single Laravel/Filament application inside `apps/platform`, with one new bounded lifecycle overlay service and changes limited to existing settings persistence, system detail, onboarding, review-pack, and read-only review/evidence/download surfaces plus focused Pest coverage. ## Likely Implementation Surfaces - `app/Support/Settings/SettingsRegistry.php` to register lifecycle-setting definitions and validation using the existing workspace settings infrastructure - `app/Services/Entitlements/WorkspaceCommercialLifecycleResolver.php` as the new bounded overlay, with `WorkspaceEntitlementResolver.php` remaining the canonical substrate provider - `app/Support/Auth/PlatformCapabilities.php` and related platform authorization helpers for one dedicated commercial-lifecycle management capability - `app/Filament/System/Pages/Directory/ViewWorkspace.php` and `resources/views/filament/system/pages/directory/view-workspace.blade.php` for read-only summary plus the confirmation-protected state-change action - `app/Filament/Pages/Workspaces/ManagedTenantOnboardingWizard.php` for contextual lifecycle messaging and activation blocking before tenant mutation - `app/Services/ReviewPackService.php`, `app/Filament/Widgets/Tenant/TenantReviewPackCard.php`, `app/Filament/Pages/Reviews/ReviewRegister.php`, `app/Filament/Resources/TenantReviewResource.php`, `app/Filament/Resources/ReviewPackResource.php`, `app/Filament/Resources/ReviewPackResource/Pages/ViewReviewPack.php`, and `app/Filament/Resources/TenantReviewResource/Pages/ViewTenantReview.php` for shared start gating and tooltip/disabled-state reuse - Existing read-only consumption surfaces `CustomerReviewWorkspace.php`, `ViewTenantReview.php`, `ViewReviewPack.php`, `ViewEvidenceSnapshot.php`, and the current review-pack download path to prove suspended history/evidence access remains available under existing RBAC - Focused unit and feature tests under `tests/Unit/Entitlements`, `tests/Feature/System/Directory`, `tests/Feature/Onboarding`, `tests/Feature/ReviewPack`, `tests/Feature/Reviews`, and `tests/Feature/Evidence` ## Complexity Tracking | Violation | Why Needed | Simpler Alternative Rejected Because | |-----------|------------|-------------------------------------| | One bounded `WorkspaceCommercialLifecycleResolver` | Two real gated behavior families plus preserved read-only consumption need one shared workspace-wide decision layered above existing entitlements | Page-local conditionals in onboarding, review-pack resources/widgets, and system detail would drift immediately and undermine business-state consistency | | Four-state commercial lifecycle vocabulary | Platform operators need one auditable commercial posture that distinguishes trial, grace, active paid, and suspended/read-only on the single system decision surface | Three unlabeled booleans or ad hoc flags would either collapse grace into suspension or lose the explicit platform-side lifecycle state needed for support and audit | ## Proportionality Review - **Current operator problem**: The repo can already answer per-key entitlement questions, but it cannot say in one place whether a workspace is currently trialing, in grace, fully active paid, or suspended/read-only, nor can it explain why onboarding and review-pack starts are blocked while history remains readable. - **Existing structure is insufficient because**: `WorkspaceEntitlementResolver` and current workspace settings expose substrate truth only. They do not provide one workspace-wide lifecycle posture, one system-owned mutation path, or one action-family outcome that distinguishes lifecycle blocks from entitlement blocks and authorization failures. - **Narrowest correct implementation**: Keep persistence inside existing `workspace_settings`, add only one four-state lifecycle family plus rationale, derive action-family outcomes in one bounded overlay service, mutate it from one system detail page, and apply it only to onboarding activation, review-pack starts, and preserved read-only history/evidence/download semantics. - **Ownership cost created**: One new state vocabulary, one overlay service, one platform capability, cross-surface copy discipline, and focused lifecycle/read-only tests. - **Alternative intentionally rejected**: A billing/subscription engine, customer-account model, payment-provider seam, or many local page booleans was rejected because the current release only needs a single workspace commercial overlay on top of the already-real entitlement substrate. - **Release truth**: current-release truth. The four-state vocabulary is justified now because platform operators already need to set and audit those named postures, even though only `grace` and `suspended_read_only` introduce new blocked outcomes for the two in-scope action families in this slice. ## Phase 0 — Research (output: `research.md`) See: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/251-commercial-entitlements-billing-state/research.md` Goals: - Confirm the narrowest reuse of the existing `entitlements` settings domain and audit path for lifecycle state and rationale. - Confirm that one bounded overlay service can compose `WorkspaceEntitlementResolver` without creating a second commercial framework. - Confirm that lifecycle mutation remains platform-only on the existing system workspace detail page and does not leak into `/admin` self-service. - Confirm that review-pack start blocking happens before `ReviewPack` or `OperationRun` creation and can reuse the current blocked-decision transport. - Confirm that suspended read-only preservation remains bounded to existing review, evidence, and generated-pack consumption surfaces instead of becoming a broad product-wide suspension sweep. ## Phase 1 — Design & Contracts (outputs: `data-model.md`, `contracts/`, `quickstart.md`) See: - `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/251-commercial-entitlements-billing-state/data-model.md` - `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/251-commercial-entitlements-billing-state/contracts/workspace-commercial-lifecycle-overlay.logical.openapi.yaml` - `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/251-commercial-entitlements-billing-state/quickstart.md` Design focus: - Persist `commercial_lifecycle_state` plus rationale through the existing `entitlements` settings domain instead of adding a new table or billing domain. - Keep the overlay inside `App\Services\Entitlements` and let it compose `WorkspaceEntitlementResolver` rather than replacing it. - Extend the existing system workspace detail page with a read-only lifecycle summary and one confirmation-protected `Change commercial state` action, while leaving `WorkspaceSettings` as substrate truth rather than a second mutation plane. - Gate `ManagedTenantOnboardingWizard` completion from the central lifecycle decision after underlying entitlement truth is known. - Gate review-pack `Generate pack`, `Regenerate`, and `Export executive pack` starts through `ReviewPackService` and current action surfaces, stopping before any `ReviewPack` or `OperationRun` write when the lifecycle blocks the action. - Preserve `CustomerReviewWorkspace`, review detail, evidence detail, review-pack detail, and pack download access under current RBAC while suspended, and keep any broader mutable-surface suspension work explicitly out of scope. ## Phase 1 — Agent Context Update After Phase 1 artifacts are generated, update Copilot context from the completed plan: - `/Users/ahmeddarrazi/Documents/projects/wt-plattform/.specify/scripts/bash/update-agent-context.sh copilot` ## Phase 2 — Implementation Outline (tasks created later by `/speckit.tasks`) - Register lifecycle state and rationale setting definitions under the existing `entitlements` settings domain and wire them into the current workspace-setting audit path. - Add one bounded `WorkspaceCommercialLifecycleResolver` that composes underlying entitlement decisions and yields action-family outcomes plus suspended read-only allowances. - Add one dedicated platform capability for commercial lifecycle management and enforce it on the system detail mutation action only. - Extend `ViewWorkspace` plus its Blade view with current lifecycle state, affected behavior summary, and a confirmation-protected `Change commercial state` action. - Gate onboarding completion in `ManagedTenantOnboardingWizard` using the shared lifecycle decision while preserving existing tenant operability checks and 404/403 semantics. - Gate review-pack start surfaces and `ReviewPackService` using the shared lifecycle decision, preserving current queued-start UX when allowed and reusing the existing blocked-decision transport when blocked. - Prove suspended read-only continuation by asserting existing review/evidence/download surfaces remain available under current RBAC while no new onboarding activation or review-pack run can start. - Add focused Sail/Pest unit and feature coverage only. ## Constitution Check (Post-Design) Re-check result: PASS. The design keeps Filament v5 + Livewire v4 compliance intact, leaves provider registration unchanged in `bootstrap/providers.php`, introduces no new globally searchable resource, keeps asset strategy unchanged, preserves strict `/admin` vs `/system` separation, layers one bounded lifecycle resolver above the existing entitlement substrate, and blocks review-pack starts before `OperationRun` creation rather than forking shared run UX. ## Planning Readiness - Outcome: keep - No unresolved clarification markers remain in the plan-phase artifacts. - No application implementation is included in this planning step. - The next repo-native step is `/speckit.tasks` for an implementation task breakdown, not code changes. ## Implementation Close-Out - **Workflow outcome**: keep. - **Implementation result**: one bounded commercial lifecycle overlay was implemented through existing workspace settings, one system-plane `Change commercial state` action, onboarding activation gating, review-pack start allow/warn/block semantics, and preserved suspended read-only review/evidence/download access. - **Blocked-decision transport**: document-in-feature. The existing `WorkspaceEntitlementBlockedException` transport remains sufficient for review-pack blocked starts; no second business-state exception family was introduced. - **Preserved read-only scope**: document-in-feature. Suspension stays bounded to onboarding activation and new review-pack starts in this spec; broader mutable-surface suspension remains out of scope. - **Browser smoke path**: `/system/login` as `operator@tenantpilot.io`, `/system/directory/workspaces/1`, open `Change commercial state`, set `Trial` with rationale, confirm, observe updated lifecycle summary and notification follow-up, then restore `Active paid`. - **Browser smoke result**: pass after fixing `WorkspaceResolver` to accept Livewire serialized workspace route parameters; the follow-up notification update no longer emits console errors or 404/419 markers. - **Lane results**: targeted unit/support/system/onboarding/review-pack/read-only Pest lanes passed; dirty-only Pint passed; `git diff --check` passed.