TenantAtlas/specs/420-m365-generic-evidence-coverage-pack/spec.md
Ahmed Darrazi 9405058433
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 5m46s
feat: complete m365 generic evidence coverage pack
2026-06-27 13:00:22 +02:00

43 KiB

Feature Specification: Spec 420 - M365 Generic Evidence Coverage Pack

Feature Branch: 420-m365-generic-evidence-coverage-pack Created: 2026-06-27 Status: Draft Input: User-provided "Spec 420 - M365 Generic Evidence Coverage Pack" draft plus repo checks against Specs 414, 415, 417, 418, 419, roadmap/candidate queue, constitution, Product Surface Contract, TenantPilot agent gates, and current TenantConfiguration runtime.

Candidate Selection

  • Selected candidate: Spec 420 - M365 Generic Evidence Coverage Pack.
  • Source location: User-provided draft attachment in this session. docs/product/spec-candidates.md says the automatic next-best-prep queue is empty as of 2026-06-15, so this is a direct manual promotion.
  • Why selected: Spec 419 established the registry-only M365 workload layer and explicitly deferred "M365 Generic Evidence Coverage Pack" as the next M365 runtime follow-up. Specs 414, 415, 417, and 418 provide the Coverage v2 kernel, generic content-backed capture path, canonical identity engine, and operator inspection surface required to prepare this safely.
  • Roadmap relationship: Aligns with the roadmap's provider-boundary, evidence, workspace/managed-environment ownership, and claim-safety priorities. It is not auto-selected from the active candidate queue.
  • Close alternatives deferred: Management-report PDF runtime validation, governance artifact lifecycle retention, provider readiness productization, cross-domain indicator follow-through, system-panel browser fixture work, and first governed AI runtime consumer remain manual-promotion backlog items. Entra compare/render, Exchange/Teams compare, Security/Compliance readiness, certified packs, restore, customer reports, and M365 dashboards remain later specs.
  • Related spec guardrail: specs/414-tcm-first-coverage-core-cutover/, specs/415-generic-content-backed-capture/, specs/417-canonical-identity-engine/, specs/418-coverage-v2-operator-surface/, and specs/419-m365-tcm-workload-registry-expansion/ are read-only dependency context with implementation history. Do not rewrite them, normalize their historical notes, or strip task/browser/review evidence.
  • Prerequisite gate result: PASS for preparation. Repo truth includes TenantConfigurationResourceType, TenantConfigurationResource, TenantConfigurationResourceEvidence, TenantConfigurationSupportedScope, ResourceTypeRegistry, SupportedScopeResolver, ClaimGuard, GenericContentEvidenceCaptureService, CoverageSourceContractResolver, CanonicalIdentityResolver, OperationRunService, GraphClientInterface, and M365 registry rows from Spec 419.
  • Smallest viable implementation slice: Use the existing generic capture stack to enable one explicit content-backed M365 capture path for conditionalAccessPolicy when its repo-real Graph contract remains valid, and prove structured blocked outcomes for selected Exchange, Teams, and Security/Compliance resource types with missing source contracts. If the existing conditionalAccessPolicy contract is not valid for generic capture, stop and amend this package before implementation continues. Do not add a UI start action, customer output, compare/render/restore/certification, broad M365 claims, or workload-specific mini-platform.
  • Draft-to-repo deviations:
    • The user draft names operation type tenant_configuration.m365_capture; current repo truth already has tenant_configuration.capture. This spec reuses the existing operation type unless implementation proves a distinct type has a current operator or lifecycle consequence.
    • The user draft includes new eligibility outcomes such as capture_blocked_source_unavailable and capture_blocked_high_risk; current repo truth has captured, capture_blocked_missing_contract, capture_blocked_permission, capture_blocked_beta, capture_blocked_unsupported, and capture_failed. This spec uses existing outcomes plus stable reason codes unless a new outcome passes proportionality review.
    • The user draft suggests a broad first-pack list. This spec narrows the first implementation-ready pack to four representative resource types: conditionalAccessPolicy, acceptedDomain, appPermissionPolicy, and dlpCompliancePolicy.

