TenantAtlas/specs/434-exchange-evidence-capture-adapter-content-only-guard/tasks.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

14 KiB

Tasks: Exchange Evidence Capture Adapter and Content-Only Guard

Input: Design documents from specs/434-exchange-evidence-capture-adapter-content-only-guard/ Prerequisites: spec.md, plan.md, checklists/requirements.md

Implementation Mode: backend adapter/guard implementation only. No UI, routes, jobs, schedules, listeners, migrations, customer output, compare/render, certification, restore, or tenant_id ownership truth unless the spec is amended first.

Implementation Note (2026-07-08): T007-T021 were covered by apps/platform/tests/Feature/TenantConfiguration/Spec434ExchangeEvidenceCaptureAdapterTest.php rather than split into separate Unit files because the adapter boundary, unsafe-identity zero resource/evidence assertions, OperationRun summary-count updates, same-scope checks, and evidence/resource absence are DB-backed behavior. The file keeps fixtures local and also exercises direct identity-gate paths for existing conflict and unsupported-identity states. No literal writer spy is used; writer non-reachability is proven by adapter code order plus zero resource/evidence database assertions.

Test Governance Checklist

  • Lane assignment is named as Unit/Feature fast-feedback/confidence and is the narrowest sufficient proof.
  • New or changed tests stay in the smallest honest family; no browser or heavy-governance family is added accidentally.
  • Shared helpers, factories, seeds, fixtures, and context defaults stay cheap by default; Spec 434 fixtures remain local.
  • Planned validation commands cover adapter/guard behavior without pulling in unrelated lane cost.
  • Browser proof is explicitly N/A - no rendered UI surface changed.
  • Human Product Sanity and Product Surface implementation-report close-out are N/A - no rendered UI surface changed.
  • Any migration, UI, customer-output, or durable empty-collection proof need is escalated to spec amendment or follow-up spec.

Phase 1: Preflight

Purpose: Lock scope, repo truth, and completed-spec guardrails before runtime work.

  • T001 Capture current branch, HEAD, and git status --short in specs/434-exchange-evidence-capture-adapter-content-only-guard/implementation-report.md.
  • T002 Confirm Specs 429-433 are completed or implementation-closed read-only context and are not edited.
  • T003 Confirm Spec 433 implementation report is PASS WITH CONDITIONS with no merge-blocking adapter, readiness, redaction, no-promotion, or no-UI findings.
  • T004 Confirm no existing specs/434-* package is overwritten and this package remains the only active Spec 434 target.
  • T005 Confirm implementation diff starts with no runtime UI, route, job, schedule, listener, migration, customer-output, report, Review Pack, PDF, restore, certification, compare/render, or tenant_id scope.
  • T006 Confirm tenant_configuration.capture is the only evidence-owning OperationRun type for this slice.

Phase 2: Tests First - Adapter and Eligibility

Purpose: Define expected adapter boundaries before implementation.

  • T007 [P] Add feature-backed tests in apps/platform/tests/Feature/TenantConfiguration/Spec434ExchangeEvidenceCaptureAdapterTest.php proving the adapter accepts only transportRule, remoteDomain, and inboundConnector.
  • T008 [P] Add feature-backed tests proving wrong OperationRun type, missing OperationRun, wrong workspace, wrong managed environment, and wrong provider connection block before evidence append.
  • T009 [P] Add feature-backed tests proving missing Spec 433 readiness, exchange_powershell_invoke provider capability status other than Supported, missing Spec 432 runner boundary, invalid ExchangePowerShellInvocationResult shape, and missing Spec 430 verified command contract block before evidence append.
  • T010 [P] Add tests proving Exchange capture does not call ProviderGateway or the generic Graph list path.
  • T011 [P] Add tests proving no fake Graph endpoint, fake captured outcome, or fake_empty_success is used for Exchange eligibility, and persisted outcomes reuse existing CaptureOutcome values only.

Phase 3: Tests First - Identity and Content Guard

Purpose: Prove unsafe evidence cannot be appended or over-promoted.

  • T012 [P] Add feature-backed tests in apps/platform/tests/Feature/TenantConfiguration/Spec434ExchangeEvidenceCaptureAdapterTest.php proving identity conflict blocks before resource upsert/evidence append.
  • T013 [P] Add feature-backed tests proving missing stable external ID, unsupported identity, duplicate identity, and display-name-only identity block by default.
  • T014 [P] Prove unsafe identity does not reach evidence append by adapter code order plus zero resource/evidence assertions; no literal writer spy is used.
  • T015 [P] Add feature-backed tests in apps/platform/tests/Feature/TenantConfiguration/Spec434ExchangeEvidenceCaptureAdapterTest.php proving Exchange adapter writes cannot exceed content_backed.
  • T016 [P] Add tests proving comparable, renderable, certified, restore-ready, and customer-claimable promotion does not occur through the Spec 434 path.

