# Implementation Plan: Operator Reason Code Translation and Humanization Contract **Branch**: `157-reason-code-translation` | **Date**: 2026-03-22 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/TenantAtlas/specs/157-reason-code-translation/spec.md` **Input**: Feature specification from `/specs/157-reason-code-translation/spec.md` **Note**: This template is filled in by the `/speckit.plan` command. See `.specify/scripts/` for helper scripts. ## Summary Define one shared reason translation contract that converts stable internal reason codes into operator-facing labels, explanations, retryability classes, and next-step guidance. The implementation should preserve existing backend reason-code precision, avoid new business-domain storage, and adopt the contract first where the repo already centralizes reason-bearing UX: operations notifications and run detail, provider next-step flows, tenant-operability governance, and adopted system-console RBAC or onboarding health surfaces. Existing heuristic string matching in `RunFailureSanitizer` should shrink from being the primary explanation path on adopted surfaces to being a bounded fallback only. ## Technical Context **Language/Version**: PHP 8.4.15 **Primary Dependencies**: Laravel 12, Filament v5, Livewire v4, PostgreSQL, Laravel Sail, Pest v4 **Storage**: PostgreSQL-backed existing records such as `operation_runs`, tenant governance records, onboarding workflow state, and provider connection state; no new business-domain table is required for the first slice **Testing**: Pest feature tests, unit tests for reason-translation contracts and fallback behavior, existing architecture or guard-style tests, focused notification and Filament surface assertions **Target Platform**: Laravel web application running locally via Sail and deployed via Dokploy **Project Type**: Web application **Performance Goals**: No render-time external calls; reason translation must remain constant-time and fit inside current presenter and badge paths; Monitoring and canonical views remain DB-only at render time; notification generation must not add query-heavy joins beyond existing run and tenant lookups **Constraints**: Preserve stable internal reason-code contracts, preserve RBAC 404 versus 403 semantics, preserve existing Ops-UX lifecycle and notification rules, avoid page-local ad-hoc translation helpers, and keep the first slice bounded to central adoption seams rather than full-repo migration **Scale/Scope**: Cross-domain contract foundation plus bounded first-slice adoption across operations and notifications, provider blocking and next-steps, tenant-operability governance, and adopted system-console RBAC or onboarding reason surfaces ### Filament v5 Implementation Notes - **Livewire v4.0+ compliance**: Maintained. This work changes operator-facing explanation behavior inside the existing Filament v5 + Livewire v4 stack and introduces no incompatible Livewire pattern. - **Provider registration location**: No new panel is introduced. Existing panel providers remain registered in `bootstrap/providers.php`. - **Global search rule**: No new globally searchable resource is added. Existing reason-bearing labels and next-step hints must remain non-member-safe on canonical and tenant-context views. - **Destructive actions**: No new destructive action family is introduced. Existing destructive actions on adopted surfaces remain confirmation-protected and capability-gated. - **Asset strategy**: No new global or on-demand assets are planned. Deployment behavior remains unchanged, including `php artisan filament:assets` where already required. - **Testing plan**: Add Pest coverage for reason translation envelopes, fallback behavior, notification wording, adopted surface rendering, and authorization-safe next-step guidance. ## Constitution Check *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* - Inventory-first: PASS. The feature changes explanation semantics only and does not alter inventory versus snapshot ownership or capture paths. - Read/write separation: PASS. No new mutation flow is introduced. Existing write flows remain governed by their owning specs. - Graph contract path: PASS. No new Graph path or contract registry change is required. - Deterministic capabilities: PASS. Capability derivation remains unchanged and continues to gate adopted surfaces server-side. - RBAC-UX plane separation: PASS. The feature spans tenant/admin and system surfaces while preserving 404 for non-members and 403 for in-scope capability denial. - Workspace isolation: PASS. Humanized reason labels, summaries, and next-step hints must be derived only from entitled workspace scope. - Tenant isolation: PASS. Shared reason wording must not leak unauthorized tenant state in canonical views, filters, summaries, or notifications. - Destructive confirmation standard: PASS. No destructive semantics are changed. - Global search tenant safety: PASS WITH WORK. Shared translated labels and next-step hints must remain non-member-safe; focused regression coverage is required. - Run observability: PASS. Existing `OperationRun` usage remains canonical. This feature only changes how reasons are translated and displayed. - Ops-UX 3-surface feedback: PASS WITH WORK. Adopted operation notifications and run details must stay within the existing toast, progress, and terminal notification contract. - Ops-UX lifecycle: PASS. `OperationRun.status` and `OperationRun.outcome` remain service-owned. This feature only changes explanation paths. - Ops-UX summary counts: PASS WITH WORK. `SummaryCountsNormalizer` already humanizes keys, but the first slice must improve reason-bearing summary language without changing the numeric contract. - Ops-UX guards: PASS WITH WORK. Add guard coverage so adopted surfaces cannot fall back to raw or heuristic-only operator reason strings without an approved translation path. - Ops-UX system runs: PASS. No change to initiator-null notification semantics. - Automation: PASS. No queue, lock, or retry mechanism is changed by the contract itself. - Data minimization: PASS. This feature reduces raw reason exposure on primary operator surfaces by pushing internal codes into diagnostics. - Badge semantics (BADGE-001): PASS WITH WORK. Where translated reasons affect status-like wording, they must align with the existing outcome taxonomy and centralized badge semantics. - UI naming (UI-NAMING-001): PASS WITH WORK. Shared reason labels become part of the operator-facing vocabulary and must stay consistent across run detail, notifications, banners, and guidance text. - Operator surfaces (OPSURF-001): PASS WITH WORK. Default-visible content on adopted surfaces must show label, explanation, and next step while relegating raw codes and payload fragments to diagnostics. - Filament UI Action Surface Contract: PASS. Existing action surfaces remain structurally unchanged; the rollout changes explanation copy and guidance only. - Filament UI UX-001: PASS. No new screen category is introduced. Adopted surfaces keep their current layout while improving the operator-first information hierarchy. **Phase 0 Gate Result**: PASS - The feature is bounded to a shared translation contract plus a first-slice adoption set, not a full domain rewrite. - Existing presenter, registry, and notification seams provide a practical implementation path. - The main delivery risk is inconsistency between translated labels and raw-code fallbacks, which is addressable through contract tests and guard coverage. ## Project Structure ### Documentation (this feature) ```text specs/157-reason-code-translation/ ├── plan.md ├── research.md ├── data-model.md ├── quickstart.md ├── contracts/ │ ├── no-external-api-changes.md │ ├── reason-resolution.logical.openapi.yaml │ └── reason-translation-entry.schema.json └── tasks.md ``` ### Source Code (repository root) ```text app/ ├── Filament/ │ ├── Resources/ │ └── Widgets/ ├── Notifications/ ├── Services/ │ ├── Operations/ │ ├── Providers/ │ ├── Tenants/ │ ├── Intune/ │ └── Verification/ ├── Support/ │ ├── Baselines/ │ ├── Operations/ │ ├── OpsUx/ │ ├── Providers/ │ └── Tenants/ └── Models/ tests/ ├── Feature/ ├── Unit/ └── Architecture/ ``` **Structure Decision**: Use the existing Laravel web application structure. The documentation artifacts live under `specs/157-reason-code-translation/`, while the planned implementation targets concentrate in `app/Support/OpsUx`, `app/Support/Providers`, `app/Support/Operations`, `app/Support/Tenants`, `app/Notifications`, `app/Filament/Resources`, and focused Pest suites under `tests/Unit`, `tests/Feature`, and existing guard-oriented directories. ## Phase 0 — Research (complete) - Output: [specs/157-reason-code-translation/research.md](research.md) - Resolved key decisions: - Preserve stable internal reason codes and translate them through a shared resolution envelope rather than renaming backend contracts. - Use existing central seams as first-slice adoption points: `OperationUxPresenter`, `OperationRunCompleted`, `ProviderNextStepsRegistry`, and enum-backed reason families that already model reason semantics. - Reduce `RunFailureSanitizer` from being the primary operator explanation path on adopted surfaces to being a bounded fallback or normalization seam only. - Prefer domain-owned translations behind one common contract shape over a monolithic page-local formatting pattern. - First-slice rollout order is contract foundation, enum-backed families, provider next-step flows, then operations notifications and run-detail wording. ## Phase 1 — Design & Contracts (complete) - Output: [data-model.md](./data-model.md) defines the shared reason artifact, resolution envelope, translation entry, next-step option, and adoption-target model. - Output: [contracts/reason-resolution.logical.openapi.yaml](./contracts/reason-resolution.logical.openapi.yaml) captures the logical request and response contract for resolving a raw reason into operator-facing presentation. - Output: [contracts/reason-translation-entry.schema.json](./contracts/reason-translation-entry.schema.json) defines the documentation-first schema for a translation entry and its actionability constraints. - Output: [contracts/no-external-api-changes.md](./contracts/no-external-api-changes.md) records that this feature is internal-contract work with no public transport API changes. - Output: [quickstart.md](./quickstart.md) documents the recommended rollout order and focused validation commands. ### Post-design Constitution Re-check - PASS: No new panel, Graph path, route family, or business-domain storage is introduced. - PASS: The design preserves Filament v5 + Livewire v4 and keeps provider registration unchanged in `bootstrap/providers.php`. - PASS WITH WORK: Operations notifications, run detail, and summary wording need focused validation so translated labels improve clarity without violating the existing Ops-UX contract. - PASS WITH WORK: Canonical and tenant-context views need explicit non-member regression coverage because translated next-step hints and summary labels are part of the leak surface. - PASS WITH WORK: Fallback behavior must remain understandable by meeting a minimum label, explanation, and action-guidance floor, and it must not become a loophole that reintroduces raw-code-as-primary-message patterns. ## Phase 2 — Implementation Planning `tasks.md` should cover: - Defining the shared reason resolution envelope and domain-facing translation contract in `app/Support` so adopted reason families return the same minimum shape: label, explanation, actionability class, and next-step guidance when applicable. - Implementing the first enum-backed adoption slice for `ExecutionDenialReasonCode`, `TenantOperabilityReasonCode`, and `RbacReason`, reusing their existing semantics while standardizing their operator-facing output. - Extending provider-domain flows so `ProviderReasonCodes` can be resolved through the shared contract and `ProviderNextStepsRegistry` becomes one domain implementation of that contract rather than the only next-step registry in the system. - Updating `OperationUxPresenter` and `OperationRunCompleted` so terminal notifications and run detail wording consume translated reason envelopes instead of raw or heuristically sanitized fragments. - Updating adopted summary and banner paths so humanized labels remain operator-first while raw internal reason codes stay available in diagnostics. - Reducing adopted uses of heuristic string matching in `RunFailureSanitizer` so it no longer acts as the primary operator explanation path on first-slice surfaces. - Adding unit and feature tests for translation envelopes, fallback behavior, retryability or actionability classes, entitlement-safe next-step guidance, and adopted notification wording. - Adding guard coverage that fails when adopted surfaces expose raw internal reason codes as the primary operator-facing message or drift away from the canonical operator vocabulary for blocked, missing, denied, stale, unsupported, partial, and retry states. ### Contract Implementation Note - The OpenAPI file is logical, not transport-prescriptive. It documents how existing presenters, notifications, badge mappers, and Filament surfaces should resolve raw reason state into operator-facing output. - The JSON schema is documentation-first and guard-friendly. It can be enforced through fixtures, curated translation registries, or unit tests rather than a new runtime parser in the first slice. - The no-external-api note makes the boundary explicit: this feature standardizes internal explanation behavior and transport payload composition, not external REST endpoints. ### Deployment Sequencing Note - No migration is expected in the first slice. - No asset publish change is expected. - Recommended rollout order: shared contract foundation, enum-backed adoption slice, provider next-step slice, operations notification and run-detail slice, then broader domain adoption only after guards are green. ### Story Delivery Note - User Story 1 and User Story 2 are both P1. The executable delivery order should start with User Story 2's contract and diagnostic-boundary requirements because preserving backend precision is the precondition for safe translation. - User Story 1 follows immediately through operations and provider-facing wording because those are the highest-leverage operator surfaces. - User Story 3 finishes the first slice by extending the common contract across additional reason families and guard coverage. ## Complexity Tracking | Violation | Why Needed | Simpler Alternative Rejected Because | |-----------|------------|-------------------------------------| | None | Not applicable | Not applicable |