TenantAtlas/specs/177-inventory-coverage-truth/data-model.md
ahmido f52d52540c feat: implement inventory coverage truth (#208)
## 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
2026-04-05 12:35:20 +00:00

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.