# Implementation Plan: UI Copy, IA & Localization Neutralization **Branch**: `286-ui-copy-ia-localization-neutralization` | **Date**: 2026-05-09 | **Spec**: [spec.md](./spec.md) **Input**: Feature specification from `specs/286-ui-copy-ia-localization-neutralization/spec.md` ## Summary Prepare the reserved workspace-first cutover copy slice by converging the operator-facing glossary on a single environment-first vocabulary across the confirmed post-cutover admin surfaces. The narrow implementation path updates shared localization keys, page titles, shared shell labels, dashboard headings, context chips, registry return labels, selected workspace widgets, and bounded provider-neutral helper text while explicitly avoiding route renames, class renames, RBAC/capability renames, schema changes, or broader provider-surface cleanup. This plan is intentionally bounded. Filament remains v5 on Livewire v4, provider registration remains in `apps/platform/bootstrap/providers.php`, touched resources keep their current search posture, destructive action behavior is preserved, and deployment assets remain unchanged. ## Inherited Baseline / Explicit Delta ### Inherited baseline - Spec `279` already established the managed-environment core cutover and is historical prerequisite context only. - Spec `280` already prepared the workspace-first route and page ownership model that `286` must align with rather than redesign. - Spec `281` already prepared provider-neutral provider-connection and target-scope vocabulary; `286` must reuse that boundary rather than rename provider-owned detail blindly. - Spec `282` already frames the adjacent artifact-retargeting lane and remains out of scope except where `286` must avoid contradicting environment-scoped admin nouns. - Spec `283` already prepared provider capability boundaries; `286` must not rename or absorb provider-capability vocabulary. - Spec `285` already captures the adjacent workspace-first RBAC lane; `286` must not absorb role, capability, or policy wording changes. - Spec `275` already covers customer-facing localization adoption on review surfaces and remains related glossary discipline only, not the current admin-surface target. - Current repo runtime already shows environment-shaped seams, including environment routes in `TenantDashboard::getUrl()`, but key operator surfaces still expose titles and labels such as `Choose tenant`, `Managed tenants`, `Tenant scope`, and `All tenants`. ### Explicit delta in this plan - Replace the in-scope operator-facing tenant-first glossary with an environment-first glossary in English and German. - Rename the in-scope translation-key family and only the local display labels/test IDs owned by the enumerated surfaces where `tenant_*` naming still leaks into operator-facing shells. - Neutralize the default-visible helper text on the exact `PolicyResource`, `ViewPolicy`, `VersionsRelationManager`, and `baseline-compare-landing` surfaces while keeping provider detail secondary. - Keep auth-provider wording, route names, slugs, classes, RBAC behavior, and provider-owned deeper detail unchanged. - Keep Spec `287` and any broader provider-surface cleanup explicitly deferred. ## Technical Context **Language/Version**: PHP 8.4.15, Laravel 12.52 **Primary Dependencies**: Filament 5.2.1, Livewire 4.1.4, current localization catalogs, current shared shell helpers, current dashboard and widget surfaces **Storage**: No persistence or schema changes; glossary and helper copy remain derived from localization files and view-model output only **Testing**: Pest feature tests and one Pest browser smoke **Validation Lanes**: confidence, browser **Target Platform**: Laravel monolith in `apps/platform` **Project Type**: web application **Performance Goals**: preserve current page responsiveness; this slice changes rendered copy and small view-model contracts only **Constraints**: no route rename, no slug rename, no model/class rename, no schema change, no RBAC rename, no asset change, no new translation framework, no auth-provider wording change, no broader provider cleanup **Scale/Scope**: one bounded environment-first glossary over current workspace-first admin surfaces only ## Likely Affected Repo Surfaces - `apps/platform/lang/en/localization.php` - `apps/platform/lang/de/localization.php` - `apps/platform/lang/en/baseline-compare.php` - `apps/platform/lang/de/baseline-compare.php` - `apps/platform/app/Filament/Pages/ChooseTenant.php` - `apps/platform/resources/views/filament/pages/choose-tenant.blade.php` - `apps/platform/app/Filament/Pages/Workspaces/ManagedTenantsLanding.php` - `apps/platform/resources/views/filament/pages/workspaces/managed-tenants-landing.blade.php` - `apps/platform/app/Filament/Pages/TenantDashboard.php` - `apps/platform/resources/views/filament/widgets/dashboard/tenant-dashboard-context-chips.blade.php` - `apps/platform/app/Support/OperateHub/OperateHubShell.php` - `apps/platform/app/Support/Navigation/CanonicalNavigationContext.php` - `apps/platform/resources/views/filament/widgets/workspace/workspace-needs-attention.blade.php` - `apps/platform/resources/views/filament/widgets/workspace/workspace-recent-operations.blade.php` - `apps/platform/app/Filament/Resources/PolicyResource.php` - `apps/platform/app/Filament/Resources/PolicyResource/Pages/ViewPolicy.php` - `apps/platform/app/Filament/Resources/PolicyResource/RelationManagers/VersionsRelationManager.php` - `apps/platform/resources/views/filament/pages/baseline-compare-landing.blade.php` - representative proof files under `apps/platform/tests/Feature/Localization/`, `apps/platform/tests/Feature/Filament/`, `apps/platform/tests/Feature/Guards/`, and `apps/platform/tests/Browser/` ## Filament v5 / Surface Notes - **Livewire v4.0+ compliance**: all touched admin surfaces remain on Filament v5 with Livewire v4. - **Provider registration location**: provider registration remains in `apps/platform/bootstrap/providers.php`; nothing moves to `bootstrap/app.php`. - **Global search rule**: - `ChooseTenant` and `ManagedTenantsLanding` are pages, not globally-searchable resources. - `TenantDashboard` remains a page and does not change global-search posture. - If any touched registry resource label is updated during implementation, the resource must keep its existing `View` or `Edit` destination and current global-search behavior. - **Destructive actions**: `286` introduces no new destructive action. Any touched destructive-like actions on adjacent pages keep their existing `->action(...)`, `->requiresConfirmation()`, and server authorization. - **Asset strategy**: no new asset registration or deploy-step change is planned. ## Neutralization Contract Fit - Use `Environment` as the default operator noun for chooser, shell, dashboard, and default action copy. - Use `Managed environment` only where a registry or heading must distinguish the object from a workspace. - Use `Provider` as the generic external-system noun when the action headline does not need a specific provider name. - Keep explicit provider names only when the provider itself is the subject, such as auth-provider flows or secondary helper text. - Replace direct `tenant_*` glossary keys and only local template-owned labels/test IDs on the in-scope admin surfaces instead of preserving alias keys for convenience. Shared cross-surface payload contracts outside the enumerated surface set remain unchanged in `286`. - Do not rename internal route names, slugs, class names, or database fields in `286`. ## UI / Surface Guardrail Plan - **Guardrail scope**: changed surfaces - **Native vs custom classification summary**: mostly native Filament pages plus existing Blade views and widget templates - **Shared-family relevance**: navigation, shell scope messaging, dashboard chips, workspace widgets, helper text - **State layers in scope**: shell, page, widget view, localization key, view-model payload - **Audience modes in scope**: operator-MSP, support-platform - **Decision/diagnostic/raw hierarchy plan**: environment-first decision copy, diagnostics-second, provider/raw-third - **Raw/support gating plan**: provider-specific detail remains helper or secondary text; raw/debug detail stays out of the default-visible path - **One-primary-action / duplicate-truth control**: chooser and registry surfaces keep one dominant environment-selection action; headings and shell labels stay orientation-only - **Handling modes by drift class or surface**: review-mandatory - **Repository-signal treatment**: review-mandatory for any remaining in-scope tenant-first or default-visible provider-first noun after implementation - **Special surface test profiles**: standard-native-filament, global-context-shell - **Required tests or manual smoke**: functional-core, browser-smoke - **Exception path and spread control**: none; any need for route or RBAC renaming becomes `follow-up-spec` - **Active feature PR close-out entry**: Smoke Coverage ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes - **Systems touched**: localization catalogs, shared shell helpers, page-title methods, dashboard chips, workspace widgets, `PolicyResource`, `ViewPolicy`, `VersionsRelationManager`, `baseline-compare-landing`, and their helper text consumers - **Shared abstractions reused**: current translation catalogs, `WorkspaceContext`, `OperateHubShell`, `CanonicalNavigationContext`, current widget view-models, and current Filament translation usage - **New abstraction introduced? why?**: none - **Why the existing abstraction was sufficient or insufficient**: current abstractions already own the right UI seams; they simply expose the wrong nouns today - **Bounded deviation / spread control**: no new local glossary or alias layer; in-scope files converge on the same key family and noun decisions, but shared payload keys outside the enumerated surface set remain unchanged until a later bounded cleanup slice owns them ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: no - **Central contract reused**: `N/A` - **Delegated UX behaviors**: `N/A` - **Surface-owned behavior kept local**: `N/A` - **Queued DB-notification policy**: `N/A` - **Terminal notification path**: `N/A` - **Exception path**: none ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: yes - **Provider-owned seams**: auth-provider labels, provider-specific helper detail, Graph-specific explanations, explicit provider names in secondary copy - **Platform-core seams**: environment chooser labels, shell scope labels, dashboard titles, registry return links, default action/helper nouns on environment-scoped admin surfaces - **Neutral platform terms / contracts preserved**: `workspace`, `environment`, `managed environment`, `provider`, `environment scope` - **Retained provider-specific semantics and why**: provider names remain where the provider itself is the subject of the action or the diagnostic explanation - **Bounded extraction or follow-up path**: no broader provider-surface cleanup in this slice; if additional provider-first copy is discovered outside the bounded surfaces, record it as `follow-up-spec` ## Constitution Check *GATE: Must pass before implementation begins and again after design artifacts are complete.* - Inventory-first / snapshot truth: PASS. No persisted truth changes. - Read/write separation: PASS. This is a read-only copy and IA slice. - Graph contract path: PASS. No new Graph usage. - Deterministic capabilities: PASS. Capability and RBAC semantics are unchanged. - RBAC-UX plane separation: PASS. `/admin` versus `/system` remains unchanged. - Workspace isolation: PASS. Workspace selection and environment entitlement remain existing boundaries. - Managed-environment isolation: PASS. Copy changes do not widen discoverability. - Destructive action discipline: PASS by preservation. No new destructive action is introduced. - Global search safety: PASS. No new globally-searchable resource is introduced by this slice. - OperationRun / Ops-UX: PASS. No start/completion/link semantics change. - Data minimization: PASS. No new payload or storage surface. - Test governance: PASS. Proof stays bounded to feature and one browser smoke. - Proportionality / no premature abstraction: PASS. No new abstraction or framework is introduced. - Persisted truth / behavioral state: PASS. No new state or table. - UI semantics / shared pattern first / Filament-native UI: PASS. Existing native surfaces remain primary. - Provider boundary: PASS with implementation condition. Default-visible copy must stay platform-core while provider-specific detail remains secondary. **Gate evaluation**: PASS. **Post-design re-check**: PASS while `spec.md`, `plan.md`, `tasks.md`, `research.md`, `data-model.md`, `quickstart.md`, `contracts/ui-copy-ia-localization-neutralization.logical.openapi.yaml`, and `checklists/requirements.md` stay aligned on the same noun choices, proof commands, and explicit non-goals. ## Test Governance Check - **Test purpose / classification by changed surface**: Feature, Browser - **Affected validation lanes**: confidence, browser - **Why this lane mix is the narrowest sufficient proof**: in-scope changes are rendered labels and helper text on existing admin surfaces, plus one chooser-to-environment orientation flow - **Narrowest proving command(s)**: - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Localization/EnvironmentContextTerminologyTest.php tests/Feature/Filament/EnvironmentContextSurfaceCopyTest.php tests/Feature/Filament/Localization/PolicyInventoryLocalizationTest.php tests/Feature/Guards/EnvironmentCopyNeutralizationGuardTest.php` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec286EnvironmentCopyNeutralizationSmokeTest.php` - `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - **Fixture / helper / factory / seed / context cost risks**: low to moderate because proof needs a workspace, one managed environment, and current admin page rendering only - **Expensive defaults or shared helper growth introduced?**: no; any new view-model helper stays local to the bounded admin surfaces - **Heavy-family additions, promotions, or visibility changes**: none beyond one bounded browser smoke - **Surface-class relief / special coverage rule**: standard-native-filament relief for page-title and translation tests; global-context-shell coverage for shell labels and chooser flow - **Closing validation and reviewer handoff**: rerun the commands above, verify that no in-scope surface still renders `tenant` or default-visible `Microsoft` nouns where a platform noun is sufficient, verify auth-provider labels remain unchanged, and verify no route or RBAC symbol changed under the guise of copy cleanup - **Budget / baseline / trend follow-up**: contained feature-local increase only - **Review-stop questions**: did the implementation rename routes, slugs, classes, or capabilities; did it neutralize auth-provider labels that should remain provider-owned; did it leave tenant-first nouns in in-scope surfaces - **Escalation path**: `follow-up-spec` for any broader symbol or provider-surface cleanup discovered during implementation - **Active feature PR close-out entry**: Smoke Coverage - **Why no dedicated follow-up spec is needed**: the reserved guardrail pack already exists as Spec `287`; `286` only needs the bounded operator-copy slice ## Review Checklist Status - **Review checklist artifact**: `checklists/requirements.md` - **Review outcome class**: `acceptable-special-case` - **Workflow outcome**: `keep` - **Test-governance outcome**: `keep` - **Resolution note**: the package is implementation-ready as a bounded copy and IA convergence slice over already-real workspace-first admin seams; no route, RBAC, provider, or schema expansion is required - **Escalation rule**: if implementation requires route or slug or class renames, capability renames, or broad provider-surface cleanup, split that work into a follow-up spec instead of widening `286` ## Rollout Considerations - Land the shared shell and chooser noun changes together so operators do not see mixed tenant/environment wording during the transition. - Update translation keys and directly surfaced view-model labels before or alongside Blade/template consumers so raw translation keys or mismatched labels do not leak. - Keep provider-neutral helper text scoped to the confirmed restore/capture/baseline-compare entry surfaces only; do not chase provider wording across the entire codebase in the same slice. ## Risk Controls - Reject any implementation that renames routes, slugs, classes, capabilities, or database fields. - Reject any implementation that neutralizes auth-provider wording where the provider is genuinely the subject. - Reject any implementation that introduces translation-key aliases instead of canonically replacing the in-scope key family. - Reject any implementation that broadens into website localization, customer-review localization, or provider-capability work. ## Research & Design Outputs - `research.md` records the glossary decisions, retained provider-owned detail, and rejected alternatives. - `data-model.md` captures the derived copy contract, translation-key family changes, and view-model label expectations. - `quickstart.md` gives reviewers the bounded proof flow and exact commands. - `contracts/ui-copy-ia-localization-neutralization.logical.openapi.yaml` models the logical GET/view-model surfaces for chooser, registry, dashboard, shell/context-bar labels, and the pinned policy/baseline-compare helper surfaces. - `checklists/requirements.md` records package readiness and review outcome. ## Project Structure ### Documentation (this feature) ```text specs/286-ui-copy-ia-localization-neutralization/ ├── checklists/ │ └── requirements.md ├── contracts/ │ └── ui-copy-ia-localization-neutralization.logical.openapi.yaml ├── data-model.md ├── plan.md ├── quickstart.md ├── research.md ├── spec.md └── tasks.md ``` ### Source Code (repository root) ```text apps/platform/ ├── app/ │ ├── Filament/Pages/ │ ├── Support/OperateHub/ │ └── Support/Navigation/ ├── lang/ ├── resources/views/filament/ └── tests/ ├── Browser/ └── Feature/ ``` **Structure Decision**: keep all implementation inside the existing Laravel admin surface, localization catalogs, and current test directories. No new base directory is needed.