TenantAtlas/specs/434-exchange-evidence-capture-adapter-content-only-guard/implementation-report.md
Ahmed Darrazi 6a6d9173e8
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m14s
feat: add Exchange evidence capture adapter guard
2026-07-08 12:38:38 +02:00

137 lines
9.1 KiB
Markdown

# 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.