Spec Candidate Check (mandatory - SPEC-GATE-001)

  • Problem: TenantPilot now recognizes M365 workload/resource types as registry-only planning truth, but generic evidence capture still effectively defaults to Intune. Without a bounded M365 evidence slice, later compare/render/certification work has no real payload basis and the product can drift toward false M365 readiness claims.
  • Today's failure: Operators and implementers can see M365 registry rows but cannot verify any real non-Intune M365 configuration evidence through the Coverage v2 evidence path. The system also lacks a proven safe missing-contract path across M365 workloads.
  • User-visible improvement: Authorized operators can rely on internal evidence truth for a small M365 first pack: conditionalAccessPolicy becomes content-backed when fake-provider capture succeeds, while Exchange, Teams, and Security/Compliance examples fail safe as structured blockers in Spec 420.
  • Smallest enterprise-capable version: Enable one repo-contract-backed M365 capture path and three missing-contract blocker paths through existing generic services, canonical identity, OperationRun, RBAC, redaction, and Claim Guard. No UI start action and no customer-facing claims.
  • Explicit non-goals: No semantic compare, customer-safe rendering, restore/apply, certification, broad M365 coverage, customer-facing reports, Review Pack output, M365 dashboard, Microsoft docs scraping, workload-specific service/platform namespaces, live provider calls in tests, v1 compatibility, or tenant_id.
  • Permanent complexity imported: Focused source-contract mapping for selected types, identity strategies for selected M365 resource types, possibly narrow Graph contract entries only when repo truth supports them, reason-code tests for missing contracts, and focused unit/feature/browser-if-rendered tests. No new table, provider framework, UI framework, or broad status taxonomy by default.
  • Why now: Spec 419 made M365 registry rows visible and explicitly deferred generic evidence capture. This is the next safety gate before any compare/render/certification pack can be credible.
  • Why not local: A local Entra-only capture path would bypass the generic Coverage v2 contracts and invite workload mini-platforms. The existing generic capture, evidence, identity, OperationRun, RBAC, and Claim Guard stack is the correct shared path.
  • Approval class: Core Enterprise.
  • Red flags triggered: Runtime evidence capture for a new workload family; source-contract mapping; identity strategy expansion. Defense: the slice reuses existing infrastructure, proves one real payload path, blocks missing contracts safely, and prevents false M365 coverage claims.
  • Score: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 2 | Wiederverwendung: 2 | Gesamt: 11/12
  • Decision: approve as a narrow generic-evidence pack with one enabled capture path and explicit missing-contract blockers.

Spec Scope Fields (mandatory)

  • Scope: workspace + managed-environment scoped runtime evidence capture for selected M365 resource types, using same-scope provider_connection_id when provider-sourced.
  • Primary Routes: No new route, page, action, navigation entry, customer output, download, or report is in scope. Existing Spec 418 Coverage v2 operator surface may show captured/blocked data if it already renders generic Coverage v2 registry/evidence rows.
  • Data Ownership: Concrete TenantConfigurationResource and TenantConfigurationResourceEvidence rows remain environment-owned with workspace_id, managed_environment_id, and same-scope provider_connection_id. Provider-native tenant/directory/account IDs are metadata only. No tenant_id is allowed as Coverage v2 internal ownership truth.
  • RBAC: Starting capture remains server-authorized through the existing capture service/capability path. Non-member or missing environment entitlement must deny as not found (404); established members without capture capability must receive 403. Readonly users cannot start capture.

For canonical-view specs:

  • Default filter behavior when tenant-context is active: N/A - no canonical route or route filter change.
  • Explicit entitlement checks preventing cross-tenant leakage: Any existing rendered operator surface must rely on current workspace/managed-environment scope. Capture services/jobs must re-resolve and validate managed environment, provider connection, and OperationRun scope before provider work.

No Legacy / No Backward Compatibility Constraint (mandatory)

TenantPilot is pre-production unless this spec explicitly records a compatibility exception.

  • Compatibility posture: canonical Coverage v2 generic capture extension; no compatibility exception.
  • Legacy aliases, fallback readers, hidden routes, duplicate UI, old labels, or historical fixtures kept?: no.
  • Why clean replacement is safe now: This is a new M365 generic-evidence slice on the Coverage v2 path. No production/customer data or external contract requires Coverage v1 compatibility, old gap taxonomy, dual writes, fallback readers, or old snapshot promotion.

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 runtime UI file, route, navigation, table/form schema, action, Blade view, Livewire component, or Filament provider change is planned. The impact is data-driven: existing Spec 418 Coverage v2 operator surfaces may show M365 resource/evidence rows or blocked outcomes because they already read generic Coverage v2 data. Implementation must make one explicit close-out decision: if rendered output changes, run focused browser proof and Human Product Sanity; if no rendered output changes, record exact N/A - no rendered UI surface changed proof. If implementation requires runtime UI edits, a new start action, or changed labels/actions, stop and amend this spec, plan, and tasks before editing runtime UI.

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)

