# Implementation Plan: Spec 437 - Exchange Comparable Promotion Slice 1 **Branch**: `feat/437-exchange-comparable-promotion-slice-1` | **Date**: 2026-07-09 | **Spec**: [spec.md](./spec.md) **Input**: Feature specification from `specs/437-exchange-comparable-promotion-slice-1/spec.md` ## Summary Derive deterministic machine-comparable payloads for exactly `transportRule`, `remoteDomain`, and `inboundConnector` from immutable Spec 436 Exchange PowerShell content-backed evidence. The builder must consume only `normalized_payload` as material input, require a valid SHA-256 `payload_hash` plus content-backed/captured provenance gates, preserve existing evidence rows, keep persisted coverage state unchanged, represent protected values through redacted presence/count/safe-state semantics, emit stable identity as a scoped app-keyed HMAC anchor, enforce value policies for exact safe fields, keep compare-shape/source contract metadata hash-relevant, and add no renderable output, certification, restore, UI, customer output, jobs, schedules, listeners, migrations, `tenant_id`, new OperationRun type, or Exchange-specific compare table. ## Technical Context **Language/Version**: PHP 8.4 / Laravel 12 **Primary Dependencies**: Laravel, Pest 4, existing TenantConfiguration Coverage v2 services **Storage**: Existing PostgreSQL-backed Coverage v2 tables are read only for this slice; no migration, comparable artifact persistence, or persisted coverage-level promotion planned **Testing**: Pest unit and feature tests **Validation Lanes**: fast-feedback and confidence; browser N/A **Target Platform**: Laravel Sail locally, Dokploy/container deployment for staging/production **Project Type**: Laravel monolith under `apps/platform` **Performance Goals**: deterministic in-memory comparable derivation with no remote/provider calls **Constraints**: normalized-payload-only material input, valid SHA-256 payload hash and content-backed/captured provenance required, evidence immutability, no persisted `coverage_level = comparable`, protected config redaction, exact safe field value policies, scoped HMAC identity anchors, no rendered surface **Scale/Scope**: exactly three Exchange PowerShell resource types ## 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, if applicable**: backend-only. - **Native vs custom classification summary**: N/A. - **Shared-family relevance**: backend Coverage v2 evidence/compare semantics only. - **State layers in scope**: none. - **Audience modes in scope**: N/A. - **Decision/diagnostic/raw hierarchy plan**: N/A at UI layer; raw/provider/protected values must not enter comparable output. - **Raw/support gating plan**: raw evidence remains internal storage only; comparable output contains no raw/protected exact values and does not update persisted coverage/readiness state. - **One-primary-action / duplicate-truth control**: N/A. - **Handling modes by drift class or surface**: hard stop if any rendered surface, route, action, report, download, or customer output appears. - **Repository-signal treatment**: review-mandatory for any accidental UI/read-model/customer/report/trigger file change. - **Special surface test profiles**: N/A. - **Required tests or manual smoke**: `N/A - no rendered UI surface changed`. - **Exception path and spread control**: 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**: comparable-only backend service and tests. - **Navigation / Filament provider-panel handling**: no changes. - **Screenshot or page-report need**: no. ## Product Surface Contract Plan - **Product Surface Contract reference**: `docs/product/standards/product-surface-contract.md` checked for no-rendered-surface path. - **No-legacy posture**: canonical bounded addition; no aliases, fallback readers, hidden routes, duplicate UI, old labels, or legacy fixtures. - **Page archetype and surface budget plan**: N/A. - **Technical Annex and deep-link demotion plan**: N/A at runtime; OperationRun/evidence/raw IDs/source keys/payloads are not rendered. - **Canonical status vocabulary plan**: N/A - no product status vocabulary. - **Product Surface exceptions**: none. - **Browser verification plan**: `N/A - no rendered UI surface changed`. - **Human Product Sanity plan**: N/A. - **Visible complexity outcome target**: neutral. - **Implementation report target**: `specs/437-exchange-comparable-promotion-slice-1/implementation-report.md`. ## Filament / Livewire / Deployment Posture - **Livewire v4 compliance**: unchanged; no Livewire/Filament code changes. - **Panel provider registration location**: unchanged; no panel provider registration change. Laravel panel providers remain under `apps/platform/bootstrap/providers.php`. - **Global search posture**: unchanged; no Filament Resource changed. - **Destructive/high-impact action posture**: none. - **Asset strategy**: no assets; no new `filament:assets` requirement. - **Testing plan**: focused unit and feature tests only; browser N/A. - **Deployment impact**: no env vars, migrations, queues, scheduler, storage, assets, routes, jobs, listeners, or commands. ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes, backend Coverage v2 comparable semantics. - **Systems touched**: existing TenantConfiguration evidence/comparable service layer. - **Shared abstractions reused**: Spec 436 normalized evidence payloads; existing evidence models; existing hash/provenance metadata; app-keyed HMAC identity anchoring. - **New abstraction introduced? why?**: bounded `ExchangePowerShellComparablePayloadBuilder` because existing generic/ExchangeTeams compare paths do not enforce Spec 436 normalized-payload-only material input, required content-backed provenance, target-specific protected-value safety, exact safe field value policies, scoped identity HMAC anchoring, and no persisted coverage-level promotion for this slice. - **Why the existing abstraction was sufficient or insufficient**: Evidence storage is sufficient. Existing generic/ExchangeTeams comparable normalizers are insufficient and forbidden for this input path. - **Bounded deviation / spread control**: provider-specific builder stays local to Exchange PowerShell evidence for three types; no platform-core status/persistence/UI/customer seam change. ## 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**: none. - **Queued DB-notification policy**: N/A. - **Terminal notification path**: N/A. - **Exception path**: none. OperationRun implementation posture: - Do not add or modify `OperationRunType` or `OperationCatalog`. - Do not use Exchange PowerShell invocation runs as comparable owners. - Do not use OperationRun context as input. - Do not store comparable payloads, deltas, raw output, transcripts, protected config, or customer text in OperationRun context/messages/notifications. ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: yes. - **Provider-owned seams**: Exchange PowerShell comparable payload builder and target-specific safe field mapping. - **Platform-core seams**: Coverage v2 evidence remains source truth; ownership remains workspace + managed environment + provider connection. - **Neutral platform terms / contracts preserved**: evidence, comparable payload, normalized payload, resource type, workload, provider connection, managed environment, operation run provenance. - **Retained provider-specific semantics and why**: `transportRule`, `remoteDomain`, `inboundConnector`, Exchange PowerShell source metadata, and protected Exchange config semantics are required for this bounded slice. - **Bounded extraction or follow-up path**: Spec 438 internal render model is separate. ## Constitution Check | Principle / Gate | Result | Notes | |---|---|---| | Inventory-first / evidence truth | PASS | Comparable derives only when immutable evidence is content-backed/captured and does not promote persisted evidence coverage level. | | Read/write separation | PASS | No provider writes, restore, apply, destructive action, or UI action. | | Graph contract path | PASS | No Graph or Exchange call in Spec 437. | | Deterministic capabilities | PASS | Comparable derivation is deterministic and testable. | | Workspace isolation | PASS | No new ownership truth; evidence scope remains existing workspace/managed-environment/provider connection. | | RBAC-UX | PASS | No routes/actions/resources/global search. | | OperationRun truth | PASS | No new OperationRun type; context not input. | | Evidence anchor contract | PASS | No fallback-to-latest or OperationRun-as-proof. | | Data minimization | PASS | Raw/protected values excluded from comparable payloads; unexpected exact protected/sensitive values block output. | | Product Surface | PASS | N/A - no rendered UI surface changed. | | Customer output | PASS | No customer output, reports, Review Packs, PDFs, or customer claims. | | Provider boundary | PASS | Provider-specific builder is bounded and local. | | Test governance | PASS | Unit/Feature only; Browser N/A. | | Proportionality | PASS | One bounded helper; no persistence/status/UI framework. | | TCM/Coverage v2 cutover guard | PASS | No legacy adapters, fallback readers, dual writes, tenant_id, or customer claims. | ## Test Governance Check - **Test purpose / classification by changed surface**: Unit for builder/comparator determinism and redaction; Feature for evidence immutability and no-promotion/no-surface guards. - **Affected validation lanes**: fast-feedback, confidence. - **Why this lane mix is the narrowest sufficient proof**: Spec 437 changes backend comparable behavior only; no browser/render/provider execution lane is needed. - **Narrowest proving command(s)**: - `cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec437 --compact` - targeted regressions listed in Phase 6. - **Fixture / helper / factory / seed / context cost risks**: reuse existing TenantConfiguration evidence factories/helpers; avoid global defaults. - **Expensive defaults or shared helper growth introduced?**: no. - **Heavy-family additions, promotions, or visibility changes**: none. - **Surface-class relief / special coverage rule**: N/A. - **Closing validation and reviewer handoff**: reviewer must verify valid payload hash and content-backed/captured provenance gates, scoped HMAC identity anchors, exact safe field value policies, no raw payload/context input, no evidence mutation, no UI/customer/trigger/persistence expansion, and exact target scope. - **Budget / baseline / trend follow-up**: none. - **Review-stop questions**: lane fit, redaction, evidence immutability, no-product-surface, no-mini-platform. - **Escalation path**: none unless implementation requires renderable, persistence, UI, or migration; then amend/split. - **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage. - **Why no dedicated follow-up spec is needed**: comparable-only builder is the dedicated bounded slice; renderable is already deferred to Spec 438. ## Project Structure ### Documentation ```text specs/437-exchange-comparable-promotion-slice-1/ |-- checklists/ | `-- requirements.md |-- implementation-report.md |-- plan.md |-- spec.md `-- tasks.md ``` ### Source Code Likely runtime paths if implementation proceeds: ```text apps/platform/app/Services/TenantConfiguration/ |-- ExchangePowerShellComparablePayloadBuilder.php `-- ExchangePowerShellCoverageComparator.php # only if needed apps/platform/tests/Unit/Support/TenantConfiguration/ `-- Spec437ExchangeComparablePayloadBuilderTest.php apps/platform/tests/Feature/TenantConfiguration/ `-- Spec437ExchangeComparablePromotionFeatureTest.php ``` **Structure Decision**: Use existing TenantConfiguration service/test locations. Do not create new base folders, migrations, routes, UI surfaces, jobs, listeners, schedules, commands, or customer-output paths. ## Complexity Tracking | Violation | Why Needed | Simpler Alternative Rejected Because | |---|---|---| | New bounded builder helper | Required to enforce normalized-payload-only input and protected Exchange target semantics. | Reusing generic/ExchangeTeams normalizer would violate Spec 437 input and redaction gates. | ## Proportionality Review - **Current operator problem**: Future compare/render/certification work cannot safely proceed until Exchange evidence can be compared without leaking protected configuration or overclaiming readiness. - **Existing structure is insufficient because**: Existing generic/ExchangeTeams comparable path predates Spec 436 normalized evidence and includes broader renderable behavior that Spec 437 explicitly defers. - **Narrowest correct implementation**: One local builder for three concrete Exchange PowerShell target types; comparator only if needed; no persisted comparable artifact or coverage-level promotion. - **Ownership cost created**: Focused tests and future review burden around redaction/determinism. - **Alternative intentionally rejected**: Raw payload compare, normalized provider payload compare outside Spec 436 evidence, and ExchangeTeamsComparablePayloadNormalizer reuse. - **Release truth**: Current-release prerequisite for the Exchange roadmap. ## Phase 0 - Preflight - Capture branch and HEAD. - Capture `git status --short`. - Confirm Spec 436 PASS/merge-ready or merged at current base. - Confirm target types content-backed. - Confirm comparable-only scope. - Confirm renderable deferred. - Confirm no UI/jobs/schedules/listeners/migration scope. - Confirm no hard-gate stop condition. Deliverable: Preflight documented in `implementation-report.md`. ## Phase 1 - Comparable Builder - Add Exchange PowerShell comparable payload builder. - Use `normalized_payload` only. - Require a valid SHA-256 `payload_hash`, `evidence_state = content_backed`, `coverage_level = content_backed`, and `capture_outcome = captured`. - Forbid raw payload/stdout/stderr/transcript input. - Forbid OperationRun context input. - Add deterministic output shape. Deliverable: Comparable builder exists and is covered by unit tests. ## Phase 2 - Target Comparable Payloads - Add `transportRule` comparable payload. - Add `remoteDomain` comparable payload. - Add `inboundConnector` comparable payload. - Encode protected config using redacted presence/count/safe-state semantics. - Block unexpected exact protected/sensitive values rather than sanitizing them through. - Validate exact safe fields by target-specific value policy before output. - Emit stable identity through scoped HMAC anchors instead of exact values or unsalted hashes. - Keep compare-shape and normalizer contract metadata hash-relevant; exclude run/evidence provenance from comparable hash. - Exclude volatile fields. Deliverable: Three target comparable payloads. ## Phase 3 - Determinism / Delta Semantics - Prove deterministic comparable payload. - Prove material changes produce changed comparable payload or machine deltas. - Prove volatile changes ignored. - Prove provider ordering deterministic. - Add comparator only if repo architecture requires it. Deliverable: Comparable semantics are deterministic. ## Phase 4 - Safety / Immutability - Prove evidence rows are not mutated. - Prove persisted coverage/resource/resource-type state is not promoted to comparable. - Prove no raw payload leaks. - Prove OperationRun context is not compare input. - Prove no renderable/customer/cert/restore state. Deliverable: Comparable promotion without overclaim. ## Phase 5 - Product Surface Guard - Prove no UI/routes/jobs/schedules/listeners. - Prove no report/review-pack/PDF/customer output. - Prove browser N/A. Deliverable: No product surface changed. ## Phase 6 - Regression / Report - Run focused tests. - Run regressions. - Run Pint. - Run `git diff --check`. - Complete implementation report. Deliverable: Spec 437 implementation report. ## Rollout Considerations - No migration or deployment flag. - No queue/scheduler/storage/asset change. - No `filament:assets` requirement introduced by this spec. - Comparable derivation remains internal backend behavior until a later spec explicitly adds render/read-model/customer surfaces. ## Risk Controls - Hard stop on raw payload/context input. - Hard stop on protected exact value leakage. - Hard stop on missing content-backed/captured provenance. - Hard stop on invalid payload hash or malformed exact safe field values. - Hard stop on evidence mutation. - Hard stop on UI/read-model/customer/report/trigger/migration expansion. - Hard stop on new OperationRun type or tenant_id ownership truth. - Use static/no-surface tests in addition to behavior tests.