# Implementation Plan: Exchange Content-Backed Evidence Promotion Slice 1 **Branch**: `feat/436-exchange-content-backed-evidence-promotion-slice-1` | **Date**: 2026-07-08 | **Spec**: [spec.md](./spec.md) **Input**: Feature specification from `specs/436-exchange-content-backed-evidence-promotion-slice-1/spec.md` ## Summary Promote exactly `transportRule`, `remoteDomain`, and `inboundConnector` to append-only internal content-backed Coverage v2 evidence through the Exchange PowerShell capture adapter. The implementation must replace the current generic/comparable normalizer write path with Spec 435 structured envelopes, target-specific normalizers, and hash builder; preserve Spec 434 identity/content-only guards and empty-collection policy; consume Spec 433 readiness, Spec 432 runner boundary, and Spec 430 command contracts; and add no UI, migration, trigger, compare/render, certification, restore, or customer claim. ## Technical Context **Language/Version**: PHP 8.4.15, Laravel 12, Filament 5, Livewire 4 **Primary Dependencies**: Existing Laravel services, Coverage v2 models, Pest 4, Exchange PowerShell support classes **Storage**: PostgreSQL through existing `tenant_configuration_resources` and `tenant_configuration_resource_evidence`; no migration planned **Testing**: Pest 4 Unit and Feature tests **Validation Lanes**: fast-feedback/confidence; PostgreSQL lane only if implementation unexpectedly touches migration/schema behavior and the spec is amended **Target Platform**: Laravel platform app under `apps/platform` **Project Type**: web monolith backend-only slice **Performance Goals**: deterministic per-item normalization/hash without external calls during tests; no UI render path or browser cost **Constraints**: no raw stdout/stderr evidence, no raw payload outside evidence storage, no generic/comparable normalizer promotion path, no evidence on unsafe identity or failed gates **Scale/Scope**: exactly three Exchange resource types and fake-runner test coverage ## 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 evidence/OperationRun only; no rendered shared interaction family. - **State layers in scope**: backend capture/evidence only. - **Audience modes in scope**: N/A. - **Decision/diagnostic/raw hierarchy plan**: raw provider payload remains evidence-storage-only; diagnostics stay internal; no product layer. - **Raw/support gating plan**: raw payload stored only in evidence storage; no UI support/raw surface. - **One-primary-action / duplicate-truth control**: N/A. - **Handling modes by drift class or surface**: hard-stop-candidate for any UI, route, trigger, report, Review Pack, PDF, or customer output. - **Repository-signal treatment**: review-mandatory for any guarded path change; hard-stop for UI/migration/trigger scope. - **Special surface test profiles**: N/A. - **Required tests or manual smoke**: browser `N/A - no rendered UI surface changed`. - **Exception path and spread control**: none. - **Active feature PR close-out entry**: `N/A - no rendered UI surface changed`. - **UI/Productization coverage decision**: No UI surface impact. - **Coverage artifacts to update**: none. - **No-impact rationale**: backend-only evidence promotion through existing tables and services. - **Navigation / Filament provider-panel handling**: checked no-impact; no provider registration/global search/asset changes. - **Screenshot or page-report need**: no. ## Product Surface Contract Plan - **Product Surface Contract reference**: `docs/product/standards/product-surface-contract.md`. - **No-legacy posture**: canonical replacement; no compatibility exception. - **Page archetype and surface budget plan**: N/A. - **Technical Annex and deep-link demotion plan**: OperationRun details, raw evidence payloads, IDs, source keys, payloads, normalized payloads, and hashes stay internal and are not rendered. - **Canonical status vocabulary plan**: N/A for UI. - **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/436-exchange-content-backed-evidence-promotion-slice-1/implementation-report.md`. ## Filament / Livewire / Deployment Posture - **Livewire v4 compliance**: unchanged; no Livewire runtime code planned. - **Panel provider registration location**: no panel change; Laravel provider registration remains `apps/platform/bootstrap/providers.php`. - **Global search posture**: no Resource/global search change. - **Destructive/high-impact action posture**: none; no UI action or start surface added. - **Asset strategy**: no assets; `filament:assets` is not newly required. - **Testing plan**: Unit/Feature for adapter wiring, target normalizers, hash determinism, identity blocking, append-only evidence, OperationRun safety, redaction, no-promotion, no-surface, and regressions. - **Deployment impact**: no env vars, migrations, queues, scheduler, storage, assets, or Dokploy runtime changes planned. ## Shared Pattern & System Fit - **Cross-cutting feature marker**: yes, backend evidence/capture only. - **Systems touched**: Exchange PowerShell adapter/eligibility/identity/content-only guard, structured output envelope, target normalizers, hash builder, Coverage v2 writer/upserter, OperationRun safe context, provider readiness. - **Shared abstractions reused**: `tenant_configuration.capture`, `OperationSummaryKeys`, `ExchangePowerShellStructuredOutputEnvelope`, `ExchangePowerShellEvidenceNormalizer`, `ExchangePowerShellHashInputBuilder`, `CanonicalIdentityResolver`, `CoverageResourceUpserter`, `CoverageEvidenceWriter`. - **New abstraction introduced? why?**: none planned. Use existing Spec 434/435 classes. If a helper is needed, keep it private/narrow and document in the report. - **Why the existing abstraction was sufficient or insufficient**: Coverage v2 storage and Spec 434/435 services are sufficient. The current adapter normalizer path is insufficient because it still uses `GenericPayloadNormalizer` and `ExchangeTeamsComparablePayloadNormalizer`. - **Bounded deviation / spread control**: Exchange-specific normalization stays provider-owned and does not alter platform-core evidence table semantics. ## OperationRun UX Impact - **Touches OperationRun start/completion/link UX?**: no rendered UX; internal OperationRun ownership/context only. - **Central contract reused**: existing `tenant_configuration.capture` lifecycle conventions. - **Delegated UX behaviors**: N/A. - **Surface-owned behavior kept local**: none. - **Queued DB-notification policy**: N/A. - **Terminal notification path**: unchanged. - **Exception path**: none; adding a new operation/start UX requires spec amendment. ## Provider Boundary & Portability Fit - **Shared provider/platform boundary touched?**: yes. - **Provider-owned seams**: Exchange PowerShell command contracts, source surface, structured item shape, target-specific normalizers, protected field handling. - **Platform-core seams**: Coverage v2 evidence/resource storage, OperationRun truth, workspace/managed-environment/provider scope, identity hard-stop, redaction/no-customer-output, no-promotion posture. - **Neutral platform terms / contracts preserved**: provider connection, managed environment, evidence, capture outcome, content-backed, operation run, canonical identity, payload hash. - **Retained provider-specific semantics and why**: `transportRule`, `remoteDomain`, `inboundConnector`, and Exchange PowerShell contract names are required for this bounded first Exchange slice. - **Bounded extraction or follow-up path**: Spec 437 can promote comparable/renderable only after Spec 436 passes. ## Constitution Check | Principle | Plan Result | Notes | |---|---|---| | Inventory-first / evidence truth | PASS | Writes existing Coverage v2 evidence as internal source-backed proof; no customer/product truth. | | Read/write separation | PASS | Backend evidence append only through trusted flow; no destructive or restore/apply action. | | Graph contract path | PASS | Exchange PowerShell path must not route through Graph gateway or fake Graph endpoints. | | Deterministic capabilities | PASS | Spec 433 readiness and provider capability stay gate truth. | | RBAC / workspace isolation | PASS | Existing scope fields and provider connection scope required; no route/action change. | | OperationRun truth | PASS | `tenant_configuration.capture` is evidence owner; invocation operation remains runner truth. | | Summary counts | PASS | Use allowed keys or amend spec before adding keys. | | Data minimization | PASS | Raw structured provider item only in evidence storage; no raw stdout/stderr/transcripts. | | Test governance | PASS | Unit/Feature focused tests; Browser N/A. | | Proportionality | PASS | No new table, OperationRun type, UI framework, or status family planned. | | Provider boundary | PASS | Exchange semantics remain provider-owned. | | Product Surface | PASS | N/A - no rendered UI surface changed. | ## Test Governance Check - **Test purpose / classification by changed surface**: Unit for normalizer/hash/identity blockers; Feature for DB-backed evidence append, OperationRun safety, append-only/latest-pointer, redaction, no-surface guard. - **Affected validation lane(s)**: fast-feedback/confidence. Browser N/A. - **Fixture/helper/factory/seed/context cost**: reuse existing Spec 430-435 fake runner/readiness fixtures; keep provider/workspace setup explicit. - **Heavy-governance or browser family impact**: none. - **Narrowest reviewer command**: focused `Spec436` tests plus listed regression filters. - **Budget/baseline/trend follow-up**: none expected. - **Review outcome target**: `document-in-feature` for any bounded non-blocking conditions; `reject-or-split` for UI/migration/trigger/target expansion/no-promotion violations. ## Technical Approach 1. Re-check Spec 435 PASS/merge-ready state and current branch/dirty state. 2. Add failing focused tests for adapter wiring, target-specific normalizer usage, hash determinism, identity blocking, append-only evidence, raw payload location, OperationRun sanitization, no-promotion, no-surface, and no-tenant-id behavior. 3. Update `ExchangePowerShellEvidenceCaptureAdapter` so non-empty eligible Exchange captures build a Spec 435 envelope from runner output, evaluate target-specific normalizer readiness, use normalized target payloads and `ExchangePowerShellHashInputBuilder` hash output, and append evidence with content-only cap. 4. Remove or bypass `GenericPayloadNormalizer` and `ExchangeTeamsComparablePayloadNormalizer` for Exchange evidence promotion; preserve generic Graph capture path. 5. Keep Spec 434 eligibility, identity, content-only, and empty-collection behavior intact. 6. Ensure OperationRun context/summary remains sanitized and uses allowed summary keys. 7. Run focused tests, regressions, Pint, `git diff --check`, and complete the implementation report. ## Domain / Model Implications - No new models, migrations, tables, columns, enum/status family, OperationRun type, UI state, or customer output artifact. - Existing `TenantConfigurationResource` latest pointer update remains the source for latest evidence state. - Existing `TenantConfigurationResourceEvidence` stores raw structured provider item, normalized payload, hash, source metadata, operation, scope, and content-backed coverage state. ## Data / Migration Plan No migration. Runtime must use existing Coverage v2 tables. If a schema gap is discovered, implementation must stop and amend spec/plan/tasks before proceeding. ## Security / RBAC / Redaction Plan - Reuse trusted backend flow and provider/capture authorization. - Preserve workspace, managed environment, and provider connection scope checks. - Require combined Exchange readiness before evidence append. - Keep protected Exchange config out of OperationRun context/logs/summaries/customer output. - Store raw structured provider item only in evidence storage. - Add sentinel tests for credential, token, stdout/stderr, transcript, normalizer preview, hash preview, and protected connector/config fields. ## Implementation Phases ### Phase 0 - Preflight - Capture branch, HEAD, and `git status --short`. - Confirm Spec 435 PASS/merge-ready and prerequisite proof from Specs 430-435. - Confirm no UI/routes/jobs/schedules/listeners/migration/tenant_id scope. ### Phase 1 - Adapter Integration Update - Wire Exchange adapter to Spec 435 structured envelope. - Wire Exchange adapter to Spec 435 target normalizers. - Wire Exchange adapter to Spec 435 hash input builder. - Remove/avoid generic/Teams comparable normalizer path for Exchange evidence. - Preserve Graph/generic capture path. ### Phase 2 - Evidence Persistence - Use Coverage v2 evidence writer. - Persist raw structured provider payload in evidence storage only. - Persist normalized target payload. - Persist payload hash. - Link OperationRun. - Preserve append-only behavior. - Update latest pointer according to repo pattern. ### Phase 3 - Target Evidence Promotion - Implement `transportRule` capture. - Implement `remoteDomain` capture with stable identity only. - Implement `inboundConnector` capture with stable identity/redaction only. - Keep blocked states explicit. ### Phase 4 - Blocking / Empty / Failure Semantics - Block readiness failures. - Block unsupported provider capability. - Block output failures. - Block unsafe identity. - Preserve empty collection no-evidence policy. - Add exact blocker outcomes and prove persisted evidence `capture_outcome` values stay within existing repo-allowed values. ### Phase 5 - Redaction / No-Promotion - Prove OperationRun context sanitized. - Prove raw payload only in evidence storage. - Prove content-backed-only coverage. - Prove no UI/jobs/schedules/listeners/customer output. ### Phase 6 - Regression / Report - Run focused tests and regressions. - Run Pint. - Run `git diff --check`. - Complete implementation report. ## Rollout Considerations - Staging/production deployment impact: none beyond code/test deployment. - No env vars, migrations, queues, scheduler, storage, asset build, reverse proxy, or Dokploy change planned. - Rollback is reverting the adapter/test changes and the Spec 436 artifacts. ## Stop Conditions Stop and amend/split if implementation needs: - UI, routes, Filament, Livewire, assets, global search, provider registration, reports, Review Packs, customer output, jobs, schedules, listeners, console commands, or browser proof. - migration/schema changes, new evidence table, `tenant_id`, new OperationRun type, or new persisted outcome/summary key. - target expansion beyond the three included types. - compare/render/certification/restore/customer claim. - Graph gateway fallback or fake Graph endpoints. - durable collection-level empty proof.