# Runtime Flows And Invariants ## Event Time Source Priority Use component event time over ingest time whenever possible. - `eventFallbackTime(actual, ingestedAt, collectedAt)`: 1. `actual` 2. `ingestedAt` 3. `collectedAt` - `collectedFallbackTime(collectedAt, ingestedAt)`: 1. `collectedAt` 2. `ingestedAt` ## Status Event Time Parsing Order `parseComponentStatusEventTime` resolves time in this order: 1. `status_changed_at` 2. Latest matching `status_history` item for current status 3. Latest parseable `status_history` item 4. `status_checked_at` ## Failure Event Rules For critical components: - Timeline event type: `COMPONENT_FAILED` - `failure_events.failure_time` uses resolved failure time (not raw ingest time) - `failure_events.external_id` includes the same failure timestamp ## First Seen Rules `parts.first_seen_at` must be the earliest known ingest-derived component time. Candidate sources: 1. Parseable `status_history[].changed_at` 2. `status_changed_at` 3. `status_checked_at` 4. `eventFallbackTime(nil, ingestedAt, collectedAt)` Persistence rule: - Keep the minimum value over time. - If incoming is earlier than stored value, overwrite with incoming value. ## Duplicate Component Serial Rules (CSV + JSON Ingest) If serial numbers are not unique within the same `p/n` (`model`) inside one ingest payload: - First occurrence keeps original `vendor_serial`. - Each next duplicate occurrence is assigned a service serial placeholder: - Format: `NO_SN-XXXXXXXX` (8-digit zero-padded global counter). - If `vendor_serial` is empty, a service serial placeholder is assigned as well. - Counter is global for the whole application and stored in `id_sequences` under `entity_type = 'no_sn_placeholder'`. ## Component Health Computation In UI Component health is derived only from the latest status event among: - `COMPONENT_FAILED` - `COMPONENT_WARNING` - `COMPONENT_OK` Non-status timeline events (`INSTALLED`, `REMOVED`, `FIRMWARE_CHANGED`, `FIRMWARE_INSTALLED`, etc.) must not change health status. ## Firmware Timeline Rules For component firmware observations: - First observed version -> `FIRMWARE_INSTALLED` (asset + component timeline pair) - Later version change -> `FIRMWARE_CHANGED` (asset + component timeline pair) Storage details: - `FIRMWARE_INSTALLED` stores transition string in `timeline_events.firmware_version`: `- -> ` - `FIRMWARE_CHANGED` stores installed/new firmware value Detection details: - Previous observation lookup: `ORDER BY observed_at DESC, id DESC LIMIT 1 OFFSET 1` ## Timeline Color Semantics - `REMOVED` -> yellow - `COMPONENT_FAILED` -> red - `COMPONENT_WARNING` and related warning semantics follow `timelineEventClass` ## Regression Guardrails Do not reintroduce these regressions: - Using ingest timestamp when payload provides better event/failure timestamp - Letting `INSTALLED` mark failed components as healthy - Missing `Previous Components` section on asset page - Missing installation history on component page - Missing firmware information on component page timeline