TenantAtlas/specs/438-exchange-internal-render-model-slice-1/plan.md
Ahmed Darrazi 996e64cb93
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 6m3s
docs(spec): defer Spec 438 close-out
2026-07-10 15:26:48 +02:00

363 lines
21 KiB
Markdown

# Implementation Plan: Spec 438 - Exchange Internal Render Model Slice 1
**Branch**: `feat/438-exchange-internal-render-model-slice-1` | **Date**: 2026-07-10 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `specs/438-exchange-internal-render-model-slice-1/spec.md`
## Summary
Add one pure local `ExchangePowerShellInternalRenderModelBuilder` that accepts the complete successful result envelope produced by Spec 437 and returns a fixed internal-only model for exactly `transportRule`, `remoteDomain`, or `inboundConnector`. The builder returns `null` for invalid input, validates required envelope/provenance/identity/redaction/target shape, maps only explicit safe fields, derives protected value presence/count summaries, preserves deterministic order, and performs no lookup, write, integration, I/O, or fallback.
**Execution status**: BLOCKED / REFERENCE ONLY. This standalone zero-consumer plan fails PROP-001 and Spec Approval Rubric Rule C and MUST NOT be executed unchanged. A consumer-owning spec must absorb and adapt the relevant contract and tasks; new current-release evidence may justify that new or amended candidate, but documentation alone does not reactivate this plan.
**Implementation Plan Status**: Deferred
**Implementation Work**: Prohibited
**Deployment Impact**: None
No runtime phases will be executed in this spec. No tests will be added in this deferred closeout state. No product surface will change. No deployment action is required.
## Deferred implementation outline
This section keeps the historical technical breakdown as a migration reference only.
## Technical Context
**Language/Version**: PHP 8.4 / Laravel 12
**Primary Dependencies**: Existing `ExchangePowerShellComparablePayloadBuilder` contract/constants, Laravel container, Pest 4
**Storage**: N/A for runtime behavior; existing PostgreSQL-backed rows are used only by the focused immutability feature test
**Testing**: Pest Unit and Feature; explicit heavy-governance/diff review; Browser N/A
**Validation Lanes**: fast-feedback, confidence, targeted regression; no browser lane
**Target Platform**: Laravel Sail locally; existing Dokploy container runtime unchanged
**Project Type**: Laravel monolith under `apps/platform`
**Performance Goals**: deterministic in-memory array transformation with no remote or database work
**Constraints**: one runtime class, complete Spec 437 result envelope only, nullable fail-closed output, fixed target allowlists, no persistence/consumer/framework
**Scale/Scope**: exactly three target types and one model version
No `research.md` is required: the input contract, target projections, redaction marker shape, and repository precedent are resolved from current Spec 437 source/tests. No `data-model.md`, `contracts/`, or `quickstart.md` is required because the slice adds no entity, schema, API, route, command, or user workflow.
## Repository Truth And Prerequisite
- Base HEAD `ff1a545c` is `Spec 437: Exchange comparable promotion slice 1 (#504)`.
- `specs/437-exchange-comparable-promotion-slice-1/implementation-report.md` records PASS and merge-ready.
- The Spec 437 builder success envelope is top-level `comparable`, `blocker`, `resource_type`, `payload`, `comparable_hash`.
- Workload, nested resource type, comparable shape version, compare-input marker, identity, target projection, redaction, source, and provenance are nested inside `payload`.
- Comparable payload shape is `exchange-powershell-comparable-payload-v1`.
- Spec 437 has no runtime call site outside its tests; zero current consumers is a documented proportionality risk.
- Spec 422 and Specs 429-437 remain read-only history.
## Public API And Failure Contract
Planned method:
```php
public function build(array $comparableResult): ?array
```
- Valid complete success envelope -> fixed render model array.
- Any invalid, blocked, malformed, unsupported, mismatched, or unsafe envelope -> `null`.
- No blocker enum/result DTO/exception taxonomy is added.
- The API does not accept models or context objects and performs no lookup.
## Target Mapping Plan
### Common validation
Validate before mapping:
1. Top-level success marker, null blocker, supported resource type, associative payload, and SHA-256 comparable hash.
2. Nested workload, matching resource type, comparable shape version, and `normalized_payload_only` marker.
3. Identity field/HMAC/source-key shape and source-key consistency.
4. Redaction marker `protected_values_use_safe_markers=true`.
5. Content-backed/captured provenance markers and SHA-256 payload hash.
6. Target-required array sections, accepting empty sections but rejecting non-empty list-shaped sections.
7. Spec 437 comparable-hash consistency by canonicalizing the payload without provenance and comparing the recomputed hash in constant time; this unkeyed hash is not origin or provenance authentication.
8. Canonical remote-domain identity denylist plus `domain_name_is_identity=false`.
9. Inbound routing duplicates agree with canonical material values when present.
10. Recognized allowlisted scalar policies and redacted-marker consistency; recognized fields not explicitly safe as exact scalars are marker-only.
11. Every value in validation-only `protected_values` and `sensitive_values` is a canonical redacted marker with the exact marker key set; raw scalars, lists, nested non-marker maps, and additional marker keys fail closed.
Unknown non-allowlisted field names are ignored for output and counts, except that every value inside the wholly protected/sensitive validation sections must still pass canonical marker validation. Missing/malformed required structure or malformed recognized data returns `null`.
### Shared output
Emit in fixed order:
1. `resource_type`
2. `workload`
3. `model_version`
4. `internal_only`
5. `customer_output`
6. `certified`
7. `restore_ready`
8. `identity_label`
9. `sections`
Identity/HMAC/source key, hashes, source metadata, and provenance are validation-only and never emitted.
### `transportRule`
- Map `material.enabled`, `material.state`, `material.mode`, and canonical integer priority.
- Emit the exact section/field/label order defined in the spec, including explicit `null` optional scalars and fixed zero-valued counts.
- Summarize only the explicit condition/action/exception allowlists from the spec.
- Preserve allowlisted safe action scalars.
- Count configured fields separately from redacted values.
- Do not count duplicate `protected_values`/`sensitive_values` validation sections.
### `remoteDomain`
- Reject canonical identity fields `domainname`, `displayname`, and `name`, and require validation-only `remote_domain_class.domain_name_is_identity=false`.
- Derive `default`/`custom` from `remote_domain_class.is_default`.
- Emit only exact safe `settings.auto_reply_enabled`.
- Emit the exact section/field/label order defined in the spec; all other recognized settings are marker-only.
- Aggregate fixed delivery/message setting groups through marker presence/count semantics.
- Never emit exact domain or identity.
### `inboundConnector`
- Map material `enabled`, canonical connector type, and `require_tls`.
- Reject present routing duplicates that disagree with those canonical material values.
- Summarize only named routing keys through safe presence/count fields.
- Emit the exact section/field/label order defined in the spec; non-duplicate recognized routing fields are marker-only.
- Treat routing copies of material fields as validation duplicates, not second display truth.
- Never emit raw IP/domain/host/smart-host/certificate/comment/source/routing values.
## Count And Canonicalization Plan
- `configured_field_count`: recognized key with non-null safe scalar or present marker.
- `redacted_field_count`: recognized key represented by a valid marker.
- `redacted_value_count`: sum of valid marker counts.
- Unknown keys do not count.
- `protected_values`/`sensitive_values` validate safety but do not contribute display counts.
- Priority normalizes non-negative integer or digit string to integer.
- Safe enums require strings, canonicalize through trim + ASCII non-alphanumeric removal + lowercase, and use only the fixed token-to-output map in the spec (including `auditandnotify -> audit_and_notify` and `onpremises -> on_premises`).
- Marker `state` must agree with `present` and `count`.
- Fixed section/field insertion order is canonical; non-semantic lists are sorted before output.
- Protected exact-value stability uses compositional proof: Spec 437 regression owns exact-value-to-marker equivalence, and Spec 438 accepts only the resulting comparable-envelope semantics.
## UI / Surface Guardrail Plan
- **Guardrail scope**: no operator-facing surface change.
- **Affected routes/pages/actions/states/navigation/panel/provider surfaces**: N/A.
- **No-impact class**: backend-only.
- **Native vs custom classification**: N/A.
- **Shared-family relevance**: none.
- **State layers in scope**: none.
- **Audience modes**: N/A.
- **Decision/diagnostic/raw hierarchy**: no rendered hierarchy; raw/protected inputs are excluded.
- **Raw/support gating**: excluded from output.
- **One-primary-action / duplicate-truth control**: N/A.
- **Handling modes**: hard stop for any UI/ReadModel/report/download/customer surface.
- **Repository-signal treatment**: review-mandatory changed-file boundary.
- **Special surface test profiles**: N/A.
- **Required tests/manual smoke**: `N/A - no rendered UI surface changed`.
- **Exception path**: none.
- **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage.
- **UI/Productization coverage decision**: No UI surface impact.
- **Coverage artifacts to update**: none.
- **No-impact rationale**: one pure service plus backend tests.
- **Navigation/provider-panel handling**: no change.
- **Screenshot/page-report need**: no.
## Product Surface Contract Plan
- **Reference**: `docs/product/standards/product-surface-contract.md` checked for the no-impact path.
- **No-legacy posture**: no compatibility path, fallback, hidden route, duplicate UI, or old renderer reuse.
- **Page archetype/surface budget**: N/A.
- **Technical Annex/deep-link demotion**: no surface; technical identifiers are omitted.
- **Canonical status vocabulary**: N/A.
- **Product Surface exceptions**: none.
- **Browser verification**: `N/A - no rendered UI surface changed`.
- **Human Product Sanity**: N/A.
- **Visible complexity target**: neutral.
- **Implementation report target**: this deferred standalone close-out uses `implementation-report.md`.
Stand-alone status-only closure must remain the only allowed report purpose for this package.
## Filament / Livewire / Deployment Posture
- **Livewire v4 compliance**: unchanged; no Livewire code.
- **Panel provider registration**: unchanged; providers remain in `apps/platform/bootstrap/providers.php`.
- **Global search**: unchanged; no Resource.
- **Destructive/high-impact actions**: none.
- **Asset strategy**: no assets and no `filament:assets` change.
- **Testing plan**: two focused Pest files, regressions, dependency/diff review; browser N/A.
- **Deployment impact**: no env, migration, queue, scheduler, storage, route, provider, permission, external call, or asset impact.
## Shared Pattern & System Fit
- **Cross-cutting marker**: no shared operator interaction family.
- **Systems touched**: Spec 437 result envelope and local Exchange service seam.
- **Shared abstractions reused**: existing comparable contract constants/shape only.
- **New abstraction**: exactly one local final builder, justified as protected-value leakage boundary.
- **Why existing abstraction is insufficient**: Spec 437 is machine-oriented; legacy renderer consumes another input shape and generically stringifies values.
- **Bounded deviation/spread control**: no interface, registry, DTO, generic base, shared presenter, consumer, or second runtime class.
## OperationRun UX Impact
- **Touches OperationRun start/completion/link UX?**: no.
- **Central contract reused**: N/A.
- **Delegated behaviors**: N/A.
- **Surface-owned behavior**: none.
- **Queued DB notification**: N/A.
- **Terminal notification**: N/A.
- **Exception**: none.
No OperationRun type, catalog entry, row, context, transition, message, or link is created or changed.
## Provider Boundary & Portability Fit
- **Shared boundary touched?**: no.
- **Provider-owned seam**: Exchange PowerShell comparable-to-internal mapping.
- **Platform-core seams**: none.
- **Neutral terms preserved**: resource type, workload, model boundary flags.
- **Retained provider semantics**: three concrete Exchange target mappings only.
- **Follow-up**: the first consumer-owning spec must absorb and adapt this contract; unchanged Spec 438 remains non-executable and no generalization is pre-approved.
## Constitution Check
| Principle / Gate | Result | Plan evidence |
|---|---|---|
| PROP-001 / BLOAT-001 | FAIL | Zero current consumers and no current operator workflow; a future-risk-only layer is not justified by current release truth. |
| ABSTR-001 | PASS only on technical shape | The proposed class is narrow and security-sensitive, but that exception does not cure the standalone Rule C failure. |
| PERSIST-001 | PASS | Derived in memory only. |
| STATE-001 | PASS | No enum/status/reason/lifecycle state. |
| UI-SEM-001 / LAYER-001 | PASS with hard stop | No consumer or shared UI layer; builder does not become product truth. |
| PROV-001 | PASS | Mapping remains provider-owned. |
| TEST-TRUTH-001 / TEST-GOV-001 | PASS | Focused Unit/Feature proof; broad boundary checks remain explicit governance/diff review. |
| Workspace scope safety | PASS / N/A | No record input, query, route, ownership field, or lookup. |
| Evidence anchor contract | PASS | No Evidence input/fallback/mutation and no proof/currentness claim. |
| OperationRun truth | PASS | No OperationRun input/output/state. |
| Customer output gate | PASS | No gate dependency or customer/report output. |
| TCM/Coverage v2 cutover | PASS | No legacy adapter, dual truth, `tenant_id`, or persisted Renderable promotion. |
| Product Surface Contract | PASS / N/A | No rendered surface; browser and sanity N/A. |
| Read/write separation | PASS | Pure readless transformation with no write or external call. |
| Data minimization | PASS | Identity/provenance/hash/raw values excluded. |
The Constitution Check blocks this plan permanently in its standalone form. A consumer-owning spec must migrate the relevant contract/tasks and run its own Constitution Check; new evidence must be encoded in that candidate rather than used to execute this unchanged plan. Any additional class, persistence, status, unauthorized surface, or generic abstraction also fails the migrated design.
## Test Governance Check
- **Test classification**: Unit for pure behavior; Feature for DB immutability; Heavy-Governance/diff for scope/dependency proof; Browser N/A.
- **Affected lanes**: fast-feedback, confidence, targeted regression.
- **Narrowest commands**: Spec 438 filter first, adjacent sequence filters second.
- **Fixture/helper cost**: minimal array fixtures; DB context opt-in only in Feature.
- **Expensive defaults/shared helper growth**: none.
- **Heavy-family changes**: none; no new discovery framework.
- **Surface relief**: N/A backend-only.
- **Closing handoff**: re-run focused tests, regressions, Pint, diff/status, and inspect source dependencies/changed paths.
- **Budget/trend follow-up**: none expected.
- **Review-stop questions**: exact envelope? fixed allowlists? no double counts? no forbidden dependency? one class? no consumer?
- **Escalation path**: reject-or-split on breadth.
- **Workflow outcome**: blocked/defer. The focused lane design may be retained only inside a future consumer-owning spec.
## Project Structure
### Preparation artifacts
```text
specs/438-exchange-internal-render-model-slice-1/
├── spec.md
├── plan.md
├── tasks.md
└── checklists/
└── requirements.md
```
The standalone Spec 438 closeout record is a governance artifact only, not a runtime implementation log. This spec uses `implementation-report.md` to document Deferred status and closure proof only.
### Planned runtime/test files
```text
apps/platform/
├── app/Services/TenantConfiguration/
│ └── ExchangePowerShellInternalRenderModelBuilder.php
└── tests/
├── Unit/Support/TenantConfiguration/
│ └── Spec438ExchangeInternalRenderModelBuilderTest.php
└── Feature/TenantConfiguration/
└── Spec438ExchangeInternalRenderModelFeatureTest.php
```
No other runtime, test-family, documentation, route, UI, migration, job, listener, command, report, or customer-output path is planned.
## Implementation Phases
The phases below are reference work decomposition only. Do not execute them in this package. A future consumer-owning spec may adopt and adapt relevant steps only after its own Candidate Selection and Spec Readiness gates pass.
### Phase 0 - Preflight And Proportionality
- Capture branch/HEAD/dirty state and Spec 437 PASS proof.
- Reconfirm one mapping class, a named current operator workflow and real consumer in the owning spec, plus no persistence/customer-output/general-framework expansion.
- Stop if no real consumer exists, the comparable envelope changed incompatibly, or another mapping runtime class is required.
### Phase 1 - Tests First: Envelope Boundary
- Add failing Unit cases for supported/blocked/malformed envelopes and forbidden object/raw/normalized inputs.
- Fix exact nullable failure behavior and required envelope validation.
- Add dependency guard expectations before implementation.
### Phase 2 - One Local Builder
- Create the final builder with one public method and fixed common output.
- Add explicit target dispatch and no generic traversal/pass-through.
- Keep validation/mapping private within the same class.
### Phase 3 - Target Mappings
- Implement `transportRule`, `remoteDomain`, and `inboundConnector` mappings from explicit allowlists.
- Implement marker validation, count semantics, and enum/priority canonicalization.
- Keep fixed section/field order.
### Phase 4 - Leakage, Determinism, Material Change
- Run the leakage corpus.
- Prove key-order/unknown-key/volatile stability.
- Prove safe material changes and protected exact-value stability.
### Phase 5 - Immutability And Boundary Proof
- Add minimal DB fixtures and prove no rows/attributes mutate.
- Inspect builder dependencies and changed paths.
- Prove no Renderable, ReadModel, old renderer, UI, customer, trigger, migration, or operation integration.
### Phase 6 - Regression And Close-Out
- Run focused and adjacent regressions.
- Run Pint, diff, changed-file, and status checks.
- In the consumer-owning spec only, create and complete that spec's implementation report with the adapted matrices and Product Surface decision.
## Validation Commands
```bash
cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec438 --compact
cd apps/platform && ./vendor/bin/sail artisan test --filter='Spec430|Spec431|Spec432|Spec433|Spec434|Spec435|Spec436|Spec437' --compact
cd apps/platform && ./vendor/bin/sail artisan test --filter='Spec415|Spec417|Spec419|Spec420|Spec421|Spec422|Spec425|Spec426|Spec427|ProviderCapability|SourceContract|CoverageV2Readiness|CustomerOutputGate' --compact
cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent
git diff --check
git diff --name-only
git status --short
```
If Sail is unavailable or is killed during an authorized consumer-owning implementation, that spec's implementation report may record the exact environmental failure and a repo-approved fallback result, following Spec 437 precedent; it must not silently claim the Sail lane passed.
## Complexity Tracking
| Risk | Conditional bounded shape | Current decision |
|---|---|---|
| One local presentation builder with zero current consumers | One class, three concrete mappings, no shared/generic infrastructure | Deferred: migrate the contract into the first real consumer-owning spec; do not revive this plan unchanged |
| Focused Feature immutability proof for a pure builder | Minimal existing-row snapshots only | Conditional on candidate approval; Unit proof alone cannot demonstrate unchanged existing rows |
## Hard Stops
Stop and amend or split if implementation requires:
- executing this standalone reference plan, including after merely documenting a future consumer
- a second runtime class, interface, registry, DTO, presenter family, base class, trait, or generic framework
- Evidence/Resource/ResourceType/OperationRun/normalized/raw/provider input or fallback
- old `ExchangeTeamsRenderableSummaryBuilder` reuse
- generic recursion, unknown-key output, generic stringification, or provider dump
- persisted render model, cache-as-truth, coverage-level promotion, migration, enum, status family, or `tenant_id`
- ReadModel, Filament, Livewire, route, view, navigation, global search, asset, report, Review Pack, PDF, CustomerOutputGate, certification, restore, job, schedule, listener, command, or OperationCatalog integration
- additional Exchange or Teams target types
- broad Heavy-Governance discovery added to fast Unit/Feature lanes
- an unresolved Spec 437 envelope/version change