## Summary - add the structured subject-resolution foundation for baseline compare and baseline capture, including capability guards, subject descriptors, resolution outcomes, and operator action categories - persist structured evidence-gap subject records and update compare/capture surfaces, landing projections, and cleanup tooling to use the new contract - add Spec 163 artifacts and focused Pest coverage for classification, determinism, cleanup, and DB-only rendering ## Validation - `vendor/bin/sail bin pint --dirty --format agent` - `vendor/bin/sail artisan test --compact tests/Unit/Support/Baselines tests/Feature/Baselines tests/Feature/Filament/OperationRunEnterpriseDetailPageTest.php` ## Notes - verified locally that a fresh post-restart baseline compare run now writes structured `baseline_compare.evidence_gaps.subjects` records instead of the legacy broad payload shape - excluded the separate `docs/product/spec-candidates.md` worktree change from this branch commit and PR Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #193
8.5 KiB
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_typemust exist in canonical support metadata.subject_classmust be one of the supported subject-class values.resolution_pathmust be compatible withsubject_class.support_mode=invalid_support_configis 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_outcomemust map to exactly one state family.structural=trueis only valid for structural state-family outcomes.retryable=trueis 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=trueandruntime_valid=falsemust be surfaced asinvalid_support_configrather than silently ignored.- Types with
compare_capability=unsupportedmust not enter compare scope. - Types with
capture_capability=unsupportedmust 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_keymust be deterministic for identical inputs.reason_codeandresolution_outcomemust 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<string,int> | 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
describedSubjectDescriptoris created from scope, metadata, and capability information.
validated- Runtime support guard confirms whether the subject may enter compare or capture.
resolved- The system attempts the appropriate local path and emits a
ResolutionOutcomeRecord.
- The system attempts the appropriate local path and emits a
persisted- New runs store the structured
EvidenceGapDetailRecordor resolved outcome details inOperationRun.context.
- New runs store the structured
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
{
"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"
}