# 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.