Existing Coverage v2 operator surface data may change without UI code edits. Productization coverage is limited to the existing internal/operator Coverage v2 readiness/resource/evidence inspection surface. No new route, primary navigation, dashboard, customer-facing surface, report, download, restore/certify action, or capture button is allowed. The existing surface must remain internal/operator only, show generic evidence or blocked outcomes honestly, and avoid customer-ready M365 coverage language.

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?: yes, for data-driven status/evidence changes on the existing Coverage v2 operator surface.
  • Page archetype: existing internal/operator Technical Annex / registry and evidence inspection surface.
  • Primary user question: Which selected M365 resource types have real generic evidence, and which are blocked because the source contract is missing or unsafe?
  • Primary action: inspect existing registry/evidence rows. No new start, restore, certify, publish, export, or customer-output action.
  • Surface budget result: existing surface budget only; no new page, action family, dashboard, or navigation.
  • Technical Annex / deep-link demotion: raw payloads, normalized payloads, source keys, OperationRun proof, identity diagnostics, permission context, source endpoints, and provider IDs remain technical/internal detail and must not become default customer proof.
  • Canonical status vocabulary: Product-facing labels, if any render, must map to existing canonical language such as Blocked, Running, Failed, Unknown, or internal Coverage v2 state labels already used by Spec 418. Do not introduce page-local "M365 covered", "certified", "restore-ready", or "customer-ready" labels.
  • Visible complexity impact: neutral to slightly broader on the existing internal evidence surface; no new surface family.
  • Product Surface exceptions: none.

Browser Verification Plan (mandatory)

  • Browser proof required?: yes, if implementation-created M365 resource/evidence rows or blocked outcomes render on the existing Coverage v2 operator surface.
  • No-browser rationale: N/A - no rendered UI surface changed only if implementation proves no rendered output changes despite runtime capture support.
  • Focused path when required: existing Spec 418 Coverage v2 readiness/operator route.
  • Primary interaction to execute: load the existing page with a fake captured conditionalAccessPolicy row and blocked selected M365 types, inspect the relevant table/slide-over path, and verify internal-only wording, no broad claim, no raw payload, no capture/restore/certify/customer-output action.
  • Console, Livewire, Filament, network, and 500-error checks: required for focused path when rendered data changes.
  • Full-suite failure triage: unrelated browser/full-suite failures may be documented only after focused proof is green.

Human Product Sanity Check (mandatory)

  • Required?: yes, if existing operator surface rendering changes.
  • No-human-sanity rationale: N/A only when no rendered product surface changes.
  • Reviewer questions: Is it clear this is internal generic evidence, not M365 coverage completion? Are missing source contracts visibly blocked without looking like failures operators can "fix" with restore/certify actions? Are raw technical details demoted?
  • Planned result location: implementation report for Spec 420.

