## 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
168 lines
8.5 KiB
Markdown
168 lines
8.5 KiB
Markdown
# 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<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
|
|
|
|
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"
|
|
}
|
|
```
|