34 KiB
Feature Specification: Spec 417 - Canonical Identity Engine
Feature Branch: 417-canonical-identity-engine
Created: 2026-06-26
Status: Draft
Input: User-provided draft "Spec 417 - Canonical Identity Engine" plus repo checks against Specs 414/415, roadmap, candidate queue, constitution, and current TenantConfiguration runtime.
Candidate Selection
- Selected candidate: Spec 417 - Canonical Identity Engine.
- Source location: User attachment
/Users/ahmeddarrazi/.codex/attachments/7ecaf0a8-0997-4ef9-a7cc-207cdb7d1271/pasted-text.txt. - Why selected: Spec 414 implemented the inactive Coverage v2 kernel and Spec 415 implemented generic content-backed capture. Current code now persists captured
tenant_configuration_resources, butCoverageResourceUpserterstill derives identity directly fromid/sourceIdand defaults identity tostable. The next safety gap is deterministic provider-scoped identity before Coverage v2 can make any customer/operator claim. - Roadmap relationship:
docs/product/spec-candidates.mdcurrently says no safe automatic next-best target remains in the active queue. This package is therefore not auto-selected from the queue; it is a user-promoted P0 follow-up in the Coverage v2 sequence and aligns with roadmap themes around evidence/coverage hardening, provider-boundary discipline, workspace/managed-environment ownership, and no-legacy cutover. - Close alternatives deferred: Management-report runtime validation, artifact lifecycle retention, provider readiness productization, cross-domain indicator runtime follow-through, system-panel browser fixture work, and first governed AI consumer remain manual-promotion backlog items. They are deferred because the user supplied a specific Coverage v2 identity draft and because Coverage v2 identity is the immediate blocker after Specs 414/415.
- Related completed-spec guardrail:
specs/414-tcm-first-coverage-core-cutover/andspecs/415-generic-content-backed-capture/are completed/validated dependency context only and must not be rewritten. The earlier 414/415 follow-up label "Spec 416 - Canonical Identity Engine" is superseded by current repo truth because Spec 416 is nowtenantpilot-agent-skill-layer-v1. - Smallest viable implementation slice: Add a canonical identity strategy/resolution/evaluation path for the initial eight Coverage v2 resource types, persist identity key kind and safe diagnostics on existing resource rows, integrate identity output into capture upsert and Claim Guard, and prove no display-name-only stable truth, cross-scope merge, customer claim, UI activation, or v1 adapter exists.
Spec Candidate Check (mandatory - SPEC-GATE-001)
- Problem: Captured Coverage v2 resources need stable, deterministic, provider-scoped identity before future compare, review, report, restore, or certification flows can trust them.
- Today's failure: A captured payload with a weak or missing provider ID can be treated as stable, while duplicate display names or unsafe derived identities could later produce false coverage, compare, restore, or customer-evidence claims.
- User-visible improvement: No direct UI change in this slice. Future operators and customers are protected from false "covered" or "ready" claims because unsafe identity blocks or limits claims before those surfaces are activated.
- Smallest enterprise-capable version: Resolve identity for the initial Spec 414/415 resource types only; integrate with existing capture/upsert/claim guard; keep diagnostics bounded and internal; do not activate UI or implement compare/render/restore/certification.
- Explicit non-goals: No Coverage v2 operator dashboard, Evidence Overview conversion, Baseline Compare conversion, Customer Review Workspace conversion, Review Pack/report identity claims, restore readiness conversion, full Microsoft TCM catalog import, v1-to-v2 adapter, old gap taxonomy, or broad legacy removal.
- Permanent complexity imported: A bounded identity strategy registry, canonical identity resolver, secondary-key/diagnostics helpers, a key-kind value family, extra identity columns/JSONB metadata on existing Coverage v2 resource rows, and focused unit/feature/PostgreSQL tests.
- Why now: Spec 415 introduced concrete resource/evidence capture. Identity safety is the next prerequisite before any customer/operator proof, compare, render, restore, certification, or legacy cutover work can proceed safely.
- Why not local: Identity decisions are consumed by capture upsert, resource persistence, conflict handling, Claim Guard, provider scope enforcement, and future claim surfaces. Keeping this logic local to one capture method would preserve the exact drift this spec must eliminate.
- Approval class: Core Enterprise.
- Red flags triggered: New status/key kind axis; new resolver/registry infrastructure; foundation-like language. Defense:
IdentityStatealready exists from Spec 414, eight concrete resource types already exist, current capture/upsert already needs identity, and unsafe identity has direct claim-safety consequences. - Score: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexität: 1 | Produktnähe: 1 | Wiederverwendung: 2 | Gesamt: 10/12
- Decision: approve, with strict no-UI/no-customer-claim/no-legacy scope.
Spec Scope Fields (mandatory)
- Scope: canonical-view / environment-owned internal runtime. No rendered UI surface.
- Primary Routes: N/A - no routes, Filament pages, navigation, customer routes, downloads, reports, or restore surfaces are in scope.
- Data Ownership: Existing
tenant_configuration_resourcesandtenant_configuration_resource_evidenceremain environment-owned throughworkspace_id,managed_environment_id, and same-scopeprovider_connection_id.tenant_configuration_resource_typesremains platform-seeded definition truth. - RBAC: Identity evaluation runs inside already-authorized capture by default. If a separate re-evaluation command/job/start path is introduced, non-member workspace/environment access must be 404, member without capability must be 403, and readonly users must not start evaluation.
No Legacy / No Backward Compatibility Constraint (mandatory)
TenantPilot is pre-production unless this spec explicitly records a compatibility exception.
- Compatibility posture: canonical replacement / no compatibility exception.
- Legacy aliases, fallback readers, hidden routes, duplicate UI, old labels, or historical fixtures kept?: no.
- Why clean replacement is safe now: Coverage v2 is inactive and not customer-facing. No production/customer data or external contract requires v1/v2 compatibility. This spec must not dual-write v1/v2 identity, promote old snapshots into v2 proof, or translate old gap taxonomy into v2 runtime truth.
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
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)
N/A - no reachable UI surface impact. This slice is internal runtime/data/claim-safety work only. If implementation needs any UI file, route, navigation entry, customer/report/review/evidence surface, or restore readiness surface, implementation must stop and update spec.md, plan.md, and tasks.md first.
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?: no rendered product surface changed; only the no-UI/no-customer-claim posture applies.
- Page archetype: N/A.
- Primary user question: N/A.
- Primary action: N/A.
- Surface budget result: N/A.
- Technical Annex / deep-link demotion: N/A for UI. Raw payloads, source keys, diagnostics, and provider identifiers remain internal persistence/support data and must not become default-visible output in this spec.
- Canonical status vocabulary: N/A for UI. Internal identity states are not product-facing status vocabulary in this slice.
- Visible complexity impact: neutral.
- Product Surface exceptions: none.
Browser Verification Plan (mandatory)
- Browser proof required?: no.
- No-browser rationale:
N/A - no rendered UI surface changed. - Focused path when required: N/A.
- Primary interaction to execute: N/A.
- Console, Livewire, Filament, network, and 500-error checks: N/A.
- Full-suite failure triage: N/A unless scope is amended to UI.
Human Product Sanity Check (mandatory)
- Required?: no.
- No-human-sanity rationale: N/A - no product surface changed.
- Reviewer questions: N/A.
- Planned result location: implementation report records no-surface rationale.
Product Surface Merge Gate Checklist (mandatory)
- No-legacy posture or approved exception recorded.
- Product Surface Impact is completed or
N/Ais justified. - Browser proof is completed or
N/A - no rendered UI surface changedis justified. - Human Product Sanity is completed or not applicable with rationale.
- Product Surface exceptions are documented or
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 completed-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, internal claim/evidence/capture semantics only.
- Interaction class(es): evidence-backed claim safety; no rendered notifications/status UI/action links.
- Systems touched: TenantConfiguration capture/upsert, Claim Guard, evidence/resource persistence, OperationRun execution context only if evaluation is separated from existing capture.
- Existing pattern(s) to extend: existing
ClaimGuard,CoverageResourceUpserter,CoverageEvidenceWriter,GenericContentEvidenceCaptureService,CoveragePayloadRedactor, and OperationRun service patterns. - Shared contract / presenter / builder / renderer to reuse: no UI presenter/renderer; use existing OperationRun lifecycle and capture service path where relevant.
- Why the existing shared path is sufficient or insufficient: Existing capture and Claim Guard are the right integration points, but current upsert lacks strategy-driven canonical identity and safe conflict diagnostics.
- Allowed deviation and why: none for UI/customer output. Bounded identity services are allowed because identity safety must be reused across capture upsert, conflict evaluation, and claim blocking.
- Consistency impact: Identity state must remain the only internal identity-safety axis; no old v1 gap reason or display-name-only stable concept may be introduced.
- Review focus: Verify no page-local or capture-local identity shortcut bypasses the canonical resolver/evaluator.
OperationRun UX Impact (mandatory when the feature creates, queues, deduplicates, resumes, blocks, completes, or deep-links to an OperationRun; otherwise write N/A - no OperationRun start or link semantics touched)
- Touches OperationRun start/completion/link UX?: no new UX. Existing Spec 415 capture OperationRuns may execute identity evaluation as part of capture.
- Shared OperationRun UX contract/layer reused: N/A unless a separate re-evaluation start path is introduced.
- Delegated start/completion UX behaviors: N/A.
- Local surface-owned behavior that remains: none.
- Queued DB-notification policy: N/A; no new queued DB notifications.
- Terminal notification path: existing central lifecycle mechanism only if an OperationRun-backed evaluation job is added.
- Exception required?: none.
If implementation adds tenant_configuration.identity_evaluation or another new operation type, it must use OperationRunService for lifecycle transitions, numeric-only summary counts, no raw payloads in context/messages, no custom terminal DB notifications, no local UX composition, and focused authorization tests for capability access, readonly denial, wrong-scope 404, and missing-capability 403.
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. Canonical identity state/key kind and workspace/environment/provider ownership are platform-core; Graph/TCM field extraction and source ID names are provider-owned source metadata.
- Seams affected: TenantConfiguration resource persistence, resource-type strategy metadata, capture upsert, provider connection scope validation, Claim Guard.
- Neutral platform terms preserved or introduced: provider connection, managed environment, resource type, canonical key kind, identity state, claim state.
- Provider-specific semantics retained and why: Microsoft Graph/TCM source fields are retained only inside per-resource-type identity strategies and source metadata because Microsoft is the current concrete provider.
- Why this does not deepen provider coupling accidentally: Provider-specific fields do not become platform ownership truth;
workspace_id,managed_environment_id, andprovider_connection_idremain the internal scope boundary. - Follow-up path: none for this slice; additional provider/resource strategies are future specs.
UI / Surface Guardrail Impact (mandatory when operator-facing surfaces are changed; otherwise write N/A)
N/A - no operator-facing surface change.
Decision-First Surface Role (mandatory when operator-facing surfaces are changed)
N/A - no operator-facing surface change.
Audience-Aware Disclosure (mandatory when operator-facing surfaces are changed)
N/A - no operator-facing surface change. Customer/read-only output must not expose identity diagnostics, source keys, raw payloads, provider request details, or OperationRun proof by default in this spec.
UI/UX Surface Classification (mandatory when operator-facing surfaces are changed)
N/A - no operator-facing surface change.
Operator Surface Contract (mandatory when operator-facing surfaces are changed)
N/A - no operator-facing surface change.
Proportionality Review (mandatory when structural complexity is introduced)
- New source of truth?: yes. Canonical resource identity becomes internal truth for captured Coverage v2 resources.
- New persisted entity/table/artifact?: no new table is expected. Existing
tenant_configuration_resourcesshould be extended where needed. A new identity-conflict table is out of scope unless implementation proves JSON diagnostics cannot satisfy current behavior. - New abstraction?: yes. Bounded identity strategy/resolver/evaluator helpers.
- New enum/state/reason family?: yes.
IdentityStatealready exists; a bounded canonical key-kind value family is expected. - New cross-domain UI framework/taxonomy?: no.
- Current operator problem: Future operators must not review, compare, restore, report, or certify the wrong resource because the system silently matched by display name or weak identity.
- Existing structure is insufficient because: Current upsert extracts only
id/sourceId, buildscanonical_resource_key, and marks new resources stable. It cannot express missing IDs, derived identities, conflicts, beta/experimental identity, secondary diagnostic keys, or claim blocking by identity state. - Narrowest correct implementation: Implement identity resolution only for the eight initial Coverage v2 resource types, integrate only with existing capture/upsert/Claim Guard, store bounded diagnostics on the resource row, and keep all UI/customer activation deferred.
- Ownership cost: Maintainers must preserve strategy definitions, identity tests, scope constraints, key-kind semantics, and redaction rules as new resource types are added.
- Alternative intentionally rejected: Keep
id/sourceIdhardcoded inCoverageResourceUpserterand fail when missing. Rejected because it overclaims stability for beta/fallback types, cannot diagnose conflicts, and blocks safe future activation. - Release truth: Current-release foundation after completed Specs 414 and 415; no future-only UI behavior is introduced.
Compatibility posture
This feature assumes a pre-production environment. Backward compatibility, legacy aliases, migration shims, historical fixtures, fallback readers, dual writes, and compatibility-specific tests are out of scope.
Testing / Lane / Runtime Impact (mandatory for runtime behavior changes)
- Test purpose / classification: Unit, Feature, PostgreSQL-focused where migration/constraints/indexes require it. Browser N/A.
- Validation lane(s): fast-feedback, confidence, pgsql for schema/index/constraint behavior, no browser unless scope is amended.
- Why this classification and these lanes are sufficient: Identity resolution and Claim Guard behavior are service-level business truth; persistence/upsert/scope/conflict behavior requires feature/database tests; UI/browser cannot prove this slice because no UI changes are allowed.
- New or expanded test families: Focused TenantConfiguration unit/feature tests only; no heavy-governance or browser family.
- Fixture / helper cost impact: Use existing TenantConfiguration factories and workspace/environment/provider setup. Any new factory state must remain opt-in and not make full provider/workspace setup a default for unrelated tests.
- Heavy-family visibility / justification: none.
- Special surface test profile: N/A.
- Standard-native relief or required special coverage: no browser proof required because no rendered UI changes.
- Reviewer handoff: Reviewers must verify lane fit, no hidden browser/heavy-governance cost, no broad fixture default, and exact focused commands in the implementation report.
- Budget / baseline / trend impact: none expected; document if identity tests materially expand TenantConfiguration lane runtime.
- Escalation needed: document-in-feature for contained identity test cost; follow-up-spec only if a broad static governance lane becomes necessary.
- Active feature PR close-out entry: Guardrail / Exception / Smoke Coverage.
- Planned validation commands:
cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agentcd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/TenantConfigurationcd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/TenantConfigurationcd apps/platform && ./vendor/bin/sail php vendor/bin/pest -c phpunit.pgsql.xml tests/Feature/TenantConfigurationgit diff --check
User Scenarios & Testing (mandatory)
User Story 1 - Resolve Captured Resource Identity Safely (Priority: P1)
As a platform engineer preparing Coverage v2 activation, I need every captured tenant configuration resource to resolve to a deterministic canonical identity state so future claims never rely on display name alone.
Why this priority: This is the minimum viable identity safety guarantee for all later Coverage v2 work.
Independent Test: Unit tests pass payload/resource-type/provider-scope examples into the resolver and assert stable, derived, missing, unsupported, and conflict outcomes without using display-name-only as stable truth.
Acceptance Scenarios:
- Given a captured payload has a provider/Graph/TCM stable ID, When identity is resolved, Then the resource receives a deterministic canonical key, key kind, and
identity_state = stable. - Given a captured payload has only allowed composite source fields, When identity is resolved, Then the resource receives
identity_state = derivedand claim behavior is limited unless explicitly allowed. - Given a captured payload has only a display name, When identity is resolved, Then it cannot be marked stable.
User Story 2 - Prevent Unsafe Merges And False Claims (Priority: P1)
As a release reviewer, I need duplicate names, derived collisions, missing IDs, beta identity paths, and cross-provider/resource collisions to fail safe so Coverage v2 cannot silently merge the wrong records.
Why this priority: Wrong identity is worse than no identity because it can create false compare, restore, or audit claims.
Independent Test: Feature tests persist captured resources across same/different workspace, managed environment, provider connection, and resource type boundaries, then assert conflicts do not merge and unsafe states block claims.
Acceptance Scenarios:
- Given two same-scope resources share a display name but have different stable IDs, When capture upserts them, Then they remain separate resources.
- Given two same-scope resources produce the same unsafe derived key, When identity is evaluated, Then neither is silently chosen and unsafe claims are blocked.
- Given the same source key appears under another workspace, managed environment, or provider connection, When identity is evaluated, Then resources do not collide across scope.
User Story 3 - Keep Identity Diagnostics Useful And Safe (Priority: P2)
As a support/platform operator, I need identity diagnostics that explain why a resource is blocked without exposing secrets, raw payloads, tokens, or provider response dumps.
Why this priority: Diagnostics are necessary for later supportability, but raw evidence cannot become customer-safe proof or default output.
Independent Test: Unit/feature tests assert diagnostic fields include bounded reason/candidate metadata and redact configured secret keys.
Acceptance Scenarios:
- Given identity cannot be resolved safely, When diagnostics are persisted, Then they include bounded reason metadata such as key kinds, missing fields, and candidate count.
- Given payload/source metadata contains sensitive keys, When diagnostics and secondary keys are built, Then secrets/tokens/cookies/authorization values are redacted or omitted.
User Story 4 - Preserve No-UI, No-Legacy Coverage v2 Boundaries (Priority: P1)
As a reviewer, I need proof that identity hardening does not activate Coverage v2 as customer/operator truth, revive v1 gap semantics, or add compatibility adapters.
Why this priority: Coverage v2 remains inactive until a later explicit activation/cutover spec.
Independent Test: Guard/feature tests assert no UI route/resource/view/navigation is added, no tenant_id ownership appears, no old gap taxonomy is emitted, and no v1-to-v2 adapter is introduced.
Acceptance Scenarios:
- Given the implementation completes, When changed files are reviewed, Then no reachable UI surface or browser-visible Coverage v2 claim is added.
- Given v1 baseline/evidence code still exists, When v2 identity services are inspected, Then old v1 gap terms such as
ambiguous_matchare not emitted as active v2 outcomes.
Functional Requirements (mandatory)
- FR-417-001: The system MUST keep Coverage v2 inactive for customer-facing and operator-facing proof surfaces in this spec.
- FR-417-002: The system MUST define identity strategies for the initial resource types from Specs 414/415:
deviceAndAppManagementAssignmentFilter,deviceEnrollmentLimitRestriction,deviceEnrollmentPlatformRestriction,deviceEnrollmentStatusPageWindows10,appProtectionPolicyAndroid,appProtectionPolicyiOS,notificationMessageTemplate, androleScopeTag. - FR-417-003: Each identity strategy MUST define preferred identity fields, fallback identity fields, display/secondary fields, whether provider connection scope is required, whether derived identity is allowed, whether experimental identity is allowed, and claim behavior for derived/conflict states.
- FR-417-004: Identity resolution MUST prefer immutable provider/Graph/TCM IDs, then documented provider-native stable IDs, then documented source identity, then source composite, then derived composite only when explicitly allowed.
- FR-417-005: Display name, name, label, or other human-readable text alone MUST NOT produce stable identity.
- FR-417-006: Identity resolution MUST produce one of the existing identity states:
stable,derived,identity_conflict,missing_external_id, orunsupported_identity. - FR-417-007: Identity resolution MUST produce a canonical key-kind value such as provider external ID, Graph object ID, TCM resource identifier, source composite, derived composite, experimental source key, or unsupported. Forbidden stable key kinds include display-name-only and name-only.
- FR-417-008: The implementation MUST use the existing
canonical_resource_keycolumn as the canonical identity key. Replacing it is out of scope unless implementation stops and updatesspec.md,plan.md, andtasks.mdwith the reason existing storage cannot serve and a single-key migration plan. It MUST NOT persist duplicate canonical key truths such as bothcanonical_resource_keyandcanonical_keywith competing semantics. - FR-417-009: Existing resource rows MUST be extended with the minimum additional identity fields needed for key kind, external/source identity, strategy identifier, secondary keys, redacted diagnostics, evaluation timestamp, and optional tombstone timestamp.
- FR-417-010: Secondary keys MAY include display name, name, provider tenant/directory metadata, app/object IDs, UPN/mail, scope tag, assignment target, platform, policy family, source endpoint/version, or schema version, but they MUST remain diagnostic metadata only.
- FR-417-011: Identity diagnostics MUST be bounded and redacted. They MUST NOT persist raw provider payloads, tokens, secrets, authorization headers, cookies, private keys, certificates, passwords, full provider response dumps, or unredacted PII.
- FR-417-012: Identity uniqueness and conflict detection MUST be scoped by
workspace_id,managed_environment_id,provider_connection_id,resource_type_id, and canonical identity key. - FR-417-013: Provider connections used for identity evaluation MUST belong to the same workspace and managed environment as the resource being evaluated.
- FR-417-014: Cross-workspace, cross-managed-environment, and cross-provider identity collisions MUST NOT merge resources.
- FR-417-015: Rename behavior MUST preserve the same resource row when a stable provider identity remains the same and only display metadata changes.
- FR-417-016: Derived identity rename behavior MUST remain limited or blocked according to Claim Guard and MUST NOT silently certify the resource.
- FR-417-017: Missing expected stable external IDs MUST produce
missing_external_idorderivedaccording to strategy; they MUST NOT default to stable. - FR-417-018: Unsupported resource identity MUST produce
unsupported_identityand block customer-facing claims. - FR-417-019: Beta/experimental identity paths MUST remain internal-only or claim-blocked by default and MUST NOT certify by default.
- FR-417-020:
CoverageResourceUpserteror its repo-equivalent MUST consume canonical identity resolver output and MUST NOT upsert by display name only, first candidate, latest candidate, or old v1 subject resolver output. - FR-417-021: Claim Guard MUST block customer-facing claims when identity state is
identity_conflict,missing_external_id, orunsupported_identity, and MUST limit or blockderivedidentity unless the supported scope explicitly permits derived identity. - FR-417-022: Full missing/deleted-resource drift workflow is out of scope. If a tombstone field is added, it MUST preserve last known canonical identity and MUST NOT make tombstoned rows active proof.
- FR-417-023: The implementation MUST NOT introduce
tenant_idas Coverage v2 ownership truth, compatibility alias, dual-write target, fallback reader, or parallel scope key. - FR-417-024: The implementation MUST NOT add a v1-to-v2 identity adapter, old snapshot identity promotion, old gap taxonomy, fallback-to-latest evidence behavior, or dual customer-facing truth.
- FR-417-025: No Filament Resource/Page, Blade view, route, navigation entry, customer report/review/evidence surface, restore readiness surface, browser-visible identity warning, or Coverage v2 activation may be added in this spec.
Key Entities / Data Truth (include if feature involves data)
- Tenant Configuration Resource Type: Platform-seeded definition of a Coverage v2 resource type, source class, support defaults, and identity strategy metadata.
- Tenant Configuration Resource: Environment-owned concrete Coverage v2 resource observed in one workspace, managed environment, provider connection, and resource type. It is the canonical internal identity holder for captured resources.
- Tenant Configuration Resource Evidence: Append-only payload evidence linked to a resource, OperationRun, provider connection, and source metadata. It remains evidence payload truth, not identity strategy truth.
- Canonical Identity Strategy: Bounded per-resource-type rule set for preferred IDs, fallbacks, secondary fields, derived allowance, experimental behavior, and claim consequences.
- Canonical Identity Result: Resolver output containing identity state, canonical resource key, key kind, source/external identity, secondary keys, diagnostics, and claim consequence hints.
Truth separation:
- Execution truth:
OperationRunfor capture/evaluation execution lifecycle only. - Artifact/evidence truth:
tenant_configuration_resource_evidenceappend-only payload rows. - Resource identity truth:
tenant_configuration_resourcescanonical identity fields. - Claim truth: Claim Guard output derived from identity, coverage, evidence, support, and scope gates.
- Operator next action: out of scope until a later UI/customer-output activation spec.
Success Criteria (mandatory)
- SC-417-001: Stable provider/Graph/TCM IDs produce stable deterministic identity scoped by workspace, managed environment, provider connection, and resource type.
- SC-417-002: Display-name-only payloads never become stable identity.
- SC-417-003: Duplicate display names with different stable IDs remain separate resources.
- SC-417-004: Duplicate unsafe derived identities produce conflict/blocked behavior instead of silent merge.
- SC-417-005: Claim Guard blocks or limits claims for unsafe identity states.
- SC-417-006: Diagnostics are actionable and redacted.
- SC-417-007: No
tenant_id, v1 adapter, old gap taxonomy, fallback reader, dual write, or UI activation is introduced. - SC-417-008: Focused unit, feature, PostgreSQL where applicable, Pint, and
git diff --checkvalidation pass or exact failures are documented.
Assumptions (mandatory)
- Specs 414 and 415 are completed/validated and remain read-only context.
- Current Coverage v2 remains inactive and not customer/operator-facing.
- Existing
tenant_configuration_resources.canonical_resource_keyis the repo-real canonical key storage for this scope. Any replacement requires a spec/plan/tasks amendment before implementation continues. - The eight initial resource types from Specs 414/415 are enough to justify a bounded strategy registry/resolver.
- Existing
CoveragePayloadRedactorcan be reused or extended for identity diagnostics and secondary keys. - No production data or external API contract requires legacy compatibility.
Risks (mandatory)
| Risk | Severity | Mitigation |
|---|---|---|
| Display name accidentally becomes stable truth | High | Resolver rules, static/feature guards, no display-name-only key kind |
| Cross-provider or cross-environment merge | High | Scope-aware uniqueness and same-scope provider tests |
| Identity diagnostics leak sensitive data | High | Redaction builder and tests for secret keys |
| Derived identity is overtrusted | High | Claim Guard blocks/limits derived unless explicitly allowed |
| New identity layer becomes too generic | Medium | Limit strategies to eight concrete resource types and current capture path |
| UI/customer activation sneaks in | Medium | No-UI guard tests and Product Surface stop condition |
Existing canonical_resource_key vs draft canonical_key creates duplicate truth |
Medium | Use one canonical field; no competing persisted key semantics |
Open Questions (must be resolved before implementation if blocking)
No blocking product questions remain for the preparation scope.
Non-blocking implementation checks:
- Confirm during implementation whether a focused additive migration or an in-place pre-production migration adjustment is preferred for the identity columns.
- Confirm exact Graph/TCM ID field names per contract/resource type from repo-real payloads and tests; strategy defaults may use current contract metadata where available.
- Confirm whether tombstone persistence is required in this slice or whether it remains field-ready/deferred until drift/delete workflow.
Follow-up Spec Candidates (out of scope for Spec 417)
- Coverage v2 Operator Surface / internal diagnostics UI.
- Legacy Coverage v1 cutover and removal.
- Intune core comparable/renderable pack.
- Certified Intune core coverage pack.
- Restore/readiness identity integration.
- Customer-facing identity warnings and review/report identity claims.
- Full Microsoft TCM catalog identity mapping.