Product Surface Merge Gate Checklist (mandatory)

  • No-legacy posture or approved exception recorded.
  • Product Surface Impact is filled in for data-driven existing-surface impact.
  • Browser proof is required if rendered Coverage v2 output changes, or N/A - no rendered UI surface changed must be justified.
  • Human Product Sanity is required if rendered Coverage v2 output changes, or N/A must be justified.
  • Product Surface exceptions are documented as 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 historical-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 at domain-contract level; no new UI interaction family.
  • Interaction class(es): evidence capture status, OperationRun-backed operation lifecycle, internal Coverage v2 evidence inspection.
  • Systems touched: CoverageSourceContractResolver, GenericContentEvidenceCaptureService, CoverageResourceUpserter, CoverageEvidenceWriter, GenericPayloadNormalizer, CoveragePayloadRedactor, CanonicalIdentityResolver, ClaimGuard, StartTenantConfigurationCapture, existing OperationRun/audit paths, and existing Coverage v2 operator read model if rendered.
  • Existing pattern(s) to extend: existing Coverage v2 generic capture/evidence/identity/claim services.
  • Shared contract / presenter / builder / renderer to reuse: existing OperationRun lifecycle service, capture job/service, resource/evidence writer, identity strategy registry, Claim Guard, and existing Coverage v2 operator read model. Do not add local workload-specific engines.
  • Why the existing shared path is sufficient or insufficient: Existing generic capture already handles source resolution, fakeable provider calls, normalization, hashing, evidence persistence, OperationRun summary, and same-scope provider validation. It is sufficient for the first M365 slice when contract mappings and identity strategies are added narrowly.
  • Allowed deviation and why: none by default. Any source-contract metadata addition must remain local to the generic resolver/registry.
  • Consistency impact: M365 capture must use the same Coverage v2 evidence states, capture outcomes, identity states, claim states, OperationRun summary keys, RBAC semantics, and redaction rules as Intune capture.
  • Review focus: Verify no Entra/Exchange/Teams/Security mini-platform, no direct Graph endpoint guessing, no raw payload leak, no customer claim activation, and no historical-spec rewrite.
  • Touches OperationRun start/completion/link UX?: yes for backend capture lifecycle; no new UI start/link semantics.
  • Shared OperationRun UX contract/layer reused: existing OperationRunService, OperationRunType::TenantConfigurationCapture, existing queued job path, and central terminal notification lifecycle.
  • Delegated start/completion UX behaviors: no new UI toast/link/browser event. Any existing OperationRun link rendered by Spec 418 remains secondary diagnostic only and must respect Gate::allows('view', $run).
  • Local surface-owned behavior that remains: none; no start surface is added.
  • Queued DB-notification policy: no new queued DB notification opt-in.
  • Terminal notification path: existing central lifecycle mechanism for OperationRun.
  • Exception required?: none. Reuse tenant_configuration.capture; do not introduce tenant_configuration.m365_capture unless a separate OperationRun type passes proportionality review.

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. Generic Coverage v2 capture/evidence/identity is platform-core; Microsoft workload names and Graph/TCM contract metadata are provider-owned.
  • Seams affected: source contract mapping, provider gateway list path, canonical resource type identity strategy, permission context metadata, source metadata, workload labels, and Claim Guard statements.
  • Neutral platform terms preserved or introduced: provider connection, managed environment, resource type, source contract, coverage level, evidence state, capture outcome, identity state, claim state, OperationRun, permission context.
  • Provider-specific semantics retained and why: Microsoft Graph/TCM names remain because this spec is explicitly M365 evidence capture. They must stay in source metadata/contract config and must not become platform ownership keys.
  • Why this does not deepen provider coupling accidentally: No new provider framework, no tenant_id, no provider-native ID routing, no workload-specific tables/services, no UI dashboard, and no customer claims are introduced.
  • Follow-up path: compare/render/certified packs must be separate specs after evidence truth exists.

UI / Surface Guardrail Impact (mandatory when operator-facing surfaces are changed; otherwise write N/A)

Existing Spec 418 Coverage v2 operator surfaces may show new M365 resource/evidence rows through existing data queries. No new route, page, navigation, action, table/form definition, Blade view, Livewire component, Filament provider, customer surface, report, or download is in scope.

Decision-First Surface Role (mandatory when operator-facing surfaces are changed)

The existing surface remains an internal technical/evidence inspection surface. New data must answer "captured generic evidence or blocked missing contract" rather than implying M365 coverage completion, readiness, certification, customer proof, or restore support.

Audience-Aware Disclosure (mandatory when operator-facing surfaces are changed)

Internal/operator only. Raw payloads, normalized payloads, permission context, provider IDs, OperationRun proof, and source metadata are technical diagnostics and must be hidden or secondary on existing surfaces. Customer/read-only output is out of scope.

UI/UX Surface Classification (mandatory when operator-facing surfaces are changed)

Existing page, data-only impact. No new page archetype, action family, primary navigation, modal type, wizard, dashboard, or customer surface is introduced.

Operator Surface Contract (mandatory when operator-facing surfaces are changed)

The existing Coverage v2 operator surface must remain read-only and claim-safe: no capture/start, restore/apply, certify, publish, export, report/download, or customer-output action; raw evidence hidden by default; OperationRun links secondary and authorized.

Proportionality Review (mandatory when structural complexity is introduced)

  • New source of truth?: no. TenantConfigurationResource and TenantConfigurationResourceEvidence remain existing Coverage v2 resource/evidence truth.
  • New persisted entity/table/artifact?: no new table by default. Existing rows are created during runtime capture.
  • New abstraction?: no new abstraction by default. Existing resolver, capture service, identity registry, redactor, writer, and Claim Guard are extended.
  • New enum/state/reason family?: no new enum/status family by default. Use existing capture outcomes and stable reason codes.
  • New cross-domain UI framework/taxonomy?: no.
  • Current operator problem: M365 registry rows lack real generic evidence and can otherwise be over-read as future coverage truth.
  • Existing structure is insufficient because: existing structures support generic capture but currently map only initial Intune contract keys and identity strategies; they need narrow M365 entries to exercise the generic path.
  • Narrowest correct implementation: one enabled contract-backed capture path plus three blocked missing-contract paths across workloads.
  • Ownership cost: focused tests and maintenance of source-contract mappings, identity strategies, and Claim Guard assertions for the selected first pack.
  • Alternative intentionally rejected: building Entra/Exchange/Teams/Security-specific engines or dashboards; claiming content-backed coverage for missing contracts; adding a new OperationRun type without distinct lifecycle behavior.
  • Release truth: current-release trust and evidence foundation for later M365 packs.