Phase 4: Tests First - Empty Collection, Redaction, and No Product Surface

Purpose: Prove zero-item and redaction behavior before implementation.

  • T017 [P] Add feature-backed tests in apps/platform/tests/Feature/TenantConfiguration/Spec434ExchangeEvidenceCaptureAdapterTest.php proving empty collections create no resource row and no evidence row.
  • T018 [P] Add tests proving empty collections produce only safe flat numeric zero-item summary counts using existing summary keys.
  • T019 [P] Add tests proving OperationRun context/messages/summary counts contain no raw payload, stdout, stderr, serialized Exchange object, credential material, token, or provider response body.
  • T020 [P] Add static guard assertions in apps/platform/tests/Feature/TenantConfiguration/Spec434ExchangeEvidenceCaptureAdapterTest.php proving no new routes, Filament pages/resources/widgets, Livewire components, Blade views, navigation, assets, global search resources, jobs, schedules, listeners, customer-output code, or migrations are introduced.
  • T021 [P] Add static guard assertions proving no tenant_id, Exchange-specific evidence table, legacy shim, fallback reader, dual write, or Exchange mini-platform is introduced.

Phase 5: Adapter Boundary Implementation

Purpose: Add the narrow trusted Exchange adapter.

  • T022 Create apps/platform/app/Services/TenantConfiguration/ExchangePowerShellEvidenceCaptureAdapter.php or repo-canonical equivalent.
  • T023 Implement same-scope validation for workspace, managed environment, provider connection, and tenant_configuration.capture OperationRun.
  • T024 Implement target allowlist for transportRule, remoteDomain, and inboundConnector.
  • T025 Implement dependency on Spec 433 combined readiness, ProviderCapabilityEvaluator exchange_powershell_invoke status Supported, and Spec 432 accepted ExchangePowerShellInvocationResult output boundary.
  • T026 Implement dependency on verified Spec 430 command contract metadata.
  • T027 Ensure adapter is internal/trusted only and exposes no route, UI action, command, schedule, listener, or public trigger.

Phase 6: Capture Eligibility and Source Contract Semantics

Purpose: Keep Exchange capture honest without pretending it is Graph capture.

  • T028 Create apps/platform/app/Services/TenantConfiguration/ExchangePowerShellCaptureEligibilityGate.php or repo-canonical equivalent.
  • T029 Represent Exchange capture eligibility without fake Graph source_endpoint or fake Captured source contract outcome.
  • T030 Preserve CoverageSourceContractResolver Graph behavior and add only bounded Exchange-specific eligibility metadata where needed.
  • T031 Ensure transportRule, remoteDomain, and inboundConnector remain pending full content-backed promotion until Spec 435 or equivalent.
  • T032 Map safe command contract metadata, accepted runner-result metadata, response shape metadata, redaction metadata, and normalization handoff into sanitized internal context without storing raw ExchangePowerShellInvocationResult::collection outside the evidence path.

Phase 7: Identity Hard-Stop Implementation

Purpose: Stop unsafe identity before any evidence append.

  • T033 Create apps/platform/app/Services/TenantConfiguration/ExchangePowerShellIdentityEvidenceGate.php or repo-canonical equivalent.
  • T034 Evaluate identity before calling CoverageEvidenceWriter.
  • T035 Block identity conflict, missing stable external ID, unsupported identity, duplicate identity, and display-name-only identity by default.
  • T036 Return only Spec 434 allowlisted sanitized blocker outcomes without raw payload or provider output.
  • T037 Ensure unsafe identity creates no TenantConfigurationResourceEvidence row.

Phase 8: Content-Only Guard Implementation

Purpose: Prevent accidental promotion beyond internal content-backed evidence.

  • T038 Create apps/platform/app/Services/TenantConfiguration/ExchangePowerShellContentOnlyEvidenceGuard.php or repo-canonical equivalent.
  • T039 Add a max-coverage-level guard for the Exchange adapter path so stored coverage is no higher than content_backed.
  • T040 Adjust CoverageEvidenceWriter or call-site options narrowly enough that existing Graph capture behavior remains unchanged.
  • T041 Ensure comparable, renderable, certified, restore-ready, and customer-claimable state cannot be set through the Exchange adapter path.
  • T042 Ensure no new customer-visible status vocabulary or Product Surface runtime framework is introduced.

