## Summary - introduce a shared reason-translation contract with envelopes, presenter helpers, fallback handling, and provider translation support - adopt translated operator-facing reason presentation across operation runs, notifications, provider guidance, tenant operability, and RBAC-related surfaces - add Spec 157 design artifacts and targeted regression coverage for translation quality, diagnostics retention, and authorization-safe guidance ## Validation - `vendor/bin/sail bin pint --dirty --format agent` - `vendor/bin/sail artisan test --compact tests/Architecture/ReasonTranslationPrimarySurfaceGuardTest.php tests/Unit/Support/ReasonTranslation/ReasonResolutionEnvelopeTest.php tests/Unit/Support/ReasonTranslation/ExecutionDenialReasonTranslationTest.php tests/Unit/Support/ReasonTranslation/TenantOperabilityReasonTranslationTest.php tests/Unit/Support/ReasonTranslation/RbacReasonTranslationTest.php tests/Unit/Support/ReasonTranslation/ProviderReasonTranslationTest.php tests/Feature/Notifications/OperationRunNotificationTest.php tests/Feature/Operations/OperationRunBlockedExecutionPresentationTest.php tests/Feature/Operations/TenantlessOperationRunViewerTest.php tests/Feature/ReasonTranslation/GovernanceReasonPresentationTest.php tests/Feature/Authorization/ReasonTranslationScopeSafetyTest.php tests/Feature/Monitoring/OperationRunBlockedSpec081Test.php tests/Feature/ProviderConnections/ProviderOperationBlockedGuidanceSpec081Test.php tests/Feature/ProviderConnections/ProviderGatewayRuntimeSmokeSpec081Test.php` ## Notes - Livewire v4.0+ compliance remains unchanged within the existing Filament v5 stack. - No new panel was added; provider registration remains in `bootstrap/providers.php`. - No new globally searchable resource was introduced. - No new destructive action family was introduced. - No new assets were added; the existing `filament:assets` deployment behavior remains unchanged. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #187
175 lines
15 KiB
Markdown
175 lines
15 KiB
Markdown
# 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 |
|