mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-24 04:33:17 +00:00
044dc091ec
Follows #2627, which left PVE disk alert references out of resource history: binding the path reference failed review because a binding belongs to the reference string, so any disk that takes over the path inherits every row and every read of it. A physical disk's history (facets, timeline and intelligence APIs, Assistant resource context, Patrol's scoped feed) therefore never showed its own SMART health and wearout alerts. This owns each lifecycle row instead of binding the reference. **Write** - `proxmoxDiskAlertMetadata` now records `disk_wwn` next to `disk_serial`. - `MonitorAdapter.RecordChange` writes a PVE disk alert row under the one physical disk the registry knows by that serial or WWN (`proxmoxDiskAlertOwner`), wherever it sits now. A WWN only breaks a tie between two matches; it never rules a disk out, because the registry keeps a merged agent's smartctl-framed WWN (`5-c500-…`), which doesn't compare equal to PVE's (`0x5000c500…`). The registry only translates identity into a canonical ID. The path never breaks a tie, so a generation that still places another disk at the path cannot gain a row that disk does not match by identity, and no check precedes a later write. A disk not yet in inventory, or removed, gets the ID the registry mints for its identity unless another resource holds it. A row with no usable identity names only the one identity-less disk at its path. Anything else stays under the reference. - An owned row records the alert's reference as `alert_resource_id`. No alias is written, the reference is never queued for the legacy backfill, and `resolveHistoryReference` refuses it. - Rows journaled before this change stay under the reference, unrewritten (journal rows are never rewritten; retention is 30 days). **Read** - A store read by the reference (rows and every count, SQLite and MemoryStore) also returns the rows owned away from it. They are matched through the indexed alert identifier plus the recorded reference, so the Alerts history Resource action lists the same occurrences as before. - `QueryIncidents` matches owned rows to occurrences under their alert reference, while their evidence keeps the owning disk. Reads by alert identifier and by the reference return the same occurrences as before, including one occurrence whose firing and resolution two disks own. A read by a disk admits the saved shells of its own occurrences. An owned row whose firing the read lacks takes the occurrence or saved shell at its recorded start (shells within the usual tolerance), or opens it under the alert-centric read's ID, before events are assigned. That boundary is not canonical, so capped reads keep their guard. Notes recorded from a disk read reach the occurrence the alert-centric read shows. **Known residuals (in the unified-resources contract)** - History follows inventory where inventory merges: same-serial disks, a serial carried at a path when a poll reports none, and disks correlated with an agent observation by path. - When PVE and the agent share no identifier for such a disk (a SAS address reported as the serial), or the alert fired before the PVE observation reached the registry, the row carries the minted ID. The disk's history omits it, and reads by the reference still return it. - A disk the registry keys by its agent's WWN alone also carries PVE's serial, so a different disk reporting that same serial, before its first poll reaches the registry, has its row written under the first disk. - Two occurrences of one alert starting within the shell tolerance: the alert-centric read assigns a saved shell by firing order, which a disk read missing a firing cannot reproduce. **Tests** - `TestProxmoxDiskAlertRowsFollowRecordedHardwareIdentity` (SQLite and memory): reboot reorder before the registry catches up, replacement before and after its first poll, WWN-only, path-only, placeholder serial, counts. - `TestProxmoxDiskAlertOwnerDecisions`: shared serials, WWN tie-break, agent-framed WWN, RAID volume (full NAA serial, truncated WWN), minted ID already held, identity-less paths. - `TestHistoryIdentityNeverBindsProxmoxDiskAlertReferences`, which replaces `TestHistoryIdentityLeavesProxmoxDiskAlertReferencesUnbound`. - `TestProxmoxDiskAlertReferenceReadUsesIndexes`: the read by reference uses the canonical and alert-identifier indexes, not a scan. - `TestIncidentQueryKeepsOccurrencesOfHardwareOwnedDiskAlerts` compares the journaled and owned layouts for alert-identifier, `StartedAt` and reference reads, plus disk reads, notes, evidence and a split occurrence with no shell, an exact shell and an offset shell, on both stores. `TestIncidentQueryTruncatedReadKeepsOwnedOccurrencesGuarded` covers capped reads. - `TestCheckDiskHealthAlertsCarryHistoryOwnershipIdentity`: the producer's alert identifiers match `ProxmoxPhysicalDiskAlertIdentifiers`. - `TestProxmoxDiskAlertTimelineFollowsRecordedHardware`: real alert manager, reboot reorder, incidents by reference and by disk. - Each new test fails against the code it guards (checked by reverting it). **Live check** (private mock-mode build, fresh data dir): 6 fired rows and 1 acknowledgement, all owned by the disk their serial names. No aliases. Each disk's timeline API returns its rows. `/api/ai/incidents?resource_id=<reference>` and `?resource_id=<disk>` return the same incident (same saved ID; fired and acknowledged events whose evidence names the disk).