Phase 9: Empty Collection and Redaction Implementation

Purpose: Keep zero-item and sensitive-output behavior safe.

  • T043 Implement empty collection handling as exchange_capture_empty_collection or repo-canonical equivalent and safe summary counts only.
  • T044 Ensure empty collections create no fake TenantConfigurationResource and no fake TenantConfigurationResourceEvidence.
  • T045 Ensure durable collection-level empty proof is not implemented in Spec 434.
  • T046 Sanitize OperationRun context and failure/outcome mapping so only Spec 434 allowlisted internal codes, existing CaptureOutcome values, existing ProviderReasonCodes or ext.* reason codes, and no raw stdout/stderr, serialized Exchange objects, credential material, tokens, or provider response bodies are present.
  • T047 Use existing redaction/evidence storage policy for non-empty guarded fixture evidence only.

Phase 10: Regression Coverage

Purpose: Prove adjacent completed behavior remains intact.

  • T048 Run focused Spec 434 tests: cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec434 --compact.
  • T049 Run Spec 433 readiness regression: cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec433 --compact.
  • T050 Run Spec 432/431/430 regression: cd apps/platform && ./vendor/bin/sail artisan test --filter='Spec432|Spec431|Spec430' --compact.
  • T051 Run Coverage v2/generic capture/identity regression: cd apps/platform && ./vendor/bin/sail artisan test --filter='Spec415|Spec417|Spec419|Spec420|Spec426|Spec427' --compact.
  • T052 Run provider capability regression: cd apps/platform && ./vendor/bin/sail artisan test --filter='ProviderCapabilityRegistryTest|ProviderCapabilityEvaluationTest' --compact.
  • T053 If Sail is unavailable, document the failure and use the repo's non-Docker fallback cd apps/platform && php artisan test ... for the same focused filters.

Phase 11: Final Validation and Close-Out

Purpose: Finish the implementation report and review proof.

  • T054 Run cd apps/platform && ./vendor/bin/pint --dirty --test.
  • T055 Run git diff --check.
  • T056 Run git status --short and confirm only active Spec 434 and intended runtime/test files changed.
  • T057 Create specs/434-exchange-evidence-capture-adapter-content-only-guard/implementation-report.md.
  • T058 Record branch, HEAD, dirty state before/after, files changed, and completed-spec read-only proof.
  • T059 Record Spec 433 prerequisite proof and any PASS WITH CONDITIONS handling.
  • T060 Record OperationRun decision: tenant_configuration.capture, no new OperationRun type, existing summary keys only.
  • T061 Record adapter boundary proof and generic Graph capture boundary proof.
  • T062 Record capture eligibility, provider-capability gate, accepted runner-result gate, outcome/failure-code allowlist, identity hard-stop, content-only writer guard, empty collection policy, and redaction proof.
  • T063 Record no compare/render/certification/restore/customer claim, no UI/routes/jobs/schedules/listeners, no migration, no Exchange-specific table, no tenant_id, no legacy shim, no fallback reader, and no mini-platform proof.
  • T064 Record tests run, browser N/A - no rendered UI surface changed, Laravel 12/PHP 8.4/PostgreSQL/Pest 4 compatibility unchanged, Livewire v4 compliance unchanged, provider registration unchanged under apps/platform/bootstrap/providers.php, global search unchanged, destructive/high-impact actions none, asset strategy none, deployment impact none, visible complexity neutral, and deferred work.

Dependencies

  • Phase 1 must complete before runtime work.
  • Phases 2-4 tests should be created before implementation where practical.
  • Phase 5 adapter boundary precedes Phase 6 eligibility and Phase 7 identity wiring.
  • Phase 8 content-only guard must be complete before non-empty fixture evidence can be accepted.
  • Phase 9 empty collection/redaction must be complete before final regression.
  • Phase 11 closes only after all required validation is documented.

Stop Conditions

Stop and amend or split the spec if implementation needs any of the following:

  • new OperationRun type;
  • migration or durable collection-proof model;
  • UI, route, navigation, Filament, Livewire, browser, asset, or global search changes;
  • job, schedule, listener, console trigger, or public start surface;
  • live Exchange provider calls for validation;
  • compare/render/certification/restore/customer output;
  • Exchange-specific evidence table;
  • tenant_id ownership truth;
  • legacy shim, fallback reader, dual write, or Coverage v1 bridge.