TenantAtlas/specs/434-exchange-evidence-capture-adapter-content-only-guard/implementation-report.md
ahmido a23131cdbc feat: add Exchange evidence capture adapter guard (#501)
Summary: add Spec 434 Exchange PowerShell evidence capture adapter and prerequisite/identity/content-only guards; cap Exchange evidence at content_backed while preserving Graph capture. Validation: php artisan test --filter=Spec434 --compact; ./vendor/bin/pint --dirty --test; git diff --cached --check. Product Surface: N/A - no rendered UI surface changed; no deployment impact.
Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #501
2026-07-08 10:46:05 +00:00

9.1 KiB

Implementation Report: Exchange Evidence Capture Adapter and Content-Only Guard

Date: 2026-07-08

Preflight

  • Branch: 434-exchange-evidence-capture-adapter-content-only-guard
  • HEAD: a6f45299 feat: add Exchange credential permission evidence readiness (#500)
  • Initial dirty state: active Spec 434 package was untracked; no completed Specs 429-433 were edited.
  • Final dirty state: intended Spec 434 runtime/test files plus active Spec 434 package only.
  • Activated gates/skills: spec-kit-implementation-loop, pest-testing, spec readiness, workspace scope safety, OperationRun truth, evidence anchor contract, provider freshness semantics, Product Surface gate, customer output gate, TCM cutover guard, RBAC/action safety.
  • Hard-gate stop conditions: none.

Close-Out Dirty State

  • git status --short --branch:
    • ## 434-exchange-evidence-capture-adapter-content-only-guard
    • M apps/platform/app/Services/TenantConfiguration/CoverageEvidenceWriter.php
    • ?? apps/platform/app/Services/TenantConfiguration/ExchangePowerShellCaptureEligibilityGate.php
    • ?? apps/platform/app/Services/TenantConfiguration/ExchangePowerShellContentOnlyEvidenceGuard.php
    • ?? apps/platform/app/Services/TenantConfiguration/ExchangePowerShellEvidenceCaptureAdapter.php
    • ?? apps/platform/app/Services/TenantConfiguration/ExchangePowerShellIdentityEvidenceGate.php
    • ?? apps/platform/tests/Feature/TenantConfiguration/Spec434ExchangeEvidenceCaptureAdapterTest.php
    • ?? specs/434-exchange-evidence-capture-adapter-content-only-guard/
  • git diff --name-only: apps/platform/app/Services/TenantConfiguration/CoverageEvidenceWriter.php
  • Untracked Spec 434 package files are expanded in the Files Changed section below.

Completed-Spec Context

  • Specs 429-433 were treated as read-only context.
  • Spec 433 implementation report state: PASS WITH CONDITIONS; the remaining condition was a broader existing provider readiness card and did not block the Spec 434 adapter.
  • Spec 434 keeps the existing tenant_configuration.capture OperationRun as the only evidence-owning operation type for this slice.

Runtime Changes

  • Added ExchangePowerShellEvidenceCaptureAdapter.
  • Added ExchangePowerShellCaptureEligibilityGate.
  • Added ExchangePowerShellIdentityEvidenceGate.
  • Added ExchangePowerShellContentOnlyEvidenceGuard.
  • Extended CoverageEvidenceWriter::append() with an optional maximum coverage level cap.

Boundary Proof

  • Included capture targets only: transportRule, remoteDomain, inboundConnector.
  • Unsupported Exchange/Teams targets block before resource/evidence append.
  • Same-scope checks cover workspace, managed environment, provider connection, and OperationRun.context.target_scope.
  • Wrong operation type blocks before evidence append.
  • Spec 433 combined readiness is required.
  • ProviderCapabilityEvaluator must return Supported for exchange_powershell_invoke.
  • Spec 432 runner results are accepted only as successful list collections with output_state of structured_collection or empty_collection.
  • Spec 430 verified pending command contracts are required.
  • Adapter-owned endpoints use exchange_online_powershell_rest:<CommandName>, not Graph endpoints.
  • No ProviderGateway, generic Graph list path, fake Graph endpoint, fake_empty_success, or fake captured outcome is used.

Evidence And Identity

  • Identity hard-stop runs before resource upsert/evidence append.
  • Blocks missing stable ID, display-name-only identity, derived-only remote domain identity, duplicate stable identity, unsupported identity, and existing same-scope identity conflict.
  • Empty collections write zero summary counts only and create no resource/evidence rows.
  • Non-empty captures store internal content-backed evidence only.
  • Exchange adapter calls CoverageEvidenceWriter with a content_backed maximum and verifies evidence state, coverage level, and latest claim state after write.
  • The path does not promote to comparable, renderable, certified, restore-ready, or customer-claimable states.

Product Surface

  • Product Surface Impact: none.
  • UI Surface Impact: none.
  • No legacy posture exception required.
  • Page archetype, surface budgets, Technical Annex/deep-link demotion, canonical status vocabulary: N/A - no rendered UI surface changed.
  • Product Surface exceptions: none.
  • Browser proof: N/A - no rendered UI surface changed.
  • Human Product Sanity: N/A - no rendered UI surface changed.
  • Visible complexity outcome: neutral.

Filament / Livewire / Assets

  • Livewire v4 compliance unchanged; installed Livewire is v4.1.4.
  • Provider registration unchanged under apps/platform/bootstrap/providers.php.
  • Global search unchanged; no resources were added or modified.
  • Destructive/high-impact actions: none.
  • Asset strategy: none; no Filament assets added and no deploy-time filament:assets requirement introduced.

No-Scope-Expansion Proof

  • No UI, routes, navigation, Filament pages/resources/widgets, Livewire components, Blade views, assets, jobs, schedules, listeners, customer output, Review Pack, PDF, restore, certification, compare/render surface, migration, Exchange-specific evidence table, tenant_id, legacy shim, fallback reader, dual write, or Exchange mini-platform added.
  • Laravel 12 / PHP 8.4 / PostgreSQL / Pest 4 compatibility unchanged.
  • Deployment impact: none; no env vars, migrations, queues, cron, storage, assets, or Dokploy runtime changes.

Validation

  • cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec434 --compact: failed before results with process signal 9; fallback used per task T053.
  • cd apps/platform && php artisan test --filter=Spec434 --compact: PASS, 25 tests / 154 assertions.
  • cd apps/platform && php artisan test --filter=Spec433 --compact: PASS, 48 tests / 211 assertions.
  • cd apps/platform && php artisan test --filter='Spec432|Spec431|Spec430' --compact: PASS, 173 tests / 1357 assertions.
  • cd apps/platform && php artisan test --filter='Spec415|Spec417|Spec419|Spec420|Spec426|Spec427' --compact: PASS, 202 tests / 2137 assertions, 8 existing PostgreSQL-specific skips.
  • cd apps/platform && php artisan test --filter='ProviderCapabilityRegistryTest|ProviderCapabilityEvaluationTest' --compact: PASS, 7 tests / 30 assertions.
  • cd apps/platform && ./vendor/bin/pint --dirty --test: PASS, 6 files.
  • git diff --check: PASS for tracked changes. Close-out review note: because the new Spec 434 package and Exchange adapter/test files remain untracked in the current dirty state, git diff --check does not validate their content until they are staged/tracked; git status --short is the source of truth for the untracked file list.

Post-Implementation Analysis

  • Iteration 1 findings fixed:
    • Captured maximumCoverageLevel into the writer transaction closure.
    • Treated empty accepted collections as zero-item captured results, not unsupported failures.
    • Reused CoverageResourceIdentityEvaluator in the pre-writer identity gate to catch existing unsafe same-scope conflicts.
    • Fixed Pest dataset shape and Pint formatting.
  • Remaining in-scope findings: none.
  • Residual risk: the adapter is internal and not wired to a job/start surface in Spec 434; a future spec must explicitly design invocation-to-capture orchestration if needed.
  • Close-out hotfix corrections:
    • Requirements checklist synchronized to implementation evidence.
    • Changed-files inventory corrected to include all active Spec 434 artifacts in the dirty state.
    • Identity proof wording corrected: unsafe identity uses adapter code order plus zero resource/evidence assertions, not a literal writer spy.
    • Static validation wording corrected so git diff --check is not claimed to validate untracked file content.

Files Changed

  • apps/platform/app/Services/TenantConfiguration/CoverageEvidenceWriter.php
  • apps/platform/app/Services/TenantConfiguration/ExchangePowerShellCaptureEligibilityGate.php
  • apps/platform/app/Services/TenantConfiguration/ExchangePowerShellContentOnlyEvidenceGuard.php
  • apps/platform/app/Services/TenantConfiguration/ExchangePowerShellEvidenceCaptureAdapter.php
  • apps/platform/app/Services/TenantConfiguration/ExchangePowerShellIdentityEvidenceGate.php
  • apps/platform/tests/Feature/TenantConfiguration/Spec434ExchangeEvidenceCaptureAdapterTest.php
  • specs/434-exchange-evidence-capture-adapter-content-only-guard/spec.md
  • specs/434-exchange-evidence-capture-adapter-content-only-guard/plan.md
  • specs/434-exchange-evidence-capture-adapter-content-only-guard/tasks.md
  • specs/434-exchange-evidence-capture-adapter-content-only-guard/checklists/requirements.md
  • specs/434-exchange-evidence-capture-adapter-content-only-guard/implementation-report.md

Merge Readiness Gate

Status: PASS. Merge-ready: yes.

Manual review prompt:

Review Spec 434 for backend-only Exchange PowerShell evidence capture. Focus on the new adapter and gates, the optional writer coverage cap, same-scope/OperationRun truth, identity hard-stop behavior, empty collection behavior, and proof that no UI, jobs, routes, migrations, Graph fallback, customer output, restore/certification/compare/render path, mini-platform, or tenant_id ownership truth was introduced.