Compatibility posture

This feature assumes a pre-production environment. Backward compatibility, legacy aliases, migration shims, historical fixtures, and compatibility-specific tests are out of scope unless explicitly required by this spec.

Testing / Lane / Runtime Impact (mandatory for runtime behavior changes)

  • Test purpose / classification: Unit for resolver/normalizer/redaction/identity/Claim Guard; Feature for capture persistence, OperationRun, authorization, provider scope, no-overclaim, no-tenant-id, no-mini-platform; Browser only if rendered existing surface changes.
  • Validation lane(s): fast-feedback, confidence, PostgreSQL lane if migrations/check constraints change, focused browser if existing Coverage v2 surface renders new M365 capture data.
  • Why this classification and these lanes are sufficient: The change is backend capture/evidence behavior with possible data-driven existing-surface rendering. Unit and feature tests prove the behavior; browser is only needed for rendered UI impact.
  • New or expanded test families: focused Spec 420 TenantConfiguration tests only; no broad heavy-governance family.
  • Fixture / helper cost impact: fake provider responses only; keep workspace/managed-environment/provider setup local to tests.
  • Heavy-family visibility / justification: none unless focused browser proof is required for rendered output.
  • Special surface test profile: existing technical/evidence surface profile if browser proof is needed.
  • Standard-native relief or required special coverage: no Filament runtime UI code edits are planned.
  • Reviewer handoff: verify lane fit, no real Microsoft calls, no raw payload leak, same-scope provider proof, and no customer claims.
  • Budget / baseline / trend impact: none expected.
  • Escalation needed: document-in-feature for contained source-contract/identity expansion; follow-up-spec for compare/render/certification/UI/customer output.
  • Active feature PR close-out entry: Guardrail / Exception / Smoke Coverage.
  • Planned validation commands:
    • cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent
    • cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/TenantConfiguration/Spec420M365CaptureSourceContractResolverTest.php tests/Unit/Support/TenantConfiguration/Spec420M365CaptureEligibilityTest.php tests/Unit/Support/TenantConfiguration/Spec420M365GenericPayloadNormalizerTest.php tests/Unit/Support/TenantConfiguration/Spec420M365CaptureIdentityStrategyTest.php tests/Unit/Support/TenantConfiguration/Spec420M365CaptureClaimGuardTest.php tests/Unit/Support/TenantConfiguration/Spec420M365CaptureRedactionTest.php
    • cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/TenantConfiguration/Spec420M365GenericEvidenceCaptureTest.php tests/Feature/TenantConfiguration/Spec420M365CaptureOperationRunTest.php tests/Feature/TenantConfiguration/Spec420M365CaptureAuthorizationTest.php tests/Feature/TenantConfiguration/Spec420M365ProviderConnectionScopeTest.php tests/Feature/TenantConfiguration/Spec420M365NoOverclaimTest.php tests/Feature/TenantConfiguration/Spec420M365NoLegacyTest.php tests/Feature/TenantConfiguration/Spec420M365NoTenantIdTest.php
    • cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec420M365GenericEvidenceOperatorSurfaceSmokeTest.php if existing rendered Coverage v2 output changes
    • git diff --check

User Scenarios & Testing (mandatory)

User Story 1 - Capture One Contract-Backed M365 Resource Type (Priority: P1)

As an authorized operator, I need the generic evidence path to persist real content-backed evidence for at least one selected M365 resource type so M365 readiness is based on payload truth, not registry metadata.

Independent Test: Fake provider capture for conditionalAccessPolicy persists a concrete Coverage v2 resource and append-only evidence row with raw payload, normalized payload, deterministic hash, source metadata, provider connection scope, identity, and OperationRun link.

Acceptance Scenarios:

  1. Given a same-scope workspace, managed environment, provider connection, authorized operator, and fake provider response for conditionalAccessPolicy, When generic capture runs for that type, Then one TenantConfigurationResource row and one append-only evidence row are persisted with content_backed evidence state and a deterministic payload hash.
  2. Given the provider response contains volatile fields, When payload normalization runs twice, Then normalized payload and payload hash remain deterministic.
  3. Given the payload contains known secret keys, When evidence metadata, permission context, OperationRun context, audit metadata, and logs are inspected by tests, Then secrets are absent outside the evidence raw payload storage boundary.

