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
37 KiB
Feature Specification: Exchange Evidence Capture Adapter and Content-Only Guard
Feature Branch: 434-exchange-evidence-capture-adapter-content-only-guard
Created: 2026-07-08
Status: Draft
Input: User-provided draft Spec 434 - Exchange Evidence Capture Adapter & Content-Only Guard.
Preparation Selection
- Selected candidate: Spec 434 - Exchange Evidence Capture Adapter and Content-Only Guard.
- Source location: User-provided attachment
/Users/ahmeddarrazi/.codex/attachments/0d15249e-465b-40bd-b2c6-307e6c0f895a/pasted-text.txt. - Why selected: The user supplied a direct P0 draft and current repo truth has no existing
specs/434-*package. Specs 429-433 already establish the Exchange PowerShell sequence, and Spec 433 explicitly leaves content-backed Exchange evidence capture/promotion to Spec 434 or later. The draft correctly narrows the next slice from full evidence promotion to the adapter and guard infrastructure required before promotion can be honest. - Roadmap relationship: Continues the Coverage v2 / Microsoft 365 / Exchange sequence after Specs 429-433. It prepares Spec 435-style target evidence promotion by creating a safe Exchange capture adapter path and preventing unsafe evidence append or over-promotion.
- Close alternatives deferred: The older "Exchange Content-Backed Evidence Promotion Slice 1" is deferred because current repo truth still needs adapter, identity, and content-only guard work first. Exchange comparable/renderable promotion, certification, restore, customer output, Teams PowerShell support, broader Exchange target types, and M365 claim guard remain follow-up candidates.
- Completed-spec guardrail result: Specs 429-433 are completed or implementation-closed context only and were not modified. Spec 433 records PASS WITH CONDITIONS; the condition concerns an existing broader provider-readiness card, while Exchange-specific capability slots and safety checks are canonical/redacted. That condition is not merge-blocking for this adapter-only prep, but implementation must carry it forward and must not create new UI or customer claims. No existing Spec 434 package or branch was found.
- Smallest viable implementation slice: Build an internal trusted Exchange PowerShell capture adapter boundary that accepts only
transportRule,remoteDomain, andinboundConnector; reusestenant_configuration.capture; consumes Spec 433 readiness, Spec 432 runner boundary, and Spec 430 verified command contracts; hard-stops unsafe identity before evidence append; limits the Exchange path tocontent_backed; records safe zero-item outcomes without fake evidence; and proves generic Graph capture remains unchanged. - Feature description fed into Spec Kit: Prepare an internal Exchange PowerShell evidence capture adapter and content-only evidence guard for
transportRule,remoteDomain, andinboundConnector, reusingtenant_configuration.capture, requiring existing readiness and runner gates, blocking unsafe identity before evidence append, preventing promotion beyondcontent_backed, keeping empty collections from becoming fake evidence, preserving sanitized OperationRun context, and adding no UI, routes, jobs, schedules, listeners, migrations, customer claims, restore, compare/render, certification, ortenant_idownership truth.
Activated Skills and Gates
spec-kit-next-best-prep: selected because this is a preparation-only Spec Kit request.- TenantPilot repo skills used as planning gates: spec readiness, workspace-scope safety, RBAC/action safety, OperationRun truth, evidence-anchor contract, provider freshness semantics, Product Surface gate, customer-output gate, and temporary TCM cutover guard.
- Hard-gate stop conditions at preparation time: none. Runtime implementation must stop if it introduces unscoped evidence, raw payload leakage, direct OperationRun status/outcome writes, unsafe provider readiness, UI/customer output,
tenant_idownership truth, legacy shims, fallback readers, or over-promotion beyondcontent_backed.
Spec Candidate Check (mandatory - SPEC-GATE-001)
- Problem: TenantPilot has verified Exchange PowerShell contracts, invocation gates, production runner safety, and credential/permission readiness, but it does not yet have a safe evidence capture adapter path from Exchange runner output into Coverage v2 evidence storage.
- Today's failure: A later implementation could treat Exchange command contracts as Graph contracts, append evidence after unsafe identity, create fake empty evidence, leak raw PowerShell output into OperationRun context, or let
CoverageEvidenceWriterpromote Exchange evidence to renderable/comparable/certified/customer-ready states before target-specific promotion is proven. - User-visible improvement: Operators and reviewers get an honest internal safety boundary: Exchange capture infrastructure may produce only guarded internal content-backed fixture evidence, or it blocks with safe reasons. It does not create customer claims, UI readiness, compare/render support, restore readiness, or certification.
- Smallest enterprise-capable version: Add a trusted internal adapter and narrowly scoped guards around existing Coverage v2 resource/evidence paths. Do not add a new OperationRun type, schema, customer output, product surface, trigger, or Exchange mini-platform.
- Explicit non-goals: No full content-backed promotion for
transportRule,remoteDomain, orinboundConnector; no live Exchange provider calls in tests; no arbitrary PowerShell; no compare/render/certification/restore/customer claim; no UI/routes/navigation/Filament/Livewire/assets/global search; no jobs/schedules/listeners/triggers; no Teams; no Exchange Admin API; no broader Exchange targets; no Exchange-specific evidence tables; notenant_id; no legacy shim; no fallback reader. - Permanent complexity imported: New internal service/guard classes or repo-canonical equivalents, focused unit/feature tests, and possibly one provider-neutral eligibility representation. No new persisted entity, table, customer-visible vocabulary, Product Surface runtime framework, or OperationRun type.
- Why now: Spec 433 closed the credential/permission readiness prerequisite. The next safe step is to bridge Exchange runner output into Coverage v2 without overclaiming evidence, identity, product readiness, or customer proof.
- Why not local: A local patch inside the generic Graph capture service or writer would either make Exchange look Graph-shaped or hide security-critical guard logic inside an existing path. The adapter boundary must be explicit and testable so future target promotion can stay small and safe.
- Approval class: Core Enterprise.
- Red flags triggered: New abstraction and limited outcome vocabulary. Defense: the abstraction is security/evidence-boundary critical and replaces an unsafe implicit bridge; outcome labels change blocking behavior and test proof rather than adding presentation taxonomy.
- Score: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 1 | Wiederverwendung: 2 | Gesamt: 10/12
- Decision: approve as a narrow backend safety prerequisite for later Exchange content-backed evidence promotion.
Spec Scope Fields (mandatory)
- Scope: workspace + managed-environment + provider-connection scoped internal evidence capture path.
- Primary Routes: N/A - no route, page, navigation, panel, action, report, download, browser-rendered surface, or customer surface changes.
- Data Ownership: Existing Coverage v2 ownership remains
workspace_id,managed_environment_id, andprovider_connection_id.tenant_configuration.captureis the evidence-owning OperationRun. Notenant_idownership truth and no Exchange-specific evidence table. - RBAC: No new user-facing action is added. The internal adapter must only run inside trusted application flow after existing capture operation authorization/scope has already established workspace, managed environment, and provider connection entitlement. Any future start surface must be a separate or amended spec.
For canonical-view specs:
- Default filter behavior when tenant-context is active: N/A - no canonical route or rendered query change.
- Explicit entitlement checks preventing cross-tenant leakage: Adapter and writer path must reject mismatched
workspace_id,managed_environment_id, orprovider_connection_idbefore capture, identity evaluation, or evidence append.
No Legacy / No Backward Compatibility Constraint (mandatory)
TenantPilot is pre-production unless this spec explicitly records a compatibility exception.
- Compatibility posture: canonical addition only.
- Legacy aliases, fallback readers, hidden routes, duplicate UI, old labels, or historical fixtures kept?: no.
- Why clean replacement is safe now: Exchange evidence capture is not shipped as customer-facing proof. Unsafe or unproven states must block rather than be bridged through compatibility behavior.
UI Surface Impact (mandatory - UI-COV-001)
Does this spec add, remove, rename, or materially change any reachable UI surface?
- No UI surface impact
- Existing page changed
- New page/route added
- Navigation changed
- Filament panel/provider surface changed
- New modal/drawer/wizard/action added
- New table/form/state added
- Customer-facing surface changed
- Dangerous action changed
- Status/evidence/review presentation changed
- Workspace/environment context presentation changed
No-impact rationale: Spec 434 is backend adapter and guard infrastructure only. It must not edit runtime UI files, route files, Filament resources/pages/widgets, Livewire components, navigation, reports, downloads, customer outputs, or browser-rendered diagnostics.
UI/Productization Coverage (mandatory when UI Surface Impact is not "No UI surface impact"; otherwise write N/A - no reachable UI surface impact plus rationale)
N/A - no reachable UI surface impact. Any future UI, readiness status, trigger, customer output, report, Review Pack, or evidence viewer change must amend this spec or use a separate spec and satisfy the Product Surface Contract.
Product Surface Impact (mandatory for UI-affecting specs; otherwise write N/A - no rendered product surface changed plus rationale)
Reference: docs/product/standards/product-surface-contract.md.
- Product Surface Contract applies?: no - no rendered product surface changes.
- Page archetype: N/A.
- Primary user question: N/A.
- Primary action: N/A.
- Surface budget result: N/A.
- Technical Annex / deep-link demotion: N/A for rendered UI. OperationRun context, raw evidence, source keys, command metadata, provider diagnostics, stdout/stderr, payloads, and logs must remain internal and must not become default product content.
- Canonical status vocabulary: N/A for UI.
- Visible complexity impact: neutral; no visible surface changes.
- Product Surface exceptions: none.
Browser Verification Plan (mandatory)
- Browser proof required?: no.
- No-browser rationale:
N/A - no rendered UI surface changed. - Focused path when required: N/A.
- Primary interaction to execute: N/A.
- Console, Livewire, Filament, network, and 500-error checks: N/A.
- Full-suite failure triage: N/A.
Human Product Sanity Check (mandatory)
- Required?: no.
- No-human-sanity rationale: N/A - no product surface changed.
- Reviewer questions: N/A.
- Planned result location: N/A.
Product Surface Merge Gate Checklist (mandatory)
- No-legacy posture or approved exception recorded.
- Product Surface Impact is completed or
N/Ais justified. - Browser proof is completed or
N/A - no rendered UI surface changedis justified. - Human Product Sanity is completed or not applicable with rationale.
- Product Surface exceptions are documented or
none. - Implementation report will state Livewire v4 compliance, provider registration location, global search posture, destructive/high-impact action posture, asset strategy, tests/browser result, deployment impact, visible complexity outcome, and no completed-spec rewrite assertion.
Cross-Cutting / Shared Pattern Reuse (mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, alerts, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write N/A - no shared interaction family touched)
- Cross-cutting feature?: yes, backend shared evidence/operation/provider infrastructure only.
- Interaction class(es): OperationRun execution truth, Coverage v2 evidence writing, provider readiness, identity evaluation, capture outcome summarization. No operator interaction family or rendered surface changes.
- Systems touched: Existing
GenericContentEvidenceCaptureService,CoverageSourceContractResolver,CoverageResourceUpserter,CoverageEvidenceWriter,ExchangePowerShellCommandContracts,ExchangePowerShellCommandRunner,ExchangePowerShellInvocationResult,ExchangePowerShellProductionRunner,ExchangePowerShellInvocationReadinessEvaluator,ProviderCapabilityEvaluator,OperationSummaryKeys,SummaryCountsNormalizer, andtenantpilotExchange PowerShell config. - Existing pattern(s) to extend: Coverage v2 resource/evidence storage,
tenant_configuration.capture, Spec 430 command contract metadata, Spec 432 runner boundary, Spec 433 combined readiness,exchange_powershell_invokeprovider capability evaluation,OperationSummaryKeys, and sanitized OperationRun context conventions. - Shared contract / presenter / builder / renderer to reuse: No UI presenter/renderer. Reuse existing OperationRun service/lifecycle conventions, Coverage v2 evidence models, provider capability/readiness gates, existing
CaptureOutcomevalues, and generic capture redaction/normalization helpers where safe. - Why the existing shared path is sufficient or insufficient: Existing Graph capture is sufficient for Graph-backed contracts and must remain unchanged. It is insufficient for Exchange PowerShell runner output because Exchange has no Graph endpoint and requires an explicit provider-owned adapter boundary.
- Allowed deviation and why: A provider-owned Exchange adapter and local guard classes are allowed because they protect evidence correctness and avoid Graph-shaped fake contracts. Broad provider frameworks, UI semantics, customer-output frameworks, and Exchange mini-platforms are forbidden.
- Consistency impact: Later target promotion must reuse this adapter/guard path instead of adding a second Exchange evidence path.
- Review focus: Verify no raw provider payload leaks, no over-promotion, no fake empty evidence, no new operation type, and no generic Graph capture regression.
OperationRun UX Impact (mandatory when the feature creates, queues, deduplicates, resumes, blocks, completes, or deep-links to an OperationRun; otherwise write N/A - no OperationRun start or link semantics touched)
- Touches OperationRun start/completion/link UX?: no rendered UX. It touches internal OperationRun type/context requirements for the capture path.
- Shared OperationRun UX contract/layer reused: N/A for UI. Runtime must use existing
tenant_configuration.captureoperation truth and existing OperationRun lifecycle conventions. - Delegated start/completion UX behaviors: N/A - no toast, run link, artifact link, browser event, queued DB notification, or rendered surface.
- Local surface-owned behavior that remains: none.
- Queued DB-notification policy: N/A.
- Terminal notification path: unchanged central lifecycle behavior for
tenant_configuration.capture. - Exception required?: none. If implementation needs a new OperationRun type, queued notification, start surface, or run link behavior, stop and amend/split the spec.
Provider Boundary / Platform Core Check (mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write N/A - no shared provider/platform boundary touched)
- Shared provider/platform boundary touched?: yes.
- Boundary classification: mixed. Exchange PowerShell command execution and response handling are provider-owned. Coverage v2 evidence storage, operation truth, identity safety, and customer-claim boundaries are platform-core.
- Seams affected: source-contract decision/eligibility, capture adapter routing, identity evaluation before evidence append, evidence writer maximum level, OperationRun context and summary counts, provider readiness and
exchange_powershell_invokecapability gates. - Neutral platform terms preserved or introduced: workspace, managed environment, provider connection, operation, resource type, source contract, capture outcome, evidence state, coverage level, identity state, claim state.
- Provider-specific semantics retained and why: Exchange command names and
exchange_online_powershell_restsource surface remain provider-owned metadata because they are required to execute verified Exchange commands safely. - Why this does not deepen provider coupling accidentally: The adapter is bounded to Exchange and must not alter Graph capture, platform-core ownership, generic evidence semantics, product UI vocabulary, or customer output.
- Follow-up path: document-in-feature for bounded Exchange adapter details; follow-up spec for target-specific evidence promotion and any provider-neutral collection-proof model.
UI / Surface Guardrail Impact (mandatory when operator-facing surfaces are changed; otherwise write N/A)
N/A - no operator-facing surface change.
Decision-First Surface Role (mandatory when operator-facing surfaces are changed)
N/A - no operator-facing surface change.
Audience-Aware Disclosure (mandatory when operator-facing surfaces are changed)
N/A - no operator-facing surface change.
UI/UX Surface Classification (mandatory when operator-facing surfaces are changed)
N/A - no operator-facing surface change.
Operator Surface Contract (mandatory when operator-facing surfaces are changed)
N/A - no operator-facing surface change.
Proportionality Review (mandatory when structural complexity is introduced)
- New source of truth?: no. Execution truth remains
OperationRun; evidence truth remains existing Coverage v2 evidence rows. - New persisted entity/table/artifact?: no runtime persistence beyond existing resource/evidence rows. Spec Kit artifacts only.
- New abstraction?: yes, a narrow Exchange evidence capture adapter/guard boundary or repo-canonical equivalents.
- New enum/state/reason family?: possibly limited internal outcome/failure labels; no customer-visible status family.
- New cross-domain UI framework/taxonomy?: no.
- Current operator problem: Preventing false Exchange evidence readiness, customer claims, and unsafe evidence append before Exchange target evidence is proven.
- Existing structure is insufficient because:
GenericContentEvidenceCaptureServiceis Graph-oriented,CoverageResourceUpserterrecords identity state without hard-stopping all append paths, andCoverageEvidenceWritercan promote beyondcontent_backed. - Narrowest correct implementation: Add an Exchange-specific internal adapter and local guards around existing Coverage v2 paths. Do not add a generalized provider capture framework, new operation type, schema, UI, or customer-output layer.
- Ownership cost: Focused service/test ownership in TenantConfiguration. Future target promotion must respect the adapter contract and maintain regression tests.
- Alternative intentionally rejected: Reusing Graph capture with fake endpoints, manually writing evidence rows, adding durable empty-collection schema now, or modifying the writer globally without an Exchange-specific maximum-level guard.
- Release truth: Current-release safety prerequisite for future Exchange content-backed evidence promotion.
Compatibility posture
This feature assumes a pre-production environment. Backward compatibility, legacy aliases, migration shims, historical fixtures, fallback readers, and compatibility-specific tests are out of scope.
Testing / Lane / Runtime Impact (mandatory for runtime behavior changes)
- Test purpose / classification: Unit and Feature. Unit tests for adapter eligibility, identity hard-stop, content-only guard, empty-collection policy, and sanitized result mapping. Feature tests for database/evidence no-promotion, scope enforcement, OperationRun context, and no-product-surface guard scans.
- Validation lane(s): fast-feedback/confidence focused tests; selected regression tests for Specs 415, 417, 419, 420, 426, 427, 430, 431, 432, 433, and provider capability registry. Browser lane is N/A.
- Why this classification and these lanes are sufficient: The change is backend service/evidence behavior. No rendered UI, browser interaction, migration, queue trigger, or customer output is introduced.
- New or expanded test families: focused Spec 434 tests under existing TenantConfiguration/Coverage v2 families.
- Fixture / helper cost impact: Exchange adapter fixtures and fake runner/evidence-writer spies should remain local and cheap. No live provider setup, no browser state, no heavy global provider/workspace defaults.
- Heavy-family visibility / justification: none planned.
- Special surface test profile: N/A - no rendered UI surface changed.
- Standard-native relief or required special coverage: N/A - no Filament/Livewire surface.
- Reviewer handoff: Verify lane fit, no browser requirement, no hidden heavy fixture defaults, no application start surface, and no raw output in run context/log assertions.
- Budget / baseline / trend impact: expected neutral.
- Escalation needed: none if scope remains adapter/guard only; reject-or-split if implementation needs UI, durable empty collection proof, new operation type, schema, customer output, or broad provider framework.
- Active feature PR close-out entry: Guardrail / Exception / Smoke Coverage:
N/A - no rendered UI surface changed. - Planned validation commands:
cd apps/platform && ./vendor/bin/sail artisan test --filter=Spec434 --compactcd apps/platform && ./vendor/bin/sail artisan test --filter='Spec433|Spec432|Spec431|Spec430|Spec415|Spec417|Spec419|Spec420|Spec426|Spec427|ProviderCapabilityRegistryTest|ProviderCapabilityEvaluationTest' --compactcd apps/platform && ./vendor/bin/pint --dirty --testgit diff --check
User Scenarios & Testing (mandatory)
User Story 1 - Safe Exchange Capture Adapter Boundary (Priority: P1)
A platform engineer needs a trusted internal Exchange adapter that can receive verified runner output for the scoped Exchange targets without routing through Graph capture or adding a customer-facing surface.
Why this priority: This is the prerequisite for any later Exchange content-backed evidence promotion.
Independent Test: Unit and feature tests prove only transportRule, remoteDomain, and inboundConnector are accepted, tenant_configuration.capture is required, same-scope provider connection is required, and Graph provider gateway is not called.
Acceptance Scenarios:
- Given a scoped capture run and verified Exchange command contract, When the adapter receives a successful structured collection, Then it evaluates gates before calling the Coverage v2 writer path.
- Given an unsupported canonical type or wrong OperationRun type, When capture is attempted, Then no evidence row is created and a safe blocked outcome is returned.
- Given generic Graph capture tests, When Spec 434 is implemented, Then the existing Graph path still captures Graph-backed contracts unchanged.
User Story 2 - Identity Unsafe Evidence Cannot Be Appended (Priority: P1)
A reviewer needs proof that Exchange evidence cannot be appended when identity is unstable, conflicting, missing, unsupported, or display-name-only.
Why this priority: Evidence without stable identity can create false governance proof and wrong customer claims.
Independent Test: Tests spy on the evidence writer and database to prove unsafe identity blocks before append and produces no resource evidence row.
Acceptance Scenarios:
- Given runner output with missing stable identity, When the adapter evaluates the item, Then the writer is not called and no evidence row exists.
- Given duplicate or conflicting identity, When capture is attempted, Then the adapter returns an identity blocker and stores no payload in OperationRun context.
- Given a later target-specific rule is needed for derived identity, When implementation cannot prove it in Spec 434, Then it remains blocked and is deferred to Spec 435.
User Story 3 - Exchange Capture Cannot Over-Promote Coverage (Priority: P1)
A reviewer needs evidence that the Exchange path can only create content_backed internal evidence and cannot become comparable, renderable, certified, restore-ready, or customer-claimable in this slice.
Why this priority: Current writer behavior can promote to renderable when summary builders match; this spec must prevent accidental overclaiming through the Exchange adapter path.
Independent Test: Tests prove the Exchange adapter path applies a content_backed maximum and persisted evidence/resource state cannot exceed that maximum.
Acceptance Scenarios:
- Given a payload shape that a summary builder could render, When it is written through the Exchange adapter path, Then stored coverage remains
content_backed. - Given adapter fixture evidence, When claim state is evaluated, Then it remains internal/not customer-claimable for this slice.
- Given compare/render/certification/restore/customer output code paths, When Spec 434 is implemented, Then none are added or activated.
User Story 4 - Empty Collections Are Honest Zero-Item Outcomes (Priority: P1)
A platform reviewer needs empty Exchange collections to be represented as zero-item execution outcomes, not fake resource/evidence rows.
Why this priority: Empty collections can be misread as durable evidence unless the product explicitly models collection-level proof, which is out of scope here.
Independent Test: Empty collection tests prove safe summary counts, no resource row, no evidence row, and deferred durable collection proof.
Acceptance Scenarios:
- Given a successful Exchange runner result with zero items, When the adapter handles it, Then OperationRun summary counts record zero items and no resource/evidence row is created.
- Given no durable collection proof model exists, When a reviewer checks the implementation report, Then it states collection-level empty proof is deferred.
Functional Requirements
- FR-434-001: The implementation MUST provide an internal trusted Exchange evidence capture adapter or repo-canonical equivalent.
- FR-434-002: The adapter MUST accept only
transportRule,remoteDomain, andinboundConnectorfor this slice. - FR-434-003: The adapter MUST require an existing
tenant_configuration.captureOperationRun and MUST NOT add a new OperationRun type. - FR-434-004: The adapter MUST reject mismatched workspace, managed environment, or provider connection scope before evidence append.
- FR-434-005: The adapter MUST require Spec 433 combined credential and permission readiness and MUST treat any
ProviderCapabilityEvaluatorresult forexchange_powershell_invokeother thanSupportedas a sanitized blocker before capture proceeds. - FR-434-006: The adapter MUST require the Spec 432 runner boundary and verified structured output before capture proceeds. Accepted runner input is limited to
ExchangePowerShellCommandRunner::run(ExchangePowerShellCommandContract, ExchangePowerShellInvocationContext): ExchangePowerShellInvocationResultwheresuccessfulis true,collectionis a list, and sanitized context identifiesoutput_stateasstructured_collectionorempty_collection. - FR-434-007: The adapter MUST require Spec 430 verified command contracts and MUST NOT fake Graph endpoints or captured outcomes.
- FR-434-008: Exchange runner output MUST NOT route through
ProviderGatewayor the generic Graph list path. - FR-434-009: Identity MUST be evaluated before evidence append, and unsafe identity MUST prevent writer invocation.
- FR-434-010: Identity conflict, missing stable external ID, unsupported identity, duplicate identity, and display-name-only identity MUST block by default unless an existing repo-approved rule explicitly permits the case.
- FR-434-011: Evidence written through the Exchange adapter path MUST be capped at
content_backed. - FR-434-012: The implementation MUST prevent comparable, renderable, certified, restore-ready, and customer-claimable promotion through the Spec 434 path.
- FR-434-013: Empty collections MUST create no fake resource row and no fake evidence row.
- FR-434-014: Empty collections MAY update safe flat numeric summary counts using existing
OperationSummaryKeys. - FR-434-015: OperationRun context, messages, summary counts, logs, and notifications MUST NOT include raw payloads, raw stdout/stderr, serialized Exchange objects, credential material, tokens, or provider response bodies.
- FR-434-016: Raw and normalized payloads, if persisted for non-empty fixture evidence, MUST go only through existing Coverage v2 evidence storage and redaction policy.
- FR-434-017: Generic Graph content capture behavior MUST remain unchanged and covered by regression tests.
- FR-434-018: No migration, Exchange-specific evidence table,
tenant_id, legacy shim, fallback reader, dual write, route, UI, job, schedule, listener, asset, global search behavior, report, Review Pack, PDF output, restore flow, or customer claim may be added by this spec. - FR-434-019: Implementation report MUST record the OperationRun decision, adapter boundary proof, provider-capability proof, accepted runner-result proof, identity hard-stop proof, content-only guard proof, empty collection proof, generic capture regression proof, no-promotion proof, no-product-surface proof, no-tenant-id proof, tests run, and deferred work.
- FR-434-020: Persisted evidence capture outcome MUST reuse existing
CaptureOutcomevalues only.capturedis allowed only for accepted non-empty content-backed fixture evidence;capture_blocked_missing_contract,capture_blocked_permission,capture_blocked_unsupported, andcapture_failedare the only allowed blocked/failure persisted outcomes for this path. Adding a newCaptureOutcomeenum value requires amending this spec. - FR-434-021: Adapter-local outcome/failure codes, if introduced, MUST be limited to
exchange_capture_prerequisite_blocked,exchange_capture_identity_blocked,exchange_capture_content_level_blocked,exchange_capture_empty_collection, andexchange_capture_sanitized_failure. These codes MUST stay internal, sanitized, and behavior-backed: prerequisite blockers prevent writer invocation, identity blockers prevent writer invocation, content-level blockers prevent over-promotion, empty collection creates only safe zero-item summary counts, and sanitized failure fails closed without raw provider data.
Non-Functional Requirements
- NFR-434-001: Adapter behavior must be deterministic and testable with fake runner output; no live Microsoft/Exchange calls are required for validation.
- NFR-434-002: All scope and readiness failures must fail closed with sanitized reason/failure codes.
- NFR-434-003: Summary counts must remain flat numeric values from the existing allowed key set.
- NFR-434-004: Test fixtures must stay local to Spec 434 and must not introduce heavy shared defaults or browser dependencies.
- NFR-434-005: The implementation must remain compatible with Laravel 12, Filament v5, Livewire v4, PHP 8.4, PostgreSQL, and Pest 4 repo conventions.
Out of Scope
- Full content-backed evidence promotion for
transportRule,remoteDomain, orinboundConnector. - Target-specific normalization completeness and durable payload hash finalization for production evidence.
- Durable provider-neutral collection-level empty proof.
- Exchange comparable/renderable promotion.
- Exchange certification, restore readiness, customer output, Review Pack/PDF/report output, or customer-safe claims.
- Live Exchange provider calls in tests or arbitrary PowerShell execution.
- Teams, Exchange Admin API, outbound connectors, accepted domains, organization config, mailbox plans, sharing policies, Security & Compliance targets, or broader M365 coverage.
- UI, routes, navigation, Filament/Livewire components, assets, global search, jobs, schedules, listeners, or external triggers.
Acceptance Criteria
- AC-434-001: A safe internal Exchange capture adapter boundary exists and requires
tenant_configuration.capture. - AC-434-002: Unsupported target types, wrong OperationRun type, wrong scope, missing readiness, missing runner boundary, and missing verified contract all block without evidence rows.
- AC-434-003: Unsafe identity prevents evidence writer invocation and creates no evidence row.
- AC-434-004: Evidence written through the adapter path cannot exceed
content_backed. - AC-434-005: Empty collection results create zero-item summary outcomes only, with no fake resource/evidence rows.
- AC-434-006: OperationRun context and logs remain sanitized.
- AC-434-007: Generic Graph capture regressions pass and prove the existing Graph capture path is unchanged.
- AC-434-008: No UI/product surface/browser path changes exist; browser proof is
N/A - no rendered UI surface changed. - AC-434-009: No migration, no Exchange-specific evidence table, no
tenant_id, no mini-platform, no fallback reader, and no legacy shim are introduced.
Success Criteria
- SC-434-001: Later Exchange target evidence promotion can reuse the adapter/guard path without redefining OperationRun, identity hard-stop, content-only guard, empty collection policy, or generic Graph separation.
- SC-434-002: Reviewers can determine from tests and implementation report that Spec 434 did not create customer-visible Exchange evidence claims.
- SC-434-003: Focused Spec 434 tests and selected regression tests pass without browser or heavy-governance expansion.
Risks
- R-434-001: A too-generic adapter framework could violate proportionality and spread provider-specific semantics into platform core. Mitigation: keep adapter Exchange-owned and narrow.
- R-434-002: Modifying
CoverageEvidenceWriterglobally could regress Graph-backed capture. Mitigation: use a bounded max-level guard and run generic capture regressions. - R-434-003: Empty collection handling could be mistaken as durable evidence. Mitigation: no resource/evidence row; implementation report documents collection-proof deferral.
- R-434-004: Spec 433 PASS WITH CONDITIONS could be misread as full provider readiness. Mitigation: require implementation preflight to re-check Spec 433 condition and fail closed if it affects adapter safety.
Assumptions
- Spec 433 remains implemented with PASS WITH CONDITIONS and no merge-blocking readiness findings for this adapter-only slice.
tenant_configuration.captureremains the canonical evidence-owning operation type.transportRule,remoteDomain, andinboundConnectorcommand contracts remain verified/pending capture through Spec 430/431/432 repo truth.- Existing Coverage v2 resource/evidence tables are sufficient for non-empty internal content-backed fixture evidence.
- Durable collection-level empty proof requires a separate provider-neutral design and is deferred.
Open Questions
None blocking preparation. Implementation must stop and amend this spec if it needs durable empty-collection persistence, a new OperationRun type, schema changes, UI/product surface changes, live provider validation, or customer output.
Follow-up Spec Candidates
- Spec 435 - Exchange Content-Backed Evidence Promotion Slice 1 for
transportRule,remoteDomain, andinboundConnector. - Exchange comparable/renderable promotion after content-backed evidence exists.
- Teams PowerShell adapter contract and evidence support.
- M365 customer output and claim guard after evidence and compare semantics are proven.
- Provider-neutral durable collection-proof evidence model, only if product workflows require empty collection proof.
Candidate Selection Gate
PASS. The selected candidate is directly provided by the user, not covered by an existing active or completed Spec 434 package, follows implemented Specs 429-433, aligns with the Exchange/Teams Coverage v2 roadmap sequence, is narrow enough for a bounded implementation loop, and defers full target promotion plus customer/product surfaces.
Spec Readiness Gate
PASS for preparation. spec.md, plan.md, tasks.md, and checklists/requirements.md define a bounded, testable, no-application-implementation package. Runtime implementation must re-check repo state, Spec 433 conditions, and all hard gates before changing application code.