137 lines
9.1 KiB
Markdown
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.
|