User Story 2 - Block Missing M365 Source Contracts Safely (Priority: P1)

As a platform reviewer, I need selected Exchange, Teams, and Security/Compliance resource types to fail safe when source contracts are missing so TenantPilot never guesses endpoints or fakes capture.

Independent Test: Capture attempts for acceptedDomain, appPermissionPolicy, and dlpCompliancePolicy produce capture_blocked_missing_contract outcomes with stable reason codes and no evidence rows. Adding explicit contracts for these three types is out of scope for Spec 420 and requires an amended package or follow-up spec.

Acceptance Scenarios:

  1. Given acceptedDomain has no approved source contract mapping, When capture is requested, Then the outcome is capture_blocked_missing_contract, OperationRun summary counts reflect a blocked/skipped item, and no evidence row is created.
  2. Given appPermissionPolicy has no approved source contract mapping, When capture is requested, Then the provider gateway is not called.
  3. Given dlpCompliancePolicy has no approved source contract mapping, When capture is requested, Then no Graph endpoint is guessed from the resource type string or alias metadata.

User Story 3 - Preserve Identity, Scope, RBAC, And Claim Safety (Priority: P1)

As a security reviewer, I need M365 generic evidence to enforce workspace/provider scope, canonical identity, RBAC, and Claim Guard boundaries before any customer-facing claim can exist.

Independent Test: Authorization, provider scope, identity strategy, identity conflict, and claim guard tests prove allowed/denied behavior and no M365 customer claim activation.

Acceptance Scenarios:

  1. Given a non-member or actor without managed environment entitlement, When capture is requested, Then the request denies as not found (404).
  2. Given a workspace member without capture capability or a readonly user, When capture is requested, Then the request fails with 403 and no OperationRun is queued.
  3. Given a provider connection from another workspace or managed environment, When capture is requested or the job handles the run, Then the operation fails closed before provider work.
  4. Given identity resolution cannot create stable identity for a selected type, When capture persists or attempts to persist a resource, Then identity state and Claim Guard block customer-facing claims.

User Story 4 - Keep Product Surface Internal And No-Overclaim (Priority: P1)

As a product reviewer, I need any existing operator-surface rendering to remain internal, technical, and clear that generic evidence is not comparable, renderable, restorable, certified, or customer-ready.

Independent Test: If captured/blocked M365 data renders on the existing Spec 418 surface, focused browser proof verifies no broad M365 claims, no raw payload, and no new action affordances.

Acceptance Scenarios:

  1. Given captured conditionalAccessPolicy evidence exists, When the existing Coverage v2 operator surface renders it, Then the surface uses internal generic evidence wording and does not say "M365 covered", "certified", "restore-ready", or "customer-ready".
  2. Given blocked missing-contract outcomes exist, When they render on the existing surface, Then they appear as internal blockers, not as failed customer evidence or actionable restore/certify steps.
  3. Given no runtime UI files were changed, When implementation closes out, Then browser proof is provided only for data-driven rendered impact or explicitly marked N/A with proof.

