TenantAtlas/specs/426-exchange-teams-core-evidence-identity-readiness/plan.md
ahmido f7d06621a0 feat: implement Exchange Teams evidence identity readiness (#493)
Automated PR for spec 426 exchange teams core evidence identity readiness. Includes service changes and coverage/requirement/spec updates from commit fb4dc20c.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #493
2026-07-03 11:43:11 +00:00

345 lines
30 KiB
Markdown

# Implementation Plan: Spec 426 - Exchange / Teams Core Evidence & Stable Identity Readiness
**Branch**: `426-exchange-teams-core-evidence-identity-readiness` | **Date**: 2026-07-02 | **Spec**: [spec.md](./spec.md)
**Input**: Feature specification from `specs/426-exchange-teams-core-evidence-identity-readiness/spec.md`
## Summary
Prepare Exchange/Teams core evidence and stable identity readiness for later certification without overclaiming source support. Post-review correction found that the initially proposed Graph v1.0 endpoints for `transportRule`, `acceptedDomain`, `appPermissionPolicy`, and `meetingPolicy` are not production-safe source contracts. The implementation must therefore keep those four types fail-closed as missing contracts, prove no provider call/resource/evidence is created for blocked capture, and harden identity strategies for future valid source payloads. The work remains a prerequisite unblocker only. It must not certify Exchange/Teams, introduce restore/apply, activate customer claims, add routes/navigation/dashboards, create Exchange/Teams table families, or introduce `tenant_id`.
## Post-Review Correction
- Remove unverified `mailFlowRule`, `acceptedDomains`, `teamsAppPermissionPolicy`, and `teamsMeetingPolicy` Graph contract entries.
- Keep `transportRule`, `acceptedDomain`, `appPermissionPolicy`, and `meetingPolicy` blocked as `capture_blocked_missing_contract` until a verified repo-canonical provider contract exists.
- Preserve typed normalization/hash/redaction tests as helper proof only; do not claim source-backed evidence or compare/render readiness from fixtures.
- Harden identity strategies so `Identity`/display-name-like values do not become stable identity.
- Final readiness gate for source-backed evidence is `FAIL` by design; no certification follow-up may proceed from this branch.
## Technical Context
**Language/Version**: PHP 8.4, Laravel 12, Filament v5, Livewire v4
**Primary Dependencies**: Existing Coverage v2 Tenant Configuration services: `CoverageSourceContractResolver`, `GraphContractRegistry`, `ProviderGateway`, `GraphClientInterface`, `GenericContentEvidenceCaptureService`, `CoverageResourceUpserter`, `CoverageEvidenceWriter`, `CoverageIdentityStrategyRegistry`, `CanonicalIdentityResolver`, `ExchangeTeamsComparablePayloadNormalizer`, `ExchangeTeamsCoverageComparator`, `ExchangeTeamsRenderableSummaryBuilder`, `ClaimGuard`, `OperationRunService`
**Storage**: PostgreSQL through existing Coverage v2 resource/evidence/supported-scope tables; no new table planned; readiness labels are derived report assertions over existing states, not new persisted booleans/statuses
**Testing**: Pest 4, PHPUnit 12, focused Unit/Feature; Browser only if UI changes
**Validation Lanes**: fast-feedback for unit/feature; browser conditional; Pint dirty; diff check
**Target Platform**: Laravel Sail locally, Dokploy container deployment
**Project Type**: Laravel web monolith under `apps/platform`
**Performance Goals**: Capture remains bounded to four selected resource types, remote work is OperationRun-backed, and compare/render readiness is deterministic over persisted evidence
**Constraints**: no endpoint guessing, no direct HTTP, no provider bypass, no certification, no restore/apply, no customer output, no new route/navigation/dashboard, no `tenant_id`, no v1 compatibility, no completed-spec rewrites
**Scale/Scope**: exactly four mandatory resource types; no optional Exchange/Teams/M365 expansion
## Preparation Preflight Result
- Current branch before Spec Kit creation: `platform-dev`.
- Current branch after Spec Kit creation: `426-exchange-teams-core-evidence-identity-readiness`.
- Current HEAD before creation: `33e496c1 feat: complete spec 425 enta certified compare pack (#492)`.
- Initial dirty state: clean.
- Existing `426-*` spec/branch check: no existing local branch or spec package found before creation.
- Auto-prep queue: `docs/product/spec-candidates.md` currently says no safe automatic next-best-prep target remains. This package is a direct manual promotion from the user-provided candidate.
- Related completed/read-only dependency specs: 414, 415, 417, 418, 419, 420, 422, and 425.
- Source contract gaps confirmed during preparation before implementation:
- `transportRule`: no explicit mapping in `CoverageSourceContractResolver`.
- `acceptedDomain`: was explicitly blocked as `missing_source_contract_mapping` before Spec 426 implementation.
- `appPermissionPolicy`: was explicitly blocked as `missing_source_contract_mapping` before Spec 426 implementation.
- `meetingPolicy`: no explicit mapping in `CoverageSourceContractResolver`.
- Identity strategy gaps confirmed during preparation before implementation:
- No `CoverageIdentityStrategyRegistry` stable strategy for `transportRule`.
- No stable strategy for `acceptedDomain`.
- No stable strategy for `appPermissionPolicy`.
- No stable strategy for `meetingPolicy`.
- Current compare/render evidence:
- `ExchangeTeamsComparablePayloadNormalizer`, `ExchangeTeamsCoverageComparator`, and `ExchangeTeamsRenderableSummaryBuilder` support the four resource types.
- Spec 422 proof is compare/render for content-backed existing/synthetic rows, not live/source-backed capture proof.
- Current capture architecture:
- `GenericContentEvidenceCaptureService` uses `ProviderGateway::listPolicies()` through the repo provider abstraction.
- `CoverageEvidenceWriter` persists raw payload, normalized payload, payload hash, OperationRun link, source metadata, and content-backed evidence state.
- `CoverageResourceUpserter` uses `CanonicalIdentityResolver`.
- Implementation must align source-backed Exchange/Teams payloads with the typed Spec 422 normalizer before claiming compare/render readiness.
- Current enum/vocabulary alignment:
- Use repo-canonical values such as `capture_blocked_missing_contract`, `capture_blocked_permission`, `capture_blocked_beta`, `capture_blocked_unsupported`, `capture_failed`, `content_backed`, `stable`, `derived`, `identity_conflict`, `missing_external_id`, and `unsupported_identity`.
- Do not introduce parallel wording such as `capture_blocked_unsupported_source` unless the enum/status family is deliberately amended with tests and proportionality review.
## UI / Surface Guardrail Plan
- **Guardrail scope**: no operator-facing surface change by default.
- **Affected routes/pages/actions/states/navigation/panel/provider surfaces**: none by default. Existing Coverage v2 readiness/operator surface only if implementation amends artifacts first.
- **No-impact class, if applicable**: service/config/test-only.
- **Native vs custom classification summary**: N/A - no UI change.
- **Shared-family relevance**: evidence capture, identity, source contracts, claim safety, redaction, compare/render readiness.
- **State layers in scope**: none in UI; service/evidence state only.
- **Audience modes in scope**: internal/operator proof only; no customer/read-only output.
- **Decision/diagnostic/raw hierarchy plan**: evidence and readiness proof remain implementation-report/test proof; raw/support details never default-render.
- **Raw/support gating plan**: raw payloads, raw provider responses, source keys, OperationRun internals, provider diagnostics, and permission context stay hidden from default UI and excluded from customer output.
- **One-primary-action / duplicate-truth control**: no new action.
- **Handling modes by drift class or surface**: runtime UI changes require spec/plan/tasks amendment, Product Surface completion, focused browser proof, and Human Product Sanity. New route/navigation/customer/restore/certify scope is a hard stop.
- **Repository-signal treatment**: review-mandatory for evidence/status presentation only if UI is amended; hard-stop for customer output, restore/apply, certification, or mini-platform drift.
- **Special surface test profiles**: N/A by default; existing Coverage v2 Technical Annex browser smoke only if UI changes.
- **Required tests or manual smoke**: focused Unit/Feature always; Browser conditional.
- **Exception path and spread control**: none.
- **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage.
- **UI/Productization coverage decision**: `N/A - no rendered UI surface changed` by default.
- **Coverage artifacts to update**: none unless implementation amends runtime UI scope.
- **No-impact rationale**: Missing-contract blockers, identity hardening, no-fake-evidence behavior, and no-overclaim guards can be proven by existing shared services and tests without rendered UI changes.
- **Navigation / Filament provider-panel handling**: no panel, provider registration, route, or navigation change.
- **Screenshot or page-report need**: none unless runtime UI is amended into scope.
## Product Surface Contract Plan
- **Product Surface Contract reference**: `docs/product/standards/product-surface-contract.md`.
- **No-legacy posture**: canonical Coverage v2 extension; no compatibility exception.
- **Page archetype and surface budget plan**: N/A by default. If amended into existing UI, classify as Technical Annex and preserve existing surface budgets.
- **Technical Annex and deep-link demotion plan**: OperationRun, evidence IDs, source endpoints, source keys, raw payloads, permission context, provider diagnostics, unsupported internals, and raw compare values remain hidden/collapsed/internal-only.
- **Canonical status vocabulary plan**: N/A by default. If rendered, product-facing labels map to canonical vocabulary and never say certified, restore-ready, customer-ready, full Exchange, full Teams, or M365 certified.
- **Product Surface exceptions**: none.
- **Browser verification plan**: `N/A - no rendered UI surface changed` unless UI files change; otherwise focused existing Coverage v2 route smoke.
- **Human Product Sanity plan**: N/A unless UI changes.
- **Visible complexity outcome target**: neutral by default.
- **Implementation report target**: `specs/426-exchange-teams-core-evidence-identity-readiness/implementation-report.md`.
## Filament / Livewire / Deployment Posture
- **Livewire v4 compliance**: unchanged; platform remains Filament v5 on Livewire v4. Must be stated in close-out.
- **Panel provider registration location**: no panel change planned. Laravel 12 provider registration remains `apps/platform/bootstrap/providers.php`.
- **Global search posture**: no Resource/global search change planned.
- **Destructive/high-impact action posture**: none. No restore/apply/certify/start action may be introduced. Existing capture workflow may be reused only if already authorized and OperationRun-backed.
- **Asset strategy**: no new assets planned. `filament:assets` is not newly required unless implementation unexpectedly registers assets, which would require spec amendment.
- **Testing plan**: Unit/Feature for source contracts, capture eligibility, evidence persistence, identity, normalization/hash, claim guard, redaction, no certification/restore/customer/tenant_id/mini-platform; Browser only if UI changes.
- **Deployment impact**: no env vars, migrations, queues, scheduler, storage, or assets expected. If graph contracts/resource defaults change, existing deployment/sync steps must be documented in the implementation report.
## Shared Pattern & System Fit
- **Cross-cutting feature marker**: yes.
- **Systems touched**: Coverage v2 resource type registry, source contract resolver, graph contract config, provider gateway, generic capture, resource upsert/evidence write, identity strategy registry/resolver, Exchange/Teams typed normalizer/comparator/summary builder, Claim Guard, redaction, operation capture tests.
- **Shared abstractions reused**: `CoverageSourceContractResolver`, `GraphContractRegistry`, `ProviderGateway`, `GraphClientInterface`, `GenericContentEvidenceCaptureService`, `CoverageResourceUpserter`, `CoverageEvidenceWriter`, `CoverageIdentityStrategyRegistry`, `CanonicalIdentityResolver`, `ExchangeTeamsComparablePayloadNormalizer`, `ExchangeTeamsCoverageComparator`, `ExchangeTeamsRenderableSummaryBuilder`, `ClaimGuard`, `OperationRunService`.
- **New abstraction introduced? why?**: none expected. A small adapter for typed normalization during capture is allowed only if the existing generic normalizer cannot safely persist deterministic Spec 422-compatible payloads.
- **Why the existing abstraction was sufficient or insufficient**: Existing Coverage v2 paths provide scope, evidence, identity, and claim safety. They lack the exact four source contracts, identity strategies, and source-backed typed normalization alignment required for later certification.
- **Bounded deviation / spread control**: Exchange/Teams-specific logic must remain bounded to typed helpers/contract mappings inside the Tenant Configuration service boundary. No Exchange/Teams platform or generic provider framework.
## OperationRun UX Impact
- **Touches OperationRun start/completion/link UX?**: no new UX.
- **Central contract reused**: existing OperationRun-backed capture path only.
- **Delegated UX behaviors**: N/A - no new start surface.
- **Surface-owned behavior kept local**: none.
- **Queued DB-notification policy**: no new policy.
- **Terminal notification path**: existing central lifecycle mechanism only.
- **Exception path**: none.
Remote/provider capture must continue to use existing OperationRun service-owned lifecycle and sanitized summary counts. No new operation type is required unless implementation proves the existing `tenant_configuration.capture` cannot represent the capture safely; that would require spec amendment.
## Provider Boundary & Portability Fit
- **Shared provider/platform boundary touched?**: yes.
- **Provider-owned seams**: Exchange/Teams source contracts, Microsoft Graph/TCM source payload fields, provider IDs/natural keys, provider permission metadata.
- **Platform-core seams**: Coverage v2 evidence state, capture outcome, identity state, coverage level, claim state, payload hash, workspace/managed-environment/provider scope.
- **Neutral platform terms / contracts preserved**: resource type, evidence, identity, source contract, provider connection, managed environment, claim, compare/render readiness.
- **Retained provider-specific semantics and why**: `transportRule`, `acceptedDomain`, `appPermissionPolicy`, and `meetingPolicy` are Microsoft 365 resource semantics required by the exact denominator.
- **Bounded extraction or follow-up path**: document-in-feature. Spec 427 should verify/enable production-safe source contracts for the four mandatory Exchange/Teams types or keep each type explicitly blocked. Spec 428 should promote content-backed evidence only after verified contracts exist. Spec 429 should promote compare/render only after source-backed evidence exists. Certification remains a later separate spec.
## Constitution Check
- Inventory-first / evidence truth: FAIL-safe. This branch does not capture observed Exchange/Teams provider configuration evidence because verified source contracts are missing; blocked outcomes prevent fake evidence.
- Read/write separation: PASS with controls. No provider write, restore, apply, destructive UI action, or fake internal evidence write is introduced.
- Graph contract path: FAIL-safe. No unverified contracts are added to `config/graph_contracts.php`; future source contracts must use `GraphClientInterface`/provider gateway only.
- Deterministic capabilities: PASS. Readiness criteria and claim blockers are testable.
- RBAC-UX: PASS with implementation requirement. Non-member/wrong scope is 404; member missing capability is 403; readonly cannot start capture.
- Workspace isolation: PASS with implementation requirement. Same workspace/managed environment/provider connection is required.
- Tenant isolation: PASS in current repo vocabulary; no `tenant_id` ownership truth.
- Run observability: PASS. Blocked capture is OperationRun-backed and records sanitized missing-contract outcomes; readiness evaluation is DB/service-only.
- OperationRun start UX: N/A unless existing start workflow is reused; no new start surface.
- Data minimization: PASS. No raw Exchange/Teams provider payload is captured while contracts are missing; future raw payloads must remain evidence-only and never default-rendered/logged/customer-published.
- Test governance: PASS. Unit/Feature lane is sufficient unless UI changes.
- Proportionality: PASS. Four concrete source/identity gaps justify narrow missing-contract guards, identity strategies, and helper tests.
- No premature abstraction: PASS only if implementation avoids a generic Exchange/Teams framework.
- Persisted truth: PASS. Uses existing evidence/resource tables.
- Behavioral state: PASS if existing enum/status families are reused.
- UI semantics: PASS by no-UI default.
- Shared pattern first: PASS. Existing Coverage v2 services are the path.
- Provider boundary: PASS with provider-specific fields bounded to contracts/typed adapters.
- V1 explicitness / few layers: PASS. Explicit four-type implementation only.
- Spec discipline / bloat check: PASS. Certification, restore, customer output, and optional types are split out.
- Filament-native UI: N/A unless existing UI changes.
- Product Surface Contract: PASS with no-rendered-surface rationale.
## Test Governance Check
- **Test purpose / classification by changed surface**: Unit for resolver, eligibility, identity, normalization, hash, Claim Guard, redaction. Feature for blocked capture with no fake DB evidence, OperationRun, provider scope, authorization, no certification/restore/customer/tenant_id/mini-platform. Browser only if UI changes.
- **Affected validation lanes**: fast-feedback; browser conditional.
- **Why this lane mix is the narrowest sufficient proof**: Missing-contract decisions, identity hardening, no-fake-evidence behavior, and claim safety are deterministic service/DB behavior. Browser proof is only meaningful when rendered UI changes.
- **Narrowest proving command(s)**:
- `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=ExchangeTeamsSourceContractResolverTest`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=ExchangeTeamsIdentityStrategyRegistryTest`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec426ExchangeTeamsCoreEvidenceReadinessTest`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec426ExchangeTeamsStableIdentityReadinessTest`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec426ExchangeTeamsClaimGuardFeatureTest`
- **Fixture / helper / factory / seed / context cost risks**: Add minimal fake provider payloads for four resource types; avoid full workspace/provider setup defaults outside feature tests.
- **Expensive defaults or shared helper growth introduced?**: no.
- **Heavy-family additions, promotions, or visibility changes**: none unless UI changes.
- **Surface-class relief / special coverage rule**: `N/A - no rendered UI surface changed` by default.
- **Closing validation and reviewer handoff**: verify missing-contract blockers, no fake evidence persistence, stable identity strategy hardening, no compare/render overclaim, claim blocking, redaction, no restore/customer/tenant_id/mini-platform.
- **Budget / baseline / trend follow-up**: none expected.
- **Review-stop questions**: Did any type rely on beta-only source, display-name identity, fake evidence, direct HTTP, endpoint guessing, customer claim, restore path, or `tenant_id`? If yes, fail or split.
- **Escalation path**: reject-or-split for certification/restore/customer/mini-platform scope; document-in-feature for bounded source/identity limitations.
- **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage.
- **Why no dedicated follow-up spec is needed**: This is the dedicated fail-safe readiness unblocker. Source-contract verification, content-backed evidence promotion, compare/render promotion, and certification are intentionally split into later specs.
## Risk Controls And Rollout Considerations
- **Rollout shape**: Service/config/test-only by default. No migration, env var, route, navigation, asset, queue, scheduler, storage, or customer-output rollout is planned.
- **Staging gate**: Later implementation must validate source contracts, capture outcomes, redaction, provider scope, and no-certification/no-restore/no-customer claims on staging before production promotion.
- **Provider-contract risk control**: New source contracts must be explicit registry entries with source class, source version/schema metadata where available, permission metadata where supported, and fake-provider tests. Runtime endpoint guessing is a stop condition.
- **Evidence integrity risk control**: Missing contract, missing permission, unsupported source, beta-only source, unavailable source, and provider failure must remain blocked/failed states, not empty evidence.
- **Identity risk control**: Any type that cannot produce stable source-backed identity fails readiness instead of falling back to display-name, order, payload-hash, operation-run, or generated identity.
- **Claim risk control**: Claim Guard must keep certification, restore-ready, full workload/M365, and customer-ready wording blocked until a later spec.
- **Operational risk control**: OperationRun summaries remain numeric-only and sanitized; compare/render readiness evaluation must not call the provider.
- **Rollback/forward note**: Because no schema or customer surface is planned, rollback is reverting the source/identity/normalization code and tests. If implementation discovers schema or UI changes are necessary, artifacts must be amended before proceeding.
## Project Structure
### Documentation (this feature)
```text
specs/426-exchange-teams-core-evidence-identity-readiness/
├── checklists/
│ └── requirements.md
├── plan.md
├── spec.md
└── tasks.md
```
### Source Code (repository root)
Likely affected runtime/test paths for later implementation:
```text
apps/platform/config/
└── graph_contracts.php
apps/platform/app/Services/TenantConfiguration/
├── CoverageSourceContractResolver.php
├── CoverageIdentityStrategyRegistry.php
├── GenericContentEvidenceCaptureService.php # only if typed capture normalization hook is needed
├── GenericPayloadNormalizer.php # only if deterministic collection/hash behavior must be generalized
├── CoverageEvidenceWriter.php # only if typed normalized payload promotion requires writer support
├── ExchangeTeamsComparablePayloadNormalizer.php
├── ExchangeTeamsCoverageComparator.php
├── ExchangeTeamsRenderableSummaryBuilder.php
└── ClaimGuard.php
apps/platform/tests/Unit/Support/TenantConfiguration/
└── ExchangeTeams*.php
apps/platform/tests/Feature/TenantConfiguration/
└── Spec426ExchangeTeams*.php
apps/platform/tests/Fixtures/TenantConfiguration/Spec426/
└── exchange-teams/
apps/platform/tests/Browser/
└── Spec426ExchangeTeamsCoreEvidenceReadinessSmokeTest.php # only if UI changes
```
**Structure Decision**: Use existing TenantConfiguration/Coverage v2 service and test directories. Do not create new base folders, migrations, routes, Filament resources/pages/widgets, commands, jobs, dashboards, reports, exports, PDFs, or customer-output surfaces.
## Complexity Tracking
| Violation | Why Needed | Simpler Alternative Rejected Because |
|---|---|---|
| Fail-closed source contract blockers | Later certification needs real source-backed capture for the exact denominator, but no verified contracts exist yet | Registering guessed Graph endpoints would allow fake certification readiness |
| Four stable identity strategies | Stable canonical identity is required to compare, track, and later certify resource instances | Display-name or payload-hash identity is unstable and unsafe |
| Typed source normalization alignment | Source-backed payloads must enter the existing Spec 422 compare/render pipeline deterministically | Generic raw-payload hashing alone does not prove comparable/renderable shape |
## Proportionality Review
- **Current operator problem**: Exchange/Teams certification remains blocked because the denominator lacks source-backed evidence and stable identity.
- **Existing structure is insufficient because**: Current source resolver and identity registry do not cover the four mandatory types; Spec 422 does not prove live/source-backed capture.
- **Narrowest correct implementation**: Keep missing source contracts blocked, remove unverified mappings, extend identity/normalization tests for exactly four concrete types, and document the source blocker.
- **Ownership cost created**: Four identity strategies and focused tests must track future provider contract changes.
- **Alternative intentionally rejected**: Certify based on row-level compare/render support or display names. That would weaken evidence integrity and create unsafe claims.
- **Release truth**: Current-release prerequisite for later source-contract verification, evidence promotion, compare/render promotion, and eventual certification.
## Technical Approach
### Phase 0 - Hard Preflight
- Confirm branch, HEAD, dirty state, active spec path, and activated skills/gates.
- Confirm completed dependency specs are read-only context.
- Re-check current source contract and identity gaps.
- Confirm Coverage v2 capture/identity/evidence infrastructure exists.
- Stop if generic capture or canonical identity infrastructure is missing.
### Phase 1 - Source Contract Gap Map
- Inspect `CoverageSourceContractResolver`, `config/graph_contracts.php`, `GraphContractRegistry`, `ProviderGateway`, and `GraphClientInterface` patterns.
- Record current resolver state for `transportRule`, `acceptedDomain`, `appPermissionPolicy`, and `meetingPolicy`.
- Determine source class, contract key, production-safety, permission metadata, response shape, volatile fields, and empty collection semantics.
- Identify whether any type is beta/experimental-only; if yes, mark certification readiness blocked.
### Phase 2 - Block Unverified Source Contracts
- Do not add resolver mappings or contract definitions for the four mandatory types until verified source contracts exist.
- Prove blocked capture makes no `ProviderGateway`/`GraphClientInterface` calls.
- Add contract tests proving no endpoint guessing, no direct HTTP, and missing-contract fail-closed behavior.
- Preserve missing-permission and unsupported-source outcomes.
### Phase 3 - Block Fake Content-Backed Evidence
- Route all four types through existing generic/shared capture path until the source contract decision blocks them.
- Persist no resource rows or evidence rows while contracts are missing.
- Preserve typed helper payload normalization for future valid source payloads, without claiming readiness/hash proof from blocked capture.
- Represent empty successful collections only as safe source-contract capture proof unless an existing repo-approved type-level evidence artifact can carry an explicit empty normalized payload/hash; do not create fake resource instances.
- Prevent fake/synthetic evidence from counting as source-backed.
### Phase 4 - Stable Identity
- Add identity strategies for the four mandatory types.
- Require stable provider/source ID or proven immutable natural key/composite.
- Reject display-name-only, array-index, priority/order, payload-hash, random UUID, and operation-run identity.
- Use `CanonicalIdentityResolver` and block identity conflicts.
### Phase 5 - Normalization And Compare/Render Helper Proof
- Align helper payload fixtures with `ExchangeTeamsComparablePayloadNormalizer`, `ExchangeTeamsCoverageComparator`, and `ExchangeTeamsRenderableSummaryBuilder` so future real source-backed payloads have a bounded path.
- Preserve material fields, exclude volatile fields, and record unsupported fields diagnostically.
- Mark readiness as compare/render-ready only when source-backed evidence and stable identity both exist; this branch does not satisfy that gate.
- Do not assign certified coverage.
### Phase 6 - Claim Guard / Safety
- Allow internal evidence-ready and stable-identity-ready wording only when proven.
- Block certification, restore-ready, full Exchange/Teams/M365, and customer-ready claims.
- Add redaction tests for secrets, tokens, cookies, authorization headers, raw payloads, raw permission context, mail content, and Teams content.
### Phase 7 - Product Surface Decision
- Confirm no runtime UI change.
- If implementation proves UI is needed, stop, amend spec/plan/tasks with exact affected surfaces, then run Product Surface/browser/Human Product Sanity proof.
- Do not add route, navigation, dashboard, certify action, restore action, report, customer output, Review Pack, export, or PDF.
### Phase 8 - Validation
- Run Pint dirty.
- Run focused unit tests.
- Run focused feature tests.
- Run browser test only if UI changed.
- Run `git diff --check`.
- Document exact validation results in implementation report.
### Phase 9 - Implementation Report
- Produce required matrices and final candidate gate result.
- Record no certification, no restore, no customer claim, no `tenant_id`, no mini-platform, and Product Surface no-impact proof.
## Stop Conditions
- Any mandatory type lacks source contract support and is treated as source-backed or compare/render-ready.
- Any mandatory type lacks stable source-backed identity.
- Any type is beta/experimental-only but treated as certification-ready.
- Synthetic/fake evidence is counted as source-backed.
- Display name, order, payload hash, or operation run ID is used as stable identity.
- Capture bypasses provider gateway/GraphClientInterface or guesses endpoints.
- Certification, restore/apply, customer output, full workload/M365 claim, new route/navigation/dashboard, or mini-platform appears.
- `tenant_id` is introduced as platform-core ownership truth or compatibility/fallback path.
- Raw payload, secrets, mail content, Teams content, or raw permission context leak into logs/UI/output.
- Tests cannot prove evidence + identity readiness.