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
10 KiB
Implementation Report: Spec 426 - Exchange / Teams Core Evidence & Stable Identity Readiness
Branch: 426-exchange-teams-core-evidence-identity-readiness
HEAD: 33e496c1 feat: complete spec 425 enta certified compare pack (#492)
Implementation date: 2026-07-02
Result: PASS WITH CONDITIONS for Spec 426 closure; FAIL-safe for source-backed evidence readiness
Gate Result
- Activated skills/gates:
pest-testing, Spec Readiness Gate, provider-freshness semantics, and TCM cutover guard for the post-review fix. Earlier implementation work also used workspace/RBAC/OperationRun/evidence/customer-output/Product Surface gates. - Closure gate:
PASS WITH CONDITIONS. - Condition: Spec 426 proves fail-safe behavior for Exchange/Teams source-backed evidence. It does not prove readiness, capture support, compare support, render support, or certification. Typed normalizer/hash tests are future-contract helper proof only.
- Source-backed evidence readiness gate: FAIL-safe/blocked because no verified production-safe source contract exists for the four mandatory types.
- Completed dependency specs 414, 415, 417, 418, 419, 420, 422, and 425 remain read-only context. No completed spec artifacts were rewritten.
- Review correction: removed unverified Graph v1.0 endpoint claims for
mailFlowRule,acceptedDomains,teamsAppPermissionPolicy, andteamsMeetingPolicy. - Final dirty state: runtime service/config/test changes plus active Spec 426 artifacts, as expected for this active spec.
Files Changed
- Source contracts and capture:
apps/platform/app/Services/TenantConfiguration/CoverageSourceContractResolver.phpapps/platform/app/Services/TenantConfiguration/GenericContentEvidenceCaptureService.phpapps/platform/config/graph_contracts.phpwas verified to contain no unverified final Spec 426 contract entries; it has no final diff in this correction.
- Stable identity:
apps/platform/app/Services/TenantConfiguration/CoverageIdentityStrategyRegistry.php
- Tests:
- Focused Spec 426 unit and feature tests under
apps/platform/tests/Unit/Support/TenantConfiguration/andapps/platform/tests/Feature/TenantConfiguration/ - Updated Spec 417/420 expectations so the four Exchange/Teams types remain fail-closed until verified contracts exist
- Focused Spec 426 unit and feature tests under
- Spec artifacts:
spec.md,plan.md,tasks.md, this implementation report
Source Contract Matrix
| Type | Contract key | Endpoint | Source class | Outcome |
|---|---|---|---|---|
transportRule |
none | none | none | capture_blocked_missing_contract |
acceptedDomain |
none | none | none | capture_blocked_missing_contract |
appPermissionPolicy |
none | none | none | capture_blocked_missing_contract |
meetingPolicy |
none | none | none | capture_blocked_missing_contract |
No endpoint guessing, direct HTTP, runtime documentation lookup, provider bypass, or guessed Microsoft Graph source contract remains. Capture attempts stop before ProviderGateway / GraphClientInterface calls for these four types.
Evidence Matrix
| Type | Capture outcome | Provider call | Resource row | Evidence row | Empty/fake behavior |
|---|---|---|---|---|---|
transportRule |
capture_blocked_missing_contract |
no | no | no | no fake resource/evidence |
acceptedDomain |
capture_blocked_missing_contract |
no | no | no | no fake resource/evidence |
appPermissionPolicy |
capture_blocked_missing_contract |
no | no | no | no fake resource/evidence |
meetingPolicy |
capture_blocked_missing_contract |
no | no | no | no fake resource/evidence |
OperationRun summaries remain flat numeric counts. Blocked runs record sanitized blocked outcomes only; no raw payload, provider response body, secret, mail content, Teams content, or raw permission context is placed in run context or audit metadata.
Identity Matrix
| Type | Strategy | Stable identity inputs | Explicitly rejected |
|---|---|---|---|
transportRule |
tcm.exchange.transport_rule.v1 |
id, sourceId, Guid, RuleId |
Identity, display/name fields, order, payload hash |
acceptedDomain |
tcm.exchange.accepted_domain.v1 |
id, sourceId, DomainName, domainName |
Identity, display/name fields, domain type/default flag |
appPermissionPolicy |
tcm.teams.app_permission_policy.v1 |
id, sourceId, policyId |
Identity, display/name fields, settings/app hash |
meetingPolicy |
tcm.teams.meeting_policy.v1 |
id, sourceId, policyId |
Identity, display/name fields, settings hash |
CanonicalIdentityResolver remains the only identity path. Identity-only payloads resolve to missing_external_id, not stable identity.
Readiness Matrix
| Type | content_backed |
identity_strategy_hardened |
compare_render_ready |
certified |
restore_ready |
customer_claimable |
|---|---|---|---|---|---|---|
transportRule |
no | yes | no | no | no | no |
acceptedDomain |
no | yes | no | no | no | no |
appPermissionPolicy |
no | yes | no | no | no | no |
meetingPolicy |
no | yes | no | no | no | no |
Typed normalizer/hash/redaction tests remain as helper proof for future valid source payloads. They are not used to claim source-backed evidence or certification readiness. Post-review coverage now also proves that typed helper output keeps stable source identity fields (Guid, RuleId, DomainName, policyId, sourceId), that the future typed capture handoff preserves that type-specific source_identity, that contract-level volatile fields are excluded from typed unsupported diagnostics/material hashes, and that payload hashes ignore volatile-field diagnostics.
Claim Guard And Redaction
- Certified, restore-ready, full Exchange/Teams/Microsoft 365, and customer-ready claims remain blocked.
- Internal compare/render wording remains bounded by Claim Guard, but this report does not claim source-backed compare/render readiness for the four mandatory types.
- Redaction tests cover provider secrets, tokens, raw provider markers, mail subject/body-like fields, and Teams recording/transcript-like fields in normalized/helper output.
Product Surface / Filament Contract
- No runtime UI files, routes, navigation, Filament resources/pages/widgets, actions, reports, exports, or customer outputs were changed.
- Product Surface decision:
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. - Livewire v4 compliance: unchanged; Filament v5 remains on Livewire v4.
- Provider registration: unchanged; Laravel provider registration remains in
apps/platform/bootstrap/providers.php. - Global search: unchanged; no resource/global search behavior was added.
- Destructive/high-impact actions: none added.
- Asset strategy: no new assets; no new
filament:assetsdeployment requirement.
Deployment Impact
- Migrations: none.
- Environment variables: none.
- Queues/cron: no new workers or schedules; existing OperationRun-backed capture job reused.
- Storage/volumes: none.
- Assets: none.
- Runtime config: no new Exchange/Teams graph contract entries remain; deploy through the normal container/config-cache path.
- Staging/Production: do not promote Exchange/Teams certification from this branch. Next sequence is Spec 427 verified source contract enablement, Spec 428 content-backed evidence promotion, Spec 429 compare/render promotion, and only later certification. A future verified provider contract must pass staging before evidence promotion or certification proceeds.
Validation
Passed after post-review fix and closure review:
cd apps/platform && ./vendor/bin/sail artisan test --compact --filter=Spec426- terminated with Signal 9 in the container runner.
- Not a closure blocker because the equivalent direct file runs below passed.
cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/TenantConfiguration/Spec426ExchangeTeamsSourceContractResolverTest.php tests/Unit/Support/TenantConfiguration/Spec426ExchangeTeamsCanonicalIdentityTest.php- 22 passed, 124 assertions.
cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/TenantConfiguration/Spec426ExchangeTeamsPayloadNormalizationFromSourceTest.php tests/Unit/Support/TenantConfiguration/Spec426ExchangeTeamsEvidenceHashTest.php tests/Unit/Support/TenantConfiguration/Spec426ExchangeTeamsClaimGuardReadinessTest.php tests/Unit/Support/TenantConfiguration/Spec426ExchangeTeamsRedactionTest.php- 24 passed, 77 assertions.
cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/TenantConfiguration/Spec426ExchangeTeamsCoreEvidenceReadinessTest.php tests/Feature/TenantConfiguration/Spec426ExchangeTeamsStableIdentityReadinessTest.php- 3 passed, 69 assertions.
cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/TenantConfiguration/Spec426ExchangeTeamsProviderScopeTest.php tests/Feature/TenantConfiguration/Spec426ExchangeTeamsNoCertificationTest.php tests/Feature/TenantConfiguration/Spec426ExchangeTeamsNoRestoreTest.php tests/Feature/TenantConfiguration/Spec426ExchangeTeamsNoTenantIdTest.php tests/Feature/TenantConfiguration/Spec426ExchangeTeamsNoMiniPlatformTest.php tests/Feature/TenantConfiguration/Spec426ExchangeTeamsClaimGuardFeatureTest.php- 7 passed, 55 assertions.
- Direct file Spec 426 total:
- 56 passed, 325 assertions.
cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/TenantConfiguration/Spec420M365GenericEvidenceCaptureTest.php tests/Feature/TenantConfiguration/Spec420M365CaptureOperationRunTest.php tests/Unit/Support/TenantConfiguration/Spec420M365CaptureSourceContractResolverTest.php tests/Unit/Support/TenantConfiguration/Spec420M365CaptureEligibilityTest.php tests/Unit/Support/TenantConfiguration/Spec417CoverageIdentityStrategyRegistryTest.php- 16 passed, 259 assertions.
cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec420M365GenericEvidenceOperatorSurfaceSmokeTest.php- 1 passed, 44 assertions.
cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent- passed.
git diff --check- passed.
Spec 426 browser validation remains N/A - no rendered UI surface changed; the Spec 420 browser regression fixture changed and passed.