Committing and publishing the current Spec 420 package changes. Includes updated services, coverage tests, browser smoke coverage, and the spec/plan/tasks artifacts for the package. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #487
19 KiB
Implementation Plan: Spec 420 - M365 Generic Evidence Coverage Pack
Branch: 420-m365-generic-evidence-coverage-pack | Date: 2026-06-27 | Spec: specs/420-m365-generic-evidence-coverage-pack/spec.md
Input: Feature specification from /specs/420-m365-generic-evidence-coverage-pack/spec.md
Summary
Extend the existing Coverage v2 generic capture path to a bounded M365 first pack. The implementation should enable one explicit contract-backed content capture path for conditionalAccessPolicy, prove missing-contract blockers for acceptedDomain, appPermissionPolicy, and dlpCompliancePolicy, and preserve workspace/managed-environment/provider scope, OperationRun lifecycle, canonical identity, redaction, and Claim Guard boundaries. No compare/render/restore/certification/customer output, new UI start action, M365 dashboard, or workload-specific mini-platform is in scope.
Technical Context
Language/Version: PHP 8.4.x, Laravel 12.x
Primary Dependencies: existing TenantConfiguration Coverage v2 models/services/enums, GraphClientInterface, provider gateway, OperationRunService, Pest 4, PostgreSQL via Sail
Storage: Existing tenant_configuration_resources and tenant_configuration_resource_evidence for concrete resource/evidence rows; existing registry tables from Specs 414/419. No new table by default.
Testing: Pest 4 / PHPUnit 12 via Sail; all provider calls faked.
Validation Lanes: fast-feedback, confidence, PostgreSQL lane if migrations/check constraints change, focused browser if existing Coverage v2 surface renders new captured/blocked M365 data.
Target Platform: Laravel Sail locally, Dokploy/container deployment for staging/production.
Project Type: Laravel monolith under apps/platform.
Performance Goals: no provider call for missing contracts, async capture for enabled contract, deterministic normalization/hash, no render-time Graph calls.
Constraints: no direct HTTP, no endpoint guessing, no customer claims, no tenant_id, no UI start action, no new dashboard/report/download, no workload-specific engines/tables/classes.
UI / Surface Guardrail Plan
- Guardrail scope: no runtime UI files, routes, navigation, Filament providers, actions, reports, downloads, or customer output are planned.
- Affected routes/pages/actions/states/navigation/panel/provider surfaces: existing Spec 418 Coverage v2 operator surface may show data-driven captured/blocked M365 resource/evidence rows.
- No-impact class, if applicable: not applicable if captured/blocked rows render. Implementation must explicitly choose one close-out path: focused browser/Human Product Sanity when rendered output changes, or
N/A - no rendered UI surface changedwith exact proof when it does not. - Native vs custom classification summary: no custom UI.
- Shared-family relevance: no new UI shared-family path.
- State layers in scope: backend capture outcomes, evidence rows, identity state, claim state, OperationRun state; existing rendered data only if already queried.
- Audience modes in scope: internal operator only.
- Decision/diagnostic/raw hierarchy plan: default product views must not expose raw payloads, provider responses, OperationRun internals, source keys, permission context, identity diagnostics, or customer-proof claims.
- Raw/support gating plan: raw payload remains in evidence storage only; existing UI must not render it by default.
- One-primary-action / duplicate-truth control: no new actions.
- Handling modes by drift class or surface: hard stop if runtime UI code, route, navigation, action, report/download, or customer surface is needed.
- Repository-signal treatment: no UI audit registry update unless implementation amends scope to runtime UI files.
- Special surface test profiles: existing technical/evidence operator surface if browser proof is required.
- Required tests or manual smoke: focused browser proof when existing rendered output changes.
- Exception path and spread control: none.
- Active feature PR close-out entry: Guardrail / Exception / Smoke Coverage.
- UI/Productization coverage decision: existing internal operator data impact only.
- Coverage artifacts to update: active Spec 420 artifacts and implementation report only. Do not rewrite Specs 414/415/417/418/419.
- No-impact rationale: no runtime UI file is planned, but data-driven rendered impact is possible.
- Navigation / Filament provider-panel handling: no panel/provider registration change.
- Screenshot or page-report need: focused browser proof screenshot only if existing rendered output changes.
Product Surface Contract Plan
- Product Surface Contract reference:
docs/product/standards/product-surface-contract.md. - No-legacy posture: canonical Coverage v2 generic capture extension; no compatibility exception.
- Page archetype and surface budget plan: existing internal/operator Technical Annex / evidence inspection surface only.
- Technical Annex and deep-link demotion plan: OperationRun links, raw/normalized payloads, source contract metadata, provider IDs, identity diagnostics, and permission context stay secondary/internal.
- Canonical status vocabulary plan: use existing Coverage v2 internal state labels and product canonical labels if rendered. No
M365 covered,certified,restore-ready, orcustomer-readywording. - Product Surface exceptions: none.
- Browser verification plan: focused existing-surface proof if captured/blocked M365 data renders.
- Human Product Sanity plan: required only when rendered output changes.
- Visible complexity outcome target: neutral; no new surface family.
- Implementation report target:
specs/420-m365-generic-evidence-coverage-pack/implementation-report.md.
Filament / Livewire / Deployment Posture
- Livewire v4 compliance: Livewire v4.x remains required. No Livewire code is planned.
- Panel provider registration location: Laravel 12 panel providers remain in
apps/platform/bootstrap/providers.php; no panel/provider change is planned. - Global search posture: no Filament Resource changes. If a Resource is unexpectedly added, stop and amend the spec.
- Destructive/high-impact action posture: no UI action. Backend capture start remains high-impact and must be server-authorized, audited, queued, and OperationRun-backed through existing service paths.
- Asset strategy: no assets.
filament:assetsnot required unless scope is amended to register assets. - Testing plan: focused unit and feature tests; focused browser only if existing rendered Coverage v2 output changes.
- Deployment impact: queue worker required for capture job; possible config/code only by default; migrations only if implementation proves schema/check constraints need updates. No env vars, scheduler, storage, or assets expected.
Shared Pattern & System Fit
- Cross-cutting feature marker: yes at evidence/operation/provider-contract level; no new UI interaction family.
- Systems touched:
CoverageSourceContractResolver,CoverageSourceContractDecision,GenericContentEvidenceCaptureService,CoverageResourceUpserter,CoverageEvidenceWriter,GenericPayloadNormalizer,CoveragePayloadRedactor,CoverageCaptureOutcomeSummarizer,CoverageIdentityStrategyRegistry,CanonicalIdentityResolver,ClaimGuard,StartTenantConfigurationCapture,CaptureTenantConfigurationEvidenceJob,OperationRunService, and existing tests. - Shared abstractions reused: existing Coverage v2 registry, source resolver, capture service, identity registry, evidence writer, Claim Guard, OperationRun lifecycle, provider gateway.
- New abstraction introduced? why?: none by default. A small local mapping in existing resolver/identity registry is preferred over new M365-specific classes.
- Why the existing abstraction was sufficient or insufficient: The existing generic capture stack already handles the hard parts; it lacks selected M365 contract/identity mappings.
- Bounded deviation / spread control: no
EntraEvidenceEngine,ExchangeEvidenceEngine,TeamsEvidenceEngine,SecurityComplianceEvidenceEngine, new dashboard, or separate table family.
OperationRun UX Impact
- Touches OperationRun start/completion/link UX?: backend lifecycle yes; no new start/link UI.
- Central contract reused: existing
OperationRunService,OperationRunType::TenantConfigurationCapture,CaptureTenantConfigurationEvidenceJob, and terminal notification lifecycle. - Delegated UX behaviors: no new toast/link/browser event. Existing diagnostic links remain secondary and authorized if rendered.
- Surface-owned behavior kept local: none.
- Queued DB-notification policy: no new queued DB notification opt-in.
- Terminal notification path: central lifecycle mechanism.
- Exception path: none. Do not add
tenant_configuration.m365_captureunless a distinct lifecycle/operator consequence is proven.
Provider Boundary & Portability Fit
- Shared provider/platform boundary touched?: yes.
- Provider-owned seams: Microsoft Graph/TCM source names, source contract keys, endpoint paths, source aliases, permission context, provider IDs in metadata.
- Platform-core seams: resource/evidence persistence, capture outcomes, coverage/evidence/identity/claim states, OperationRun, RBAC, redaction.
- Neutral platform terms / contracts preserved: provider connection, managed environment, resource type, source contract, evidence, identity, claim, operation.
- Retained provider-specific semantics and why: selected M365 canonical type names and Graph contract keys are necessary provider-owned source metadata for this M365 pack.
- Bounded extraction or follow-up path: document-in-feature for source/identity mapping; follow-up-spec for compare/render/certification/customer output.
Constitution Check
- Inventory/evidence truth: PASS. Real evidence rows are created only for real payload capture; missing contracts do not create fake evidence.
- Read/write separation: PASS. Capture is read-only provider work and queued; no restore/apply/write to Microsoft.
- Graph contract path: PASS if implementation uses explicit
GraphClientInterface/provider gateway contracts only. - Deterministic capabilities: PASS. Capture eligibility and claim behavior are testable.
- RBAC-UX: PASS with required 404/403 semantics and readonly denial.
- Workspace isolation: PASS with same-scope workspace/managed-environment/provider checks before run creation and job work.
- OperationRun: PASS with existing
tenant_configuration.captureand service-owned lifecycle. - Evidence/currentness: PASS. Evidence payload truth is distinct from OperationRun execution truth.
- Customer output: PASS. No customer output or customer-safe claim.
- Provider boundary: PASS if provider-native IDs remain metadata only.
- Product Surface: PASS with existing-surface data-impact proof if rendered.
- Test governance: PASS. Unit/Feature/Browser-if-rendered lanes are named.
- Proportionality: PASS. No new tables/status families/frameworks by default; extension is bounded to selected resource types.
- No premature abstraction: PASS if existing services are extended.
- Persisted truth: PASS. Existing durable resource/evidence tables are product truth for observed configuration.
- Behavioral state: PASS using existing outcome/state families.
- No legacy / pre-production lean: PASS. No compatibility path, v1 adapter, fallback reader, dual write, or
tenant_id.
Test Governance Check
- Test purpose / classification by changed surface: Unit for pure resolver/identity/redaction/claim behavior; Feature for persistence, authorization, OperationRun, provider scope, no-overclaim/no-legacy; Browser if existing UI renders new data.
- Affected validation lanes: fast-feedback, confidence, PostgreSQL if schema changes, browser if rendered.
- Why this lane mix is the narrowest sufficient proof: Runtime behavior is service/job/evidence based; browser is only required for actual rendered output.
- Narrowest proving command(s):
cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agentcd 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.phpcd 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.phpcd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec420M365GenericEvidenceOperatorSurfaceSmokeTest.phpif existing rendered output changesgit diff --check
- Fixture / helper / factory / seed / context cost risks: keep fake M365 provider responses local to Spec 420 tests.
- Expensive defaults or shared helper growth introduced?: none expected.
- Heavy-family additions, promotions, or visibility changes: no heavy-governance family; focused browser only when rendered.
- Surface-class relief / special coverage rule: no UI code change; browser may be N/A with proof.
- Closing validation and reviewer handoff: implementation report records matrices, tests, no-claim/no-leak/no-scope proof, browser/N/A proof, deployment impact.
- Budget / baseline / trend follow-up: none expected.
- Review-stop questions: endpoint guessing, raw leak, provider scope, identity stability, broad claim, no UI scope, no historical-spec rewrite.
- Escalation path: document-in-feature for contained mapping choices; follow-up-spec for broad packs.
- Active feature PR close-out entry: Guardrail / Exception / Smoke Coverage.
- Why no dedicated follow-up spec is needed: this is the narrow first M365 generic evidence slice; later semantic packs are listed separately.
Project Structure
Documentation (this feature)
specs/420-m365-generic-evidence-coverage-pack/
+-- spec.md
+-- plan.md
+-- tasks.md
+-- checklists/
+-- requirements.md
Source Code (likely affected in later implementation)
apps/platform/app/
+-- Services/TenantConfiguration/
| +-- CoverageSourceContractResolver.php
| +-- GenericContentEvidenceCaptureService.php
| +-- CoverageCaptureOutcomeSummarizer.php
| +-- CoverageResourceUpserter.php
| +-- CoverageEvidenceWriter.php
| +-- CoverageIdentityStrategyRegistry.php
| +-- GenericPayloadNormalizer.php
| +-- CoveragePayloadRedactor.php
| +-- ClaimGuard.php
+-- Jobs/TenantConfiguration/
| +-- CaptureTenantConfigurationEvidenceJob.php
+-- Support/
+-- OperationRunType.php only if a distinct operation type is approved
apps/platform/config/
+-- graph_contracts.php only if selected source contracts need narrow metadata adjustment
apps/platform/tests/
+-- Unit/Support/TenantConfiguration/
+-- Feature/TenantConfiguration/
+-- Browser/ only if existing rendered output changes
Structure Decision: Reuse existing Coverage v2 generic services and tests. Do not add workload-specific service namespaces, tables, dashboards, routes, or providers.
Implementation Phases
Phase 0 - Preflight
Capture branch, HEAD, dirty state, activated skills, related spec guardrail, and stop conditions. Confirm no unrelated dirty files before implementation. Re-read current resolver, registry, identity, claim, OperationRun, and Graph contract truth.
Phase 1 - Tests First: Source Contracts And Eligibility
Add tests proving conditionalAccessPolicy resolves through an explicit repo-real contract and selected missing-contract resource types block safely without provider calls or evidence rows. Include explicit retry/idempotency and duplicate active-run/resource-row protection.
Phase 2 - Tests First: Identity, Redaction, And Claims
Add tests for selected M365 identity strategies, no display-name-only stable identity, deterministic normalization/hash, redaction, and broad M365 claim blocking.
Phase 3 - Tests First: Persistence, OperationRun, RBAC, And Scope
Add feature tests for fake-provider capture persistence, append-only evidence, retry/idempotency, stale active-run/deduplication behavior, bounded duplicate resource/evidence behavior, same-scope provider connection enforcement, OperationRun lifecycle, authorization 404/403 behavior, readonly denial, no tenant_id, no legacy, and no mini-platform.
Phase 4 - Source Contract And Eligibility Implementation
Extend CoverageSourceContractResolver narrowly for the selected first pack. Use existing graph_contracts.php contract metadata for conditionalAccessPolicy if valid; if it is not valid, stop and amend the package. Leave acceptedDomain, appPermissionPolicy, and dlpCompliancePolicy as missing-contract blockers for Spec 420.
Phase 5 - Identity And Evidence Implementation
Add/confirm identity strategies, source metadata handling, evidence writing, normalization/redaction, and claim-state preservation for selected M365 resource types.
Phase 6 - OperationRun, Authorization, And Guardrails
Reuse StartTenantConfigurationCapture, CaptureTenantConfigurationEvidenceJob, OperationRunService, audit, and queued execution legitimacy paths. Add focused guards for no direct status writes, no raw payload context, no direct Graph calls, and no UI/customer output scope.
Phase 7 - Product Surface Data-Impact Verification
Confirm no UI route, page, navigation, provider, action, report, download, or customer output changed. If existing Coverage v2 surface renders captured/blocked M365 rows, run focused browser proof and Human Product Sanity. If runtime UI code changes are needed, stop and amend artifacts.
Phase 8 - Validation And Implementation Report
Run Pint dirty, focused unit/feature tests, PostgreSQL lane if required, browser if rendered, and git diff --check. Complete implementation report with matrices and required proof.
Rollout And Deployment Considerations
- Migrations: not expected; if added, validate on staging before production.
- Queue workers: required for capture job processing.
- Scheduler: no new scheduled job.
- Environment variables: none expected.
- Storage/volumes: no change.
- Assets: no change;
filament:assetsnot required. - Staging: validate fake/provider-safe tests and any rendered existing-surface proof before production promotion.
Risk Controls
- Stop if implementation requires endpoint guessing or direct HTTP.
- Stop if implementation requires a new UI start action, route, dashboard, report, restore/certify/export/download action, or customer output.
- Stop if
tenant_idappears as Coverage v2 ownership truth. - Stop if a new operation type, enum/status family, table, or abstraction is introduced without proportionality review.
- Stop if raw payloads, credentials, tokens, or provider response bodies enter OperationRun/audit/log/default UI.
- Stop if a broad M365/certified/restore-ready/customer-ready claim must be allowed.