Functional Requirements (mandatory)

  • FR-420-001: The implementation MUST use existing Coverage v2 resource/evidence tables and MUST NOT add new M365-specific tables.
  • FR-420-002: The selected first pack MUST include conditionalAccessPolicy, acceptedDomain, appPermissionPolicy, and dlpCompliancePolicy.
  • FR-420-003: conditionalAccessPolicy MUST become capture-enabled through an explicit repo-real source contract mapping when the current contract remains valid for generic read capture. If that contract is missing or unsafe, implementation MUST stop and amend this package instead of silently dropping the enabled path. It MUST NOT be captured by endpoint guessing.
  • FR-420-004: acceptedDomain, appPermissionPolicy, and dlpCompliancePolicy MUST remain capture_blocked_missing_contract blockers in Spec 420. Adding explicit contracts for those three types is out of scope and requires an amended package or follow-up spec.
  • FR-420-005: All provider calls MUST go through GraphClientInterface via existing provider gateway/contract paths.
  • FR-420-006: Runtime code MUST NOT scrape Microsoft Learn, hardcode quick endpoints, use direct HTTP clients, bypass Graph contracts, or derive runtime endpoint paths from resource type strings/aliases.
  • FR-420-007: Captured resources MUST persist workspace_id, managed_environment_id, provider_connection_id, resource_type_id, canonical identity fields, and source metadata through existing Coverage v2 models.
  • FR-420-008: Evidence rows MUST be append-only and persist raw payload, normalized payload, deterministic payload hash, source contract metadata, source version/schema hash when available, redacted permission context, and operation_run_id. If source version or schema hash is unavailable, evidence metadata MUST record an explicit null/unknown value and capture MUST NOT be blocked solely for that absence.
  • FR-420-009: Capture MUST create or reuse an OperationRun using existing tenant_configuration.capture semantics unless implementation adds a distinct operation type with proportionality proof and tests.
  • FR-420-010: OperationRun status/outcome transitions MUST go through OperationRunService.
  • FR-420-011: OperationRun summary_counts MUST remain flat numeric-only and limited to existing OperationSummaryKeys.
  • FR-420-012: OperationRun context, messages, notifications, audit metadata, and logs MUST NOT contain raw payloads, secrets, tokens, credential material, cookies, bearer headers, or raw provider error bodies.
  • FR-420-013: Capture MUST be asynchronous and fake-provider-testable. No real Microsoft Graph, TCM, Exchange, Teams, Purview, Defender, or Security/Compliance calls are allowed in tests.
  • FR-420-014: Server-side authorization MUST enforce non-member/not-entitled 404, missing capability 403, and readonly cannot start capture.
  • FR-420-015: Provider connections MUST be same-workspace and same-managed-environment before OperationRun creation and again at job execution time.
  • FR-420-016: Canonical identity strategies MUST be added or confirmed for selected resource types. Display-name-only identity MUST NOT be stable.
  • FR-420-017: Identity conflicts, missing external IDs, unsupported identity, and derived identity without allowed claims MUST block customer-facing claims.
  • FR-420-018: Claim Guard MUST block broad M365, certified, restore-ready, complete tenant, all-resource, customer-ready proof, and unscoped 100% claims.
  • FR-420-019: Captured generic evidence MUST NOT imply comparable, renderable, restorable, certified, or customer-ready status.
  • FR-420-020: Existing Spec 419 registry-only defaults MUST not be silently changed into broad M365 support/certification.
  • FR-420-021: No tenant_id may be introduced as Coverage v2 internal ownership truth.
  • FR-420-022: No v1-to-v2 adapter, fallback reader, dual write, legacy gap taxonomy, old snapshot promotion, or compatibility shim may be introduced.
  • FR-420-023: No new runtime UI start action, navigation entry, M365 dashboard, customer report, Review Pack output, restore/certify action, or download route may be added.
  • FR-420-024: If existing operator surfaces render new captured/blocked M365 data, focused browser proof and Human Product Sanity are required.
  • FR-420-025: Implementation report MUST include capture eligibility, evidence, source-contract, OperationRun, authorization, provider-scope, redaction/logging, Claim Guard, no-tenant-id, no-legacy, Product Surface, test, and deployment proof.

Non-Functional Requirements (mandatory)

  • NFR-420-001: Capture must be deterministic, idempotent where possible, and safe to retry without duplicate active runs or unbounded duplicate resource rows.
  • NFR-420-002: Normalization and hashing must be stable across key order and configured volatile fields.
  • NFR-420-003: Missing contracts must be fast, local, and fail closed before any provider call.
  • NFR-420-004: Tests must remain focused and must not broaden shared workspace/provider fixtures by default.
  • NFR-420-005: Any migration/check-constraint change must be reversible where practical and include PostgreSQL lane coverage.
  • NFR-420-006: Queue deployment impact must be documented because capture is OperationRun/job backed.
  • NFR-420-007: Existing rendered surfaces must not expose raw payloads, provider response bodies, secrets, or internal claim proof by default.

Key Entities (include if feature involves data)

  • TenantConfigurationResourceType: Existing registry definition for selected resource types.
  • TenantConfigurationResource: Existing concrete environment-owned captured resource row.
  • TenantConfigurationResourceEvidence: Existing append-only evidence payload row.
  • ProviderConnection: Existing provider provenance and credential/readiness scope; must belong to the same workspace and managed environment.
  • OperationRun: Existing execution truth for queued capture.
  • CoverageSourceContractResolver: Existing source contract resolver to extend with explicit selected M365 contract decisions.
  • GenericContentEvidenceCaptureService: Existing capture orchestrator to reuse.
  • CoverageResourceUpserter / CoverageEvidenceWriter: Existing persistence services to reuse.
  • CanonicalIdentityResolver / CoverageIdentityStrategyRegistry: Existing identity engine to extend for selected M365 resource types.
  • ClaimGuard: Existing safety gate for coverage/restore/certification/customer claims.

