TenantAtlas/specs/382-baseline-matching-canonicalization/tasks.md
ahmido 788efee1c2 feat(baselines): implement baseline matching canonicalization (#453)
Replaced legacy tenant and environment bindings in the BaselineDriftEngine with the new ProviderResourceIdentity framework as defined in Spec 382. This ensures cross-environment compatibility and deterministic baseline matching.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #453
2026-06-15 22:48:48 +00:00

14 KiB

Tasks: Spec 382 - Baseline Matching Pipeline and Canonicalization v1

Input: Design documents from /specs/382-baseline-matching-canonicalization/ Prerequisites: spec.md, plan.md, Spec 381 implementation close-out

Tests: Runtime behavior changes require Pest unit and feature tests before or alongside implementation. Browser tests are not required because this spec has no UI surface impact.

Test Governance Checklist

  • TGC001 Lane assignment is named and is the narrowest sufficient proof for the changed behavior.
  • TGC002 New or changed tests stay in the smallest honest family, and any heavy-governance or browser addition is explicit.
  • TGC003 Shared helpers, factories, seeds, fixtures, and context defaults stay cheap by default; any widening is isolated or documented.
  • TGC004 Planned validation commands cover the change without pulling in unrelated lane cost.
  • TGC005 The declared surface test profile or standard-native-filament relief is explicit.
  • TGC006 Any material budget, baseline, trend, or escalation note is recorded in the active spec or PR.

Phase 1: Preparation And Guardrails

Purpose: Protect completed-spec history and confirm the implementation slice before runtime changes.

  • T001 Confirm specs/381-provider-resource-identity-binding/implementation-close-out.md exists and treat Spec 381 as completed dependency context only.
  • T002 Confirm no code changes are made to specs/163-baseline-subject-resolution/, specs/380-management-report-pdf-staging-runtime-validation/, or specs/381-provider-resource-identity-binding/.
  • T003 Re-read apps/platform/app/Support/Resources/ResourceIdentity.php, apps/platform/app/Support/Resources/ProviderResourceDescriptor.php, apps/platform/app/Models/ProviderResourceBinding.php, and apps/platform/app/Services/Resources/ProviderResourceBindingService.php before implementation.
  • T004 Re-read apps/platform/app/Jobs/CompareBaselineToTenantJob.php, apps/platform/app/Support/Baselines/SubjectResolver.php, apps/platform/app/Support/Baselines/BaselineSubjectKey.php, and apps/platform/app/Support/Baselines/Compare/CompareStrategyRegistry.php before implementation.
  • T005 Document in specs/382-baseline-matching-canonicalization/implementation-close-out.md that Spec 382 has no UI, Filament, Livewire, asset, migration, environment variable, queue-name, scheduler, or storage surface impact unless the spec is updated first.

Phase 2: Tests First - Matching Core

Purpose: Lock the business truth before changing compare behavior.

  • T006 [P] [US1] Add tests/Unit/Support/Baselines/Matching/BaselineSubjectDescriptorTest.php covering provider identity, canonical subject key, display label as metadata, and source-reference sanitization.
  • T007 [P] [US1] Add tests/Unit/Support/Baselines/Matching/MatchingOutcomeTest.php covering resolved, ambiguous, missing-provider-resource, missing-local-evidence, unsupported, limited, excluded, and unresolved-identity outcomes.
  • T008 [P] [US1] Add tests/Unit/Support/Baselines/Matching/SubjectMatchingPipelineTest.php covering binding-first priority, exact provider identity, canonical provider-resource keys, duplicate provider-identity ambiguity, missing identity gaps, same-label/different-provider-id separation, and deterministic ordering.
  • T009 [P] [US2] Add built-in/default/virtual fake-provider proof in tests/Unit/Support/Baselines/Matching/SubjectMatchingPipelineTest.php without adding a production canonicalizer registry.
  • T010 [P] [US3] Add tests/Unit/Services/Baselines/Matching/FoundationCoverageResolverTest.php covering inventory-only, canonical-only, unsupported, and existing support-contract classification.

Phase 3: Tests First - Integration And Regression

Purpose: Prove binding-aware compare behavior, isolation, and identity-required gaps before implementation.

  • T011 [P] [US4] Replace tests/Feature/Baselines/BaselineCompareProviderResourceBindingNoOpTest.php with canonical identity coverage so active provider resource bindings are expected to be consumed rather than ignored.
  • T012 [P] [US1] Confirm tests/Feature/Baselines/BaselineCompareAmbiguousMatchGapTest.php proves duplicate provider-resource identity candidates without active binding remain unresolved ambiguity, while same labels alone do not match.
  • T013 [P] [US3] Confirm tests/Feature/Baselines/BaselineCompareGapClassificationTest.php still proves inventory-only or unsupported foundation resources do not become false policy-missing blockers.
  • T014 [P] [US1] Extend tests/Feature/ProviderResources/ProviderResourceBindingServiceTest.php so arbitrary canonical_subject_key overrides are rejected unless generated or validated as provider-resource canonical keys.
  • T015 [P] [US1] Cover binding-aware compare behavior in tests/Feature/Baselines/BaselineCompareProviderResourceBindingCanonicalIdentityTest.php and matching proof/priority behavior in tests/Unit/Support/Baselines/Matching/SubjectMatchingPipelineTest.php.
  • T016 [P] [US2] Cover fake-provider built-ins and virtual targets in tests/Unit/Support/Baselines/Matching/SubjectMatchingPipelineTest.php without Microsoft label hardcoding or provider runtime calls.
  • T017 [P] [US4] Confirm tests/Feature/Evidence/BaselineDriftPostureSourceTest.php and tests/Feature/ReviewPack/Spec349ReviewPackResolutionGuidanceTest.php still prove no intentional evidence/review readiness behavior change.

Phase 4: Canonical Key And Legacy Removal

Purpose: Prevent old display-name subject keys from masquerading as canonical provider-resource identity and remove legacy identity residue.

  • T018 [US1] Update apps/platform/app/Support/Baselines/BaselineSubjectKey.php with provider-resource canonical key validation helpers if existing generation helpers are insufficient.
  • T019 [US1] Update apps/platform/app/Services/Resources/ProviderResourceBindingService.php so supplied canonical keys are accepted only when validated as provider-resource canonical keys for the supplied subject scope and ResourceIdentity.
  • T020 [US1] Remove legacy_subject_key from apps/platform/app/Services/Resources/ProviderResourceBindingService.php, DTO/service inputs, factories, and active tests; add a Spec 382 migration that drops the column because Spec 381 already created it.
  • T021 [US1] Confirm apps/platform/database/factories/ProviderResourceBindingFactory.php generates provider-resource canonical keys by default and does not include legacy subject-key attributes.

Phase 5: Matching Support Types

Purpose: Add the narrow runtime objects needed for pre-compare matching.

  • T022 [P] [US1] Add apps/platform/app/Support/Baselines/Matching/BaselineSubjectDescriptor.php for baseline-side subject identity and sanitized source references.
  • T023 [P] [US1] Add apps/platform/app/Support/Baselines/Matching/MatchingOutcome.php for resolved, ambiguous, missing, unsupported, limited, excluded, and unresolved-identity outcomes.
  • T024 [P] [US1] Keep confidence as derived strings inside MatchingOutcome; no separate MatchingConfidence class needed.
  • T025 [US1] Add descriptor-builder methods in CompareBaselineToTenantJob to derive baseline descriptors from BaselineSnapshotItem without making display labels authoritative.
  • T026 [US1] Add current provider descriptor collection helpers in CompareBaselineToTenantJob where existing ProviderResourceDescriptor construction was insufficient.

Phase 6: Canonicalization And Foundation Coverage

Purpose: Keep provider-specific built-in/default/virtual logic behind narrow seams and avoid false policy-backed blockers.

  • T027 [P] [US2] Avoid adding a production canonicalizer interface/registry by default; use ResourceIdentity provider metadata and fake-provider coverage instead.
  • T028 [P] [US2] Add a minimal provider-owned built-in/default/virtual canonicalization seam through provider ResourceIdentity metadata, with fake-provider proof and no Microsoft label hardcoding in core.
  • T029 [P] [US2] Do not add CanonicalizationResult; ResourceIdentity plus MatchingOutcome is sufficient for v1 behavior and proof metadata.
  • T030 [US3] Add apps/platform/app/Services/Baselines/Matching/FoundationCoverageResolver.php that reuses InventoryPolicyTypeMeta, BaselineSupportCapabilityGuard, and existing support metadata before introducing any new classification source.
  • T031 [US2] Confirm any Microsoft/Intune canonicalization remains provider-owned, uses stable persisted provider metadata rather than display labels such as All users, All devices, or Default, and does not call GraphClientInterface, provider gateways, or provider runtime clients.

Phase 7: Subject Matching Pipeline

Purpose: Implement the deterministic matching priority before payload comparison.

  • T032 [US1] Add apps/platform/app/Services/Baselines/Matching/SubjectMatchingPipeline.php with matching order: active binding, provider identity/canonical identity, unresolved duplicate ambiguity, identity-required gaps, and missing/unsupported/limitation. Fingerprints, legacy keys, and display labels are not matching sources.
  • T033 [US1] Ensure SubjectMatchingPipeline scopes active binding lookup by workspace_id, managed_environment_id, canonical subject key, and active binding status; provider key is embedded in the canonical key and rechecked through binding identity fields.
  • T034 [US1] Ensure SubjectMatchingPipeline never uses display names, fingerprints, or legacy subject keys as matching evidence.
  • T035 [US3] Ensure SubjectMatchingPipeline returns missing-local-evidence instead of missing-provider-resource when provider absence is not proven.
  • T036 [US4] Ensure SubjectMatchingPipeline treats identity resolution separately from drift/no-drift and does not mark matched resources healthy by itself.

Phase 8: Baseline Compare Integration

Purpose: Consume matching outcomes in compare without broad result/UI/evidence scope.

  • T037 [US4] Integrate SubjectMatchingPipeline into apps/platform/app/Jobs/CompareBaselineToTenantJob.php before old policy_type|subject_key keying can collapse or discard candidates, remove the unused old keyed readers, and run before compare strategy payload comparison.
  • T038 [US4] Keep existing compare strategies in apps/platform/app/Support/Baselines/Compare/ responsible for payload drift/no-drift after a successful comparable match.
  • T039 [US4] Leave apps/platform/app/Support/Baselines/SubjectResolver.php unchanged; matching outcomes are mapped in the compare job adapter, so SubjectResolver remains non-authoritative for identity.
  • T040 [US3] Store only sanitized matching proof metadata in existing compare result or operation context paths; no secrets, raw sensitive provider payloads, raw Graph errors, credentials, or operator notes are stored.
  • T041 [US4] Confirm no Evidence Snapshot readiness, Review Pack readiness, customer-facing report wording, or operator resolution UI behavior changes are introduced.

Phase 9: Validation And Close-Out

Purpose: Prove the prepared scope and keep implementation reviewable.

  • T042 Run cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/Baselines/Matching.
  • T043 Run cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/Baselines/BaselineSubjectKeyCanonicalIdentityTest.php tests/Unit/Support/Resources/ResourceIdentityTest.php tests/Unit/Support/Resources/ProviderResourceDescriptorTest.php.
  • T044 Run cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Baselines/BaselineCompareProviderResourceBindingCanonicalIdentityTest.php tests/Feature/Baselines/BaselineCompareAmbiguousMatchGapTest.php tests/Feature/Baselines/BaselineCompareGapClassificationTest.php tests/Feature/Evidence/BaselineDriftPostureSourceTest.php tests/Feature/ReviewPack/Spec349ReviewPackResolutionGuidanceTest.php.
  • T045 Run cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderResources/ProviderResourceBindingServiceTest.php tests/Feature/ProviderResources/ProviderResourceBindingAuthorizationTest.php.
  • T046 Confirm the Spec 382 migration is limited to dropping provider_resource_bindings.legacy_subject_key; targeted database-backed tests run through Laravel migrations in the normal PostgreSQL-backed Sail test lane.
  • T047 Run cd apps/platform && ./vendor/bin/sail bin pint --dirty --test --format agent.
  • T048 Run git diff --check.
  • T049 Record specs/382-baseline-matching-canonicalization/implementation-close-out.md with Livewire v4 compliance, provider registration location, global search status, destructive/high-impact action status, asset strategy, tests run, and deployment impact.

Dependencies

  • Phase 1 must finish before implementation.
  • Phases 2 and 3 should be written before or alongside Phases 4-8.
  • Phase 4 must complete before active binding consumption can be trusted.
  • Phase 5 and Phase 6 unblock Phase 7.
  • Phase 7 unblocks Phase 8.
  • Phase 9 validates the completed implementation.

Parallel Opportunities

  • T006-T010 can be drafted in parallel.
  • T011-T017 can be drafted in parallel if each test file remains scoped.
  • T022-T024 can be implemented in parallel with T027-T030 after Phase 4 is understood.
  • T042-T045 can be run independently after implementation, but final close-out should use the complete targeted set.

Explicit Non-Goals

  • Do not add new persisted entities without updating spec and plan first. The only approved Spec 382 migration drops provider_resource_bindings.legacy_subject_key.
  • Do not add or change Filament resources, pages, actions, Livewire components, Blade views, navigation, or assets.
  • Do not add operator resolution UI.
  • Do not change Evidence Snapshot readiness, Review Pack readiness, or customer-facing report semantics.
  • Do not add historical payload mappers or OperationRun context readers.
  • Do not create a generic provider workflow engine or broad multi-provider framework.