# Data Model: Baseline Subject Resolution and Evidence Gap Semantics Foundation ## Overview This feature does not require a new primary database table. It introduces a richer logical model for subject classification and resolution, then persists that model inside existing compare and capture run context for new runs. Development-only run payloads using the old broad reason shape may be removed or regenerated instead of preserved through a compatibility contract. ## Entity: SubjectDescriptor Business-level descriptor for a compare or capture target before local resolution. ### Fields | Field | Type | Required | Description | |---|---|---|---| | `policy_type` | string | yes | Canonical policy or foundation type from support metadata | | `subject_external_id` | string | no | Stable local or tenant-local external identifier when available | | `subject_key` | string | yes | Deterministic comparison key used across capture and compare | | `subject_class` | enum | yes | One of `policy_backed`, `inventory_backed`, `foundation_backed`, `derived` | | `resolution_path` | enum | yes | Intended local path, such as `policy`, `inventory`, `foundation_policy`, `foundation_inventory`, or `derived` | | `support_mode` | enum | yes | `supported`, `limited`, `excluded`, or `invalid_support_config` | | `source_model_expected` | enum | no | Which local model is expected to satisfy the lookup | ### Validation Rules - `policy_type` must exist in canonical support metadata. - `subject_class` must be one of the supported subject-class values. - `resolution_path` must be compatible with `subject_class`. - `support_mode=invalid_support_config` is only valid when metadata claims support but no truthful runtime path exists. ## Entity: ResolutionOutcomeRecord Deterministic result of attempting to resolve a `SubjectDescriptor` against tenant-local state. ### Fields | Field | Type | Required | Description | |---|---|---|---| | `resolution_outcome` | enum | yes | Precise outcome such as `resolved_policy`, `resolved_inventory`, `policy_record_missing`, `inventory_record_missing`, `foundation_inventory_only`, `resolution_type_mismatch`, `unresolvable_subject`, `permission_or_scope_blocked`, `retryable_capture_failure`, `capture_failed`, `throttled`, or `budget_exhausted` | | `reason_code` | string | yes | Stable operator-facing reason family persisted with the run | | `operator_action_category` | enum | yes | `none`, `retry`, `run_inventory_sync`, `run_policy_sync_or_backup`, `review_permissions`, `inspect_subject_mapping`, or `product_follow_up` | | `structural` | boolean | yes | Whether the outcome is structural rather than operational or transient | | `retryable` | boolean | yes | Whether retry may change the outcome without prerequisite changes | | `source_model_found` | enum or null | no | Which local model actually satisfied the lookup when resolution succeeded | ### State Families | Family | Outcomes | |---|---| | `resolved` | `resolved_policy`, `resolved_inventory` | | `structural` | `foundation_inventory_only`, `resolution_type_mismatch`, `unresolvable_subject`, `invalid_support_config` | | `operational` | `policy_record_missing`, `inventory_record_missing`, `permission_or_scope_blocked`, `ambiguous_match`, `invalid_subject`, `duplicate_subject` | | `transient` | `retryable_capture_failure`, `throttled`, `budget_exhausted`, `capture_failed` | ### Validation Rules - `resolution_outcome` must map to exactly one state family. - `structural=true` is only valid for structural state-family outcomes. - `retryable=true` is only valid for transient outcomes or explicitly retryable operational outcomes. ## Entity: SupportCapabilityRecord Runtime truth contract for whether a subject type may enter baseline compare or capture. ### Fields | Field | Type | Required | Description | |---|---|---|---| | `policy_type` | string | yes | Canonical type key | | `subject_class` | enum | yes | Dominant subject class for the type | | `compare_capability` | enum | yes | `supported`, `limited`, or `unsupported` | | `capture_capability` | enum | yes | `supported`, `limited`, or `unsupported` | | `resolution_path` | enum | yes | Truthful runtime resolution path | | `config_supported` | boolean | yes | Whether metadata claims support | | `runtime_valid` | boolean | yes | Whether the runtime can honor that support claim | ### Validation Rules - `config_supported=true` and `runtime_valid=false` must be surfaced as `invalid_support_config` rather than silently ignored. - Types with `compare_capability=unsupported` must not enter compare scope. - Types with `capture_capability=unsupported` must not enter capture execution. ## Entity: EvidenceGapDetailRecord Structured subject-level record persisted under compare or capture run context for new runs. ### Fields | Field | Type | Required | Description | |---|---|---|---| | `policy_type` | string | yes | Canonical type | | `subject_external_id` | string or null | no | Stable identifier when available | | `subject_key` | string | yes | Deterministic subject identity | | `subject_class` | enum | yes | Classified subject class | | `resolution_path` | enum | yes | Path attempted or declared | | `resolution_outcome` | enum | yes | Deterministic resolution result | | `reason_code` | string | yes | Stable reason family | | `operator_action_category` | enum | yes | Recommended next action family | | `structural` | boolean | yes | Structural versus non-structural marker | | `retryable` | boolean | yes | Retryability marker | | `source_model_expected` | enum or null | no | Expected local evidence model | | `source_model_found` | enum or null | no | Actual local evidence model when present | ### Storage Locations - `operation_runs.context.baseline_compare.evidence_gaps.subjects[]` - `operation_runs.context.baseline_capture.gaps.subjects[]` or equivalent capture-context namespace ### Validation Rules - New-run records must store structured objects, not only string subject tokens. - `subject_key` must be deterministic for identical inputs. - `reason_code` and `resolution_outcome` must not contradict each other. - Old development rows that omit the new fields are cleanup candidates and should be regenerated or deleted rather than treated as a first-class runtime shape. ## Derived Entity: EvidenceGapProjection Read-model projection used by canonical run-detail and tenant review surfaces. ### Fields | Field | Type | Description | |---|---|---| | `detail_state` | enum | `no_gaps`, `structured_details_recorded`, `details_not_recorded`, `legacy_broad_reason` | | `count` | integer | Total gap count | | `by_reason` | map | Aggregate counts by reason | | `recorded_subjects_total` | integer | Number of structured subject rows available for projection | | `missing_detail_count` | integer | Gap count that has no structured row attached | | `structural_count` | integer | Number of recorded structural gap rows | | `operational_count` | integer | Number of recorded non-structural, non-retryable rows | | `transient_count` | integer | Number of recorded retryable rows | | `legacy_mode` | boolean | Indicates the run still stores a broad legacy gap payload | | `buckets` | list | Grouped records by reason with searchable row payload | | `requires_regeneration` | boolean | Whether stale local development data should be regenerated rather than interpreted semantically | ## State Transitions ### Resolution lifecycle for a subject 1. `described` - `SubjectDescriptor` is created from scope, metadata, and capability information. 2. `validated` - Runtime support guard confirms whether the subject may enter compare or capture. 3. `resolved` - The system attempts the appropriate local path and emits a `ResolutionOutcomeRecord`. 4. `persisted` - New runs store the structured `EvidenceGapDetailRecord` or resolved outcome details in `OperationRun.context`. 5. `projected` - Existing operator surfaces consume the new structured projection. Stale development data is regenerated or removed instead of driving a permanent compatibility path. ## Example New-Run Compare Gap Record ```json { "policy_type": "roleScopeTag", "subject_external_id": "42f4fcb8-5b35-44ec-9240-0a1ad7c31fb1", "subject_key": "rolescopetag|42f4fcb8-5b35-44ec-9240-0a1ad7c31fb1", "subject_class": "foundation_backed", "resolution_path": "foundation_inventory", "resolution_outcome": "foundation_inventory_only", "reason_code": "foundation_not_policy_backed", "operator_action_category": "product_follow_up", "structural": true, "retryable": false, "source_model_expected": "inventory_item", "source_model_found": "inventory_item" } ```