Acceptance Criteria (mandatory)

  • AC-420-001: conditionalAccessPolicy capture with a fake provider response persists concrete resource and evidence rows with raw/normalized payloads and deterministic payload hash.
  • AC-420-002: Evidence links to the same-scope provider connection and OperationRun.
  • AC-420-003: acceptedDomain, appPermissionPolicy, and dlpCompliancePolicy block with capture_blocked_missing_contract for Spec 420.
  • AC-420-004: Missing-contract types do not call provider gateway/Graph and do not create fake evidence rows.
  • AC-420-005: Source metadata records source contract key, endpoint, source version/schema hash when known, explicit null/unknown values when source version/schema hash is unavailable, and does not overclaim TCM/Graph source truth.
  • AC-420-006: Canonical identity resolver is used; display-name-only stable identity is impossible.
  • AC-420-007: Non-member and no-entitlement actors receive 404; established members without capture capability receive 403; readonly cannot start capture.
  • AC-420-008: Cross-workspace or cross-environment provider connections are rejected before run creation and before job provider work.
  • AC-420-009: OperationRun lifecycle uses OperationRunService, numeric summary counts, sanitized messages, and no raw payload/secrets.
  • AC-420-010: Claim Guard blocks broad M365, certified, restore-ready, customer-ready, complete tenant, all-resource, and unscoped 100% claims.
  • AC-420-011: No tenant_id, old gap taxonomy, v1 adapter, fallback reader, dual write, old snapshot promotion, or workload-specific mini-platform appears.
  • AC-420-012: No UI start action, customer output, report, dashboard, restore/certify/publish/export action, or new navigation appears.
  • AC-420-013: Focused unit/feature tests pass; focused browser proof passes when rendered existing-surface data changes; git diff --check passes.

Success Criteria (mandatory)

  • SC-420-001: Implementation report includes a capture eligibility matrix for the four selected resource types.
  • SC-420-002: Implementation report includes an evidence matrix showing captured, blocked, identity, and claim states.
  • SC-420-003: Tests prove one enabled fake-provider capture path and at least three structured missing-contract blockers.
  • SC-420-004: Tests prove RBAC, provider scope, OperationRun, redaction, no-overclaim, no-tenant-id, no-legacy, and no-mini-platform boundaries.
  • SC-420-005: Product Surface proof records either focused existing-surface browser/Human Product Sanity results or exact N/A proof.

Assumptions

  • Specs 414, 415, 417, 418, and 419 remain read-only dependency context.
  • Existing config/graph_contracts.php contains a conditionalAccessPolicy contract, but CoverageSourceContractResolver does not yet map it for generic capture. Implementation must verify the contract remains valid before enabling capture.
  • The first pack intentionally proves missing-contract blockers for non-Entra workloads rather than inventing Exchange, Teams, or Security/Compliance endpoint contracts.
  • Existing tenant_configuration.capture operation semantics are sufficient for selected M365 capture because the execution lifecycle is the same generic capture workflow.
  • Existing Spec 418 operator surfaces may render M365 resource/evidence rows if data exists; no UI code edits are planned.

Open Questions

None blocking. Implementation must record these bounded decisions in the implementation report:

  1. Whether conditionalAccessPolicy uses the existing graph_contracts.types.conditionalAccessPolicy as-is or needs a narrow contract metadata adjustment.
  2. Whether source metadata needs an additional non-persisted/detail key to distinguish TCM-documented registry rows from actual Graph fallback execution without changing registry ownership truth.
  3. Whether focused browser proof is required because captured/blocked M365 rows render on the existing Coverage v2 surface.

Risks

Risk Severity Mitigation
Capture becomes broad M365 claim High Claim Guard tests, internal-only wording, no customer output
Endpoint guessing High explicit resolver mappings only, missing-contract blockers
Raw payload or secrets leak High redaction tests, OperationRun/audit/log guards
Source-class confusion Medium source metadata proof and implementation-report matrix
Cross-provider leakage High same-scope provider checks before run and job provider work
Identity instability High identity strategies and conflict tests
OperationRun status bypass High OperationRunService tests/static guard
UI activation sneaks in Medium no new UI scope, Product Surface stop condition
Workload mini-platforms appear High guard tests against workload-specific tables/classes/services
Test scope grows too broad Medium fake providers, focused unit/feature/browser-if-rendered lanes

Follow-Up Spec Candidates

  • Entra Core Comparable/Renderable Pack.
  • Exchange and Teams Comparable Pack.
  • Security and Compliance Readiness Pack.
  • Entra Certified Compare Pack.
  • Exchange/Teams Certified Pack.
  • Security and Compliance Compare Pack.
  • Customer-facing M365 coverage/reporting only after evidence, compare/render, and certification truth exists.