## Summary - implement Spec 177 inventory coverage truth across resolver, badges, KPIs, coverage page, and operation run detail surfaces - add repo-native spec artifacts for the feature under `specs/177-inventory-coverage-truth` - add unit, feature, and browser coverage for truth derivation, continuity, and inventory item filter/pagination smoke paths ## Testing - `vendor/bin/sail bin pint --dirty --format agent` - focused Spec 177 browser smoke file passed with 2 tests / 57 assertions - extended inventory-focused test pack passed with 52 tests / 434 assertions Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #208
163 lines
5.6 KiB
Markdown
163 lines
5.6 KiB
Markdown
# Phase 1 Data Model: Inventory Coverage Truth (177)
|
|
|
|
## Existing Persisted Truth
|
|
|
|
### `OperationRun` as coverage basis
|
|
Represents the canonical execution record for inventory syncs and remains the source of per-type sync truth.
|
|
|
|
**Relevant existing fields**
|
|
- `workspace_id`
|
|
- `tenant_id`
|
|
- `type`
|
|
- `status`
|
|
- `outcome`
|
|
- `summary_counts`
|
|
- `failure_summary`
|
|
- `context`
|
|
- `started_at`
|
|
- `completed_at`
|
|
|
|
**Relevant existing inventory context shape**
|
|
- `context.inventory.coverage.policy_types`
|
|
- `context.inventory.coverage.foundation_types`
|
|
- each entry stores at minimum `status`
|
|
- optional fields already supported by `InventoryCoverage` normalization:
|
|
- `item_count`
|
|
- `error_code`
|
|
|
|
**Existing invariant**
|
|
- `InventoryCoverage::fromContext()` is the canonical parser for run coverage payload.
|
|
|
|
### `InventoryItem`
|
|
Represents last observed tenant inventory rows and remains the source of current observed-item counts.
|
|
|
|
**Relevant existing fields**
|
|
- `workspace_id`
|
|
- `tenant_id`
|
|
- `policy_type`
|
|
- `external_id`
|
|
- `display_name`
|
|
- `category`
|
|
- `platform`
|
|
- `meta_jsonb`
|
|
- `last_seen_at`
|
|
- `last_seen_operation_run_id`
|
|
|
|
**Existing invariant**
|
|
- Observed rows prove last observation only. They do not by themselves prove current tenant coverage completeness.
|
|
|
|
### `InventoryPolicyTypeMeta` + capability metadata
|
|
Represents product support and capability reference for supported and foundation types.
|
|
|
|
**Relevant existing fields and derived attributes**
|
|
- `type`
|
|
- `label`
|
|
- `category`
|
|
- `platform`
|
|
- `restore`
|
|
- `risk`
|
|
- foundation flag
|
|
- dependency support from `CoverageCapabilitiesResolver`
|
|
|
|
**Existing invariant**
|
|
- Capability metadata is product support truth, not tenant coverage truth.
|
|
|
|
## New Derived Runtime Contract
|
|
|
|
### `TenantCoverageTruth`
|
|
Derived runtime contract that answers the operator question: which supported types are currently covered for this tenant, which types need follow-up, and which run establishes that statement.
|
|
|
|
**Proposed fields**
|
|
- `tenant_id`
|
|
- `basis_run_id` nullable
|
|
- `basis_run_outcome` nullable
|
|
- `basis_completed_at` nullable
|
|
- `has_current_coverage_result` boolean
|
|
- `supported_type_count`
|
|
- `succeeded_type_count`
|
|
- `failed_type_count`
|
|
- `skipped_type_count`
|
|
- `unknown_type_count`
|
|
- `follow_up_type_count`
|
|
- `observed_item_total`
|
|
- `rows` list of `TenantCoverageTypeTruth`
|
|
|
|
**Derived invariants**
|
|
- Exactly one row exists for each supported policy type and foundation type currently in the product support catalog.
|
|
- `follow_up_type_count = failed + skipped + unknown`.
|
|
- `has_current_coverage_result` is true only when a completed inventory-sync basis run with parseable payload exists.
|
|
- The basis run is chosen independently from current item counts.
|
|
|
|
### `TenantCoverageTypeTruth`
|
|
Derived row contract for one supported type.
|
|
|
|
**Proposed fields**
|
|
- `type`
|
|
- `segment` (`policy` or `foundation`)
|
|
- `label`
|
|
- `category`
|
|
- `platform` nullable
|
|
- `coverage_state` (`succeeded`, `failed`, `skipped`, `unknown`)
|
|
- `follow_up_required` boolean
|
|
- `observed_item_count`
|
|
- `basis_error_code` nullable
|
|
- `restore_mode` nullable
|
|
- `risk_level` nullable
|
|
- `supports_dependencies` boolean
|
|
|
|
**Derived invariants**
|
|
- `follow_up_required` is true for `failed`, `skipped`, and `unknown`; false only for `succeeded`.
|
|
- `observed_item_count > 0` does not change `coverage_state`.
|
|
- `coverage_state = unknown` when the type is supported but absent from the basis run payload.
|
|
- `basis_error_code` is allowed only for non-succeeded payload-backed states.
|
|
|
|
## Derived State Family
|
|
|
|
### Coverage state family
|
|
This feature introduces one derived state family for tenant coverage rows:
|
|
|
|
- `Succeeded`
|
|
- the basis run reported the type as successfully processed
|
|
- `Failed`
|
|
- the basis run reported the type as attempted and failed
|
|
- `Skipped`
|
|
- the basis run reported the type as intentionally skipped or not processed during that run
|
|
- `Unknown`
|
|
- no current coverage result exists for the supported type in the basis run
|
|
|
|
**Behavioral consequence**
|
|
- `Failed`, `Skipped`, and `Unknown` all suppress calm claims and increment follow-up counts.
|
|
- `Unknown` is derived, not persisted.
|
|
|
|
## Relationships
|
|
|
|
- One `TenantCoverageTruth` resolves for one tenant at a time.
|
|
- One `TenantCoverageTruth` may reference zero or one basis `OperationRun`.
|
|
- One `TenantCoverageTruth` contains one row per supported product type from `InventoryPolicyTypeMeta::supported()` and `InventoryPolicyTypeMeta::foundations()`.
|
|
- Each `TenantCoverageTypeTruth` joins one supported type to zero or one payload-backed status from the basis run and zero or more `InventoryItem` rows from the current tenant observation set.
|
|
|
|
## Selection Rules
|
|
|
|
### Basis run selection
|
|
- candidate runs are `OperationRun` rows where:
|
|
- `tenant_id` matches the selected tenant
|
|
- `type = inventory_sync`
|
|
- `status = completed`
|
|
- candidates are ordered by:
|
|
- `completed_at DESC`
|
|
- `id DESC`
|
|
- the selected basis run is the first candidate whose `context.inventory.coverage` payload can be parsed by `InventoryCoverage::fromContext()`
|
|
- if no candidate qualifies, the tenant has no current coverage basis run
|
|
|
|
### Unknown derivation
|
|
- if a supported type is absent from both `policy_types` and `foundation_types` in the selected basis payload, the type is `Unknown`
|
|
- absence from the basis payload is not converted into `Skipped`
|
|
- item presence from older runs does not upgrade `Unknown`
|
|
|
|
## Validation Rules
|
|
|
|
- No schema migration is required.
|
|
- No new persisted state is introduced.
|
|
- Coverage rows must remain tenant-scoped.
|
|
- Capability metadata must not alter the derived coverage state.
|
|
- Surfaces may cite the basis run only when they can do so without violating authorization. |