584 lines
30 KiB
Markdown
584 lines
30 KiB
Markdown
# 10 — Architectural Decision Log (ADL)
|
||
|
||
> **Rule:** Every significant architectural decision **must be recorded here** before or alongside
|
||
> the code change. This applies to humans and AI assistants alike.
|
||
>
|
||
> Format: date · title · context · decision · consequences
|
||
|
||
---
|
||
|
||
## ADL-001 — In-memory only state (no database)
|
||
|
||
**Date:** project start
|
||
**Context:** LOGPile is designed as a standalone diagnostic tool, not a persistent service.
|
||
**Decision:** All parsed/collected data lives in `Server.result` (in-memory). No database, no files written.
|
||
**Consequences:**
|
||
- Data is lost on process restart — intentional.
|
||
- Simple deployment: single binary, no setup required.
|
||
- JSON export is the persistence mechanism for users who want to save results.
|
||
|
||
---
|
||
|
||
## ADL-002 — Vendor parser auto-registration via init()
|
||
|
||
**Date:** project start
|
||
**Context:** Need an extensible parser registry without a central factory function.
|
||
**Decision:** Each vendor parser registers itself in its package's `init()` function.
|
||
`vendors/vendors.go` holds blank imports to trigger registration.
|
||
**Consequences:**
|
||
- Adding a new parser requires only: implement interface + add one blank import.
|
||
- No central list to maintain (other than the import file).
|
||
- `go test ./...` will include new parsers automatically.
|
||
|
||
---
|
||
|
||
## ADL-003 — Highest-confidence parser wins
|
||
|
||
**Date:** project start
|
||
**Context:** Multiple parsers may partially match an archive (e.g. generic + specific vendor).
|
||
**Decision:** Run all parsers' `Detect()`, select the one returning the highest score (0–100).
|
||
**Consequences:**
|
||
- Generic fallback (score 15) only activates when no vendor parser scores higher.
|
||
- Parsers must be conservative with high scores (70+) to avoid false positives.
|
||
|
||
---
|
||
|
||
## ADL-004 — Canonical hardware.devices as single source of truth
|
||
|
||
**Date:** v1.5.0
|
||
**Context:** UI tabs and Reanimator exporter were reading from different sub-fields of
|
||
`AnalysisResult`, causing potential drift.
|
||
**Decision:** Introduce `hardware.devices` as the canonical inventory repository.
|
||
All UI tabs and all exporters must read exclusively from this repository.
|
||
**Consequences:**
|
||
- Any UI vs Reanimator discrepancy is classified as a bug, not a "known difference".
|
||
- Deduplication logic runs once in the repository builder (serial → bdf → distinct).
|
||
- New hardware attributes must be added to canonical schema first, then mapped to consumers.
|
||
|
||
---
|
||
|
||
## ADL-005 — No hardcoded PCI model strings; use pci.ids
|
||
|
||
**Date:** v1.5.0
|
||
**Context:** NVIDIA and other vendors release new GPU models frequently; hardcoded maps
|
||
required code changes for each new model ID.
|
||
**Decision:** Use the `pciutils/pciids` database (git submodule, embedded at build time).
|
||
PCI vendor/device ID → human-readable model name via lookup.
|
||
**Consequences:**
|
||
- New GPU models can be supported by updating `pci.ids` without code changes.
|
||
- `make build` auto-syncs `pci.ids` from submodule before compilation.
|
||
- External override via `LOGPILE_PCI_IDS_PATH` env var.
|
||
|
||
---
|
||
|
||
## ADL-006 — Reanimator export uses canonical hardware.devices (not raw sub-fields)
|
||
|
||
**Date:** v1.5.0
|
||
**Context:** Early Reanimator exporter read from `Hardware.GPUs`, `Hardware.NICs`, etc.
|
||
directly, diverging from UI data.
|
||
**Decision:** Reanimator exporter must use `hardware.devices` — the same source as the UI.
|
||
Exporter groups/filters canonical records by section; does not rebuild from sub-fields.
|
||
**Consequences:**
|
||
- Guarantees UI and export consistency.
|
||
- Exporter code is simpler — mainly a filter+map, not a data reconstruction.
|
||
|
||
---
|
||
|
||
## ADL-007 — Documentation language is English
|
||
|
||
**Date:** 2026-02-20
|
||
**Context:** Codebase documentation was mixed Russian/English, reducing clarity for
|
||
international contributors and AI assistants.
|
||
**Decision:** All maintained project documentation (`docs/bible/`, `README.md`,
|
||
`CLAUDE.md`, and new technical docs) must be written in English.
|
||
**Consequences:**
|
||
- Bible is authoritative in English.
|
||
- AI assistants get consistent, unambiguous context.
|
||
|
||
---
|
||
|
||
## ADL-008 — Bible is the single source of truth for architecture docs
|
||
|
||
**Date:** 2026-02-23
|
||
**Context:** Architecture information was duplicated across `README.md`, `CLAUDE.md`,
|
||
and the Bible, creating drift risk and stale guidance for humans and AI agents.
|
||
**Decision:** Keep architecture and technical design documentation only in `docs/bible/`.
|
||
Top-level `README.md` and `CLAUDE.md` must remain minimal pointers/instructions.
|
||
**Consequences:**
|
||
- Reduces documentation drift and duplicate updates.
|
||
- AI assistants are directed to one authoritative source before making changes.
|
||
- Documentation updates that affect architecture must include Bible changes (and ADL entries when significant).
|
||
|
||
---
|
||
|
||
## ADL-009 — Redfish analysis is performed from raw snapshot replay (unified tunnel)
|
||
|
||
**Date:** 2026-02-24
|
||
**Context:** Live Redfish collection and raw export re-analysis used different parsing paths,
|
||
which caused drift and made bug fixes difficult to validate consistently.
|
||
**Decision:** Redfish live collection must produce a `raw_payloads.redfish_tree` snapshot first,
|
||
then run the same replay analyzer used for imported raw exports.
|
||
**Consequences:**
|
||
- Same `redfish_tree` input produces the same parsed result in live and offline modes.
|
||
- Debugging parser issues can be done against exported raw bundles without live BMC access.
|
||
- Snapshot completeness becomes critical; collector seeds/limits are part of analyzer correctness.
|
||
|
||
---
|
||
|
||
## ADL-010 — Raw export is a self-contained re-analysis package (not a final result dump)
|
||
|
||
**Date:** 2026-02-24
|
||
**Context:** Exporting only normalized `AnalysisResult` loses raw source fidelity and prevents
|
||
future parser improvements from being applied to already collected data.
|
||
**Decision:** `Export Raw Data` produces a self-contained raw package (JSON or ZIP bundle)
|
||
that the application can reopen and re-analyze. Parsed data in the package is optional and not
|
||
the source of truth on import.
|
||
**Consequences:**
|
||
- Re-opening an export always re-runs analysis from raw source (`redfish_tree` or uploaded file bytes).
|
||
- Raw bundles include collection context and diagnostics for debugging (`collect.log`, `parser_fields.json`).
|
||
- Endpoint compatibility is preserved (`/api/export/json`) while actual payload format may be a bundle.
|
||
|
||
---
|
||
|
||
## ADL-011 — Redfish snapshot crawler is bounded, prioritized, and failure-tolerant
|
||
|
||
**Date:** 2026-02-24
|
||
**Context:** Full Redfish trees on modern GPU systems are large, noisy, and contain many
|
||
vendor-specific or non-fetchable links. Unbounded crawling and naive queue design caused hangs
|
||
and incomplete snapshots.
|
||
**Decision:** Use a bounded snapshot crawler with:
|
||
- explicit document cap (`LOGPILE_REDFISH_SNAPSHOT_MAX_DOCS`)
|
||
- priority seed paths (PCIe/Fabrics/Firmware/Storage/PowerSubsystem/ThermalSubsystem)
|
||
- normalized `@odata.id` paths (strip `#fragment`)
|
||
- noisy expected error filtering (404/405/410/501 hidden from UI)
|
||
- queue capacity sized to crawl cap to avoid producer/consumer deadlock
|
||
**Consequences:**
|
||
- Snapshot collection remains stable on large BMC trees.
|
||
- Most high-value inventory paths are reached before the cap.
|
||
- UI progress remains useful while debug logs retain low-level fetch failures.
|
||
|
||
---
|
||
|
||
## ADL-012 — Vendor-specific storage inventory probing is allowed as fallback
|
||
|
||
**Date:** 2026-02-24
|
||
**Context:** Some Supermicro BMCs expose empty standard `Storage/.../Drives` collections while
|
||
real disk inventory exists under vendor-specific `Disk.Bay` endpoints and enclosure links.
|
||
**Decision:** When standard drive collections are empty, collector/replay may probe vendor-style
|
||
`.../Drives/Disk.Bay.*` endpoints and follow `Storage.Links.Enclosures[*]` to recover physical drives.
|
||
**Consequences:**
|
||
- Higher storage inventory coverage on Supermicro HBA/HA-RAID/MRVL/NVMe backplane implementations.
|
||
- Replay must mirror the same probing behavior to preserve deterministic results.
|
||
- Probing remains bounded (finite candidate set) to avoid runaway requests.
|
||
|
||
---
|
||
|
||
## ADL-013 — PowerSubsystem is preferred over legacy Power on newer Redfish implementations
|
||
|
||
**Date:** 2026-02-24
|
||
**Context:** X14+/newer Redfish implementations increasingly expose authoritative PSU data in
|
||
`PowerSubsystem/PowerSupplies`, while legacy `/Power` may be incomplete or schema-shifted.
|
||
**Decision:** Prefer `Chassis/*/PowerSubsystem/PowerSupplies` as the primary PSU source and use
|
||
legacy `Chassis/*/Power` as fallback.
|
||
**Consequences:**
|
||
- Better compatibility with newer BMC firmware generations.
|
||
- Legacy systems remain supported without special-case collector selection.
|
||
- Snapshot priority seeds must include `PowerSubsystem` resources.
|
||
|
||
---
|
||
|
||
## ADL-014 — Threshold logic lives on the server; UI reflects status only
|
||
|
||
**Date:** 2026-02-24
|
||
**Context:** Duplicating threshold math in frontend and backend creates drift and inconsistent
|
||
highlighting (e.g. PSU mains voltage range checks).
|
||
**Decision:** Business threshold evaluation (e.g. PSU voltage nominal range) must be computed on
|
||
the server; frontend only renders status/flags returned by the API.
|
||
**Consequences:**
|
||
- Single source of truth for threshold policies.
|
||
- UI can evolve visually without re-implementing domain logic.
|
||
- API payloads may carry richer status semantics over time.
|
||
|
||
---
|
||
|
||
## ADL-015 — Supermicro crashdump archive parser removed from active registry
|
||
|
||
**Date:** 2026-03-01
|
||
**Context:** The Supermicro crashdump parser (`SMC Crash Dump Parser`) produced low-value
|
||
results for current workflows and was explicitly rejected as a supported archive path.
|
||
**Decision:** Remove `supermicro` vendor parser from active registration and project source.
|
||
Do not include it in `/api/parsers` output or parser documentation matrix.
|
||
**Consequences:**
|
||
- Supermicro crashdump archives (`CDump.txt` format) are no longer parsed by a dedicated vendor parser.
|
||
- Such archives fall back to other matching parsers (typically `generic`) unless a new replacement parser is added.
|
||
- Reintroduction requires a new parser package and an explicit registry import in `vendors/vendors.go`.
|
||
|
||
---
|
||
|
||
## ADL-016 — Device-bound firmware must not appear in hardware.firmware
|
||
|
||
**Date:** 2026-03-01
|
||
**Context:** Dell TSR `DCIM_SoftwareIdentity` lists firmware for every component (NICs,
|
||
PSUs, disks, backplanes) in addition to system-level firmware. Naively importing all entries
|
||
into `Hardware.Firmware` caused device firmware to appear twice in Reanimator: once in the
|
||
device's own record and again in the top-level firmware list.
|
||
**Decision:**
|
||
- `Hardware.Firmware` contains only system-level firmware (BIOS, BMC/iDRAC, CPLD,
|
||
Lifecycle Controller, storage controllers, BOSS).
|
||
- Device-bound entries (NIC, PSU, Disk, Backplane, GPU) must not be added to
|
||
`Hardware.Firmware`.
|
||
- Parsers must store the FQDD (or equivalent slot identifier) in `FirmwareInfo.Description`
|
||
so the Reanimator exporter can filter by FQDD prefix.
|
||
- The exporter's `isDeviceBoundFirmwareFQDD()` function performs this filter.
|
||
**Consequences:**
|
||
- Any new parser that ingests a per-device firmware inventory must follow the same rule.
|
||
- Device firmware is accessible only via the device's own record, not the firmware list.
|
||
|
||
---
|
||
|
||
## ADL-017 — Vendor-embedded MAC addresses must be stripped from model name fields
|
||
|
||
**Date:** 2026-03-01
|
||
**Context:** Dell TSR embeds MAC addresses directly in `ProductName` and `ElementName`
|
||
fields (e.g. `"NVIDIA ConnectX-6 Lx 2x 25G SFP28 OCP3.0 SFF - C4:70:BD:DB:56:08"`).
|
||
This caused model names to contain MAC addresses in NIC model, NIC firmware device name,
|
||
and potentially other fields.
|
||
**Decision:** Strip any ` - XX:XX:XX:XX:XX:XX` suffix from all model/name string fields
|
||
at parse time before storing in any model struct. Use the regex
|
||
`\s+-\s+([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$`.
|
||
**Consequences:**
|
||
- Model names are clean and consistent across all devices.
|
||
- All parsers must apply this stripping to any field used as a device name or model.
|
||
- Confirmed affected fields in Dell: `DCIM_NICView.ProductName`, `DCIM_SoftwareIdentity.ElementName`.
|
||
|
||
---
|
||
|
||
## ADL-018 — NVMe bay probe must be restricted to storage-capable chassis types
|
||
|
||
**Date:** 2026-03-12
|
||
**Context:** `shouldAdaptiveNVMeProbe` was introduced in `2fa4a12` to recover NVMe drives on
|
||
Supermicro BMCs that expose empty `Drives` collections but serve disks at direct `Disk.Bay.N`
|
||
paths. The function returns `true` for any chassis with an empty `Members` array. On
|
||
Supermicro HGX systems (SYS-A21GE-NBRT and similar) ~35 sub-chassis (GPU, NVSwitch,
|
||
PCIeRetimer, ERoT, IRoT, BMC, FPGA) all carry `ChassisType=Module/Component/Zone` and
|
||
expose empty `/Drives` collections. Without filtering, each triggered 384 HTTP requests →
|
||
13 440 requests ≈ 22 minutes of pure I/O waste per collection.
|
||
**Decision:** Before probing `Disk.Bay.N` candidates for a chassis, check its `ChassisType`
|
||
via `chassisTypeCanHaveNVMe`. Skip if type is `Module`, `Component`, or `Zone`. Keep probing
|
||
for `Enclosure`, `RackMount`, and any unrecognised type (fail-safe).
|
||
**Consequences:**
|
||
- On HGX systems post-probe NVMe goes from ~22 min to effectively zero.
|
||
- NVMe backplane recovery (`Enclosure` type) is unaffected.
|
||
- Any new chassis type that hosts NVMe storage is covered by the default `true` path.
|
||
- `chassisTypeCanHaveNVMe` and the candidate-selection loop must have unit tests covering
|
||
both the excluded types and the storage-capable types (see `TestChassisTypeCanHaveNVMe`
|
||
and `TestNVMePostProbeSkipsNonStorageChassis`).
|
||
|
||
## ADL-019 — isDeviceBoundFirmwareName must cover vendor-specific naming patterns per vendor
|
||
|
||
**Date:** 2026-03-12
|
||
**Context:** `isDeviceBoundFirmwareName` was written to filter Dell-style device firmware names
|
||
(`"GPU SomeDevice"`, `"NIC OnboardLAN"`). When Supermicro Redfish FirmwareInventory was added
|
||
(`6c19a58`), no Supermicro-specific patterns were added. Supermicro names a NIC entry
|
||
`"NIC1 System Slot0 AOM-DP805-IO"` — a digit follows the type prefix directly, bypassing the
|
||
`"nic "` (space-terminated) check. 29 device-bound entries leaked into `hardware.firmware` on
|
||
SYS-A21GE-NBRT (HGX B200). Commit `9c5512d` attempted a fix by adding `_fw_gpu_` patterns,
|
||
but checked `DeviceName` which contains `"Software Inventory"` (from the Redfish `Name` field),
|
||
not the firmware inventory ID. The patterns were dead code from the moment they were committed.
|
||
**Decision:**
|
||
- `isDeviceBoundFirmwareName` must be extended for each new vendor whose FirmwareInventory
|
||
naming convention differs from the existing patterns.
|
||
- When adding HGX/Supermicro patterns, check that the pattern matches the field value that
|
||
`collectFirmwareInventory` actually stores — trace the data path from Redfish doc to
|
||
`FirmwareInfo.DeviceName` before writing the condition.
|
||
- `TestIsDeviceBoundFirmwareName` must contain at least one case per vendor format.
|
||
**Consequences:**
|
||
- New vendors with FirmwareInventory support require a test covering both device-bound names
|
||
(must return true) and system-level names (must return false) before the code ships.
|
||
- The dead `_fw_gpu_` / `_fw_nvswitch_` / `_inforom_gpu_` patterns were replaced with
|
||
correct prefix+digit checks (`"gpu" + digit`, `"nic" + digit`) and explicit string checks
|
||
(`"nvmecontroller"`, `"power supply"`, `"software inventory"`).
|
||
|
||
## ADL-020 — Dell TSR device-bound firmware filtered via FQDD; InfiniBand routed to NetworkAdapters
|
||
|
||
**Date:** 2026-03-15
|
||
**Context:** Dell TSR `sysinfo_DCIM_SoftwareIdentity.xml` lists firmware for every installed
|
||
component. `parseSoftwareIdentityXML` dumped all of these into `hardware.firmware` without
|
||
filtering, so device-bound entries such as `"Mellanox Network Adapter"` (FQDD `InfiniBand.Slot.1-1`)
|
||
and `"PERC H755 Front"` (FQDD `RAID.SL.3-1`) appeared in the reanimator export alongside system
|
||
firmware like BIOS and iDRAC. Confirmed on PowerEdge R6625 (8VS2LG4).
|
||
|
||
Additionally, `DCIM_InfiniBandView` was not handled in the parser switch, so Mellanox ConnectX-6
|
||
appeared only as a PCIe device with `model: "16x or x16"` (from `DataBusWidth` fallback).
|
||
`parseControllerView` called `addFirmware` with description `"storage controller"` instead of the
|
||
FQDD, so the FQDD-based filter in the exporter could not remove it.
|
||
|
||
**Decision:**
|
||
1. `isDeviceBoundFirmwareFQDD` extended with `"infiniband."` and `"fc."` prefixes; `"raid.backplane."`
|
||
broadened to `"raid."` to cover `RAID.SL.*`, `RAID.Integrated.*`, etc.
|
||
2. `DCIM_InfiniBandView` routed to `parseNICView` → device appears as `NetworkAdapter` with correct
|
||
firmware, MAC address, and VendorID/DeviceID.
|
||
3. `"InfiniBand."` added to `pcieFQDDNoisePrefix` to suppress the duplicate `DCIM_PCIDeviceView`
|
||
entry (DataBusWidth-only, no useful data).
|
||
4. `parseControllerView` now passes `fqdd` as the `addFirmware` description so the FQDD filter
|
||
removes the entry in the exporter.
|
||
5. `parsePCIeDeviceView` now prioritises `props["description"]` (chip model, e.g. `"MT28908 Family
|
||
[ConnectX-6]"`) over `props["devicedescription"]` (location string) for `pcie.Description`.
|
||
6. `convertPCIeDevices` model fallback order: `PartNumber → Description → DeviceClass`.
|
||
|
||
**Consequences:**
|
||
- `hardware.firmware` contains only system-level entries; NIC/RAID/storage-controller firmware
|
||
lives on the respective device record.
|
||
- `TestParseDellInfiniBandView` and `TestIsDeviceBoundFirmwareFQDD` guard the regression.
|
||
- Any future Dell TSR device class whose FQDD prefix is not yet in the prefix list may still leak;
|
||
extend `isDeviceBoundFirmwareFQDD` and add a test case when encountered.
|
||
|
||
---
|
||
|
||
## ADL-021 — pci.ids enrichment: chip model and vendor resolved from PCI IDs when source data is generic or missing
|
||
|
||
**Date:** 2026-03-15
|
||
**Context:**
|
||
Dell TSR `DCIM_InfiniBandView.ProductName` reports a generic marketing name ("Mellanox Network
|
||
Adapter") instead of the precise chip identifier ("MT28908 Family [ConnectX-6]"). The actual
|
||
chip model is available in `pci.ids` by VendorID:DeviceID (15B3:101B). Vendor name may also be
|
||
absent when no `VendorName` / `Manufacturer` property is present.
|
||
|
||
The general rule was established: *if model is not found in source data but PCI IDs are known,
|
||
resolve model from `pci.ids`*. This rule applies broadly across all export paths.
|
||
|
||
**Decision (two-layer enrichment):**
|
||
1. **Parser layer (Dell, `parseNICView`):** When `VendorID != 0 && DeviceID != 0`, prefer
|
||
`pciids.DeviceName(vendorID, deviceID)` over the product name from logs. This makes the chip
|
||
identifier the primary model for NIC/InfiniBand adapters (more specific than marketing name).
|
||
Fill `Vendor` from `pciids.VendorName(vendorID)` when the vendor field is otherwise empty.
|
||
Same fallback applied in `parsePCIeDeviceView` for empty `Description`.
|
||
2. **Exporter layer (`convertPCIeFromDevices`):** General rule — when `d.Model == ""` after all
|
||
legacy fallbacks and `VendorID != 0 && DeviceID != 0`, set `model = pciids.DeviceName(...)`.
|
||
Also fill empty `manufacturer` from `pciids.VendorName(...)`. This covers all parsers/sources.
|
||
|
||
**Consequences:**
|
||
- Mellanox InfiniBand slot now reports `model: "MT28908 Family [ConnectX-6]"` and
|
||
`manufacturer: "Mellanox Technologies"` in the reanimator export.
|
||
- For NICs where pci.ids has no entry, the original product name is kept (pci.ids returns "").
|
||
- `TestParseDellInfiniBandView` asserts the model and vendor from pci.ids.
|
||
|
||
---
|
||
|
||
## ADL-022 — CPUAffinity parsed into NUMANode for PCIe, NIC, and controller devices
|
||
|
||
**Date:** 2026-03-15
|
||
**Context:**
|
||
Dell TSR DCIM view classes report `CPUAffinity` for NIC, InfiniBand, PCIe, and controller
|
||
devices. Values are "1", "2" (NUMA node index), or "Not Applicable" (for devices that bridge
|
||
both CPUs or have no CPU affinity). This data is needed for topology-aware diagnostics.
|
||
|
||
**Decision:**
|
||
- Add `NUMANode int` (JSON: `"numa_node,omitempty"`) to `models.PCIeDevice`,
|
||
`models.NetworkAdapter`, `models.HardwareDevice`, and `ReanimatorPCIe`.
|
||
- Parse from `props["cpuaffinity"]` using `parseIntLoose`: numeric values ("1", "2") map
|
||
directly; "Not Applicable" returns 0 (omitted via `omitempty`).
|
||
- Thread through `buildDevicesFromLegacy` (PCIe and NIC sections) and `convertPCIeFromDevices`.
|
||
- `parseControllerView` also parses CPUAffinity since RAID controllers have NUMA affinity.
|
||
|
||
**Consequences:**
|
||
- `numa_node: 1` or `2` appears in reanimator export for devices with known affinity.
|
||
- Value 0 / absent means "not reported" — covers both "Not Applicable" and sources that don't
|
||
provide CPUAffinity at all.
|
||
- `TestParseDellCPUAffinity` verifies numeric values parsed correctly and "Not Applicable"→0.
|
||
|
||
---
|
||
|
||
## ADL-023 — Reanimator export must match ingest contract exactly
|
||
|
||
**Date:** 2026-03-15
|
||
**Context:**
|
||
LOGPile's Reanimator export had drifted from the strict ingest contract. It emitted fields that
|
||
Reanimator does not currently accept (`status_at_collection`, `numa_node`),
|
||
while missing fields and sections now present in the contract (`hardware.sensors`,
|
||
`pcie_devices[].mac_addresses`). Memory export rules also diverged from the ingest side: empty or
|
||
serial-less DIMMs were still exported.
|
||
|
||
**Decision:**
|
||
- Treat the Reanimator ingest contract as the authoritative schema for `GET /api/export/reanimator`.
|
||
- Emit only fields present in the current upstream contract revision.
|
||
- Add `hardware.sensors`, `pcie_devices[].mac_addresses`, `pcie_devices[].numa_node`, and
|
||
upstream-approved component telemetry/health fields.
|
||
- Leave out fields that are still not part of the upstream contract.
|
||
- Map internal `source_type=archive` to external `source_type=logfile`.
|
||
- Skip memory entries that are empty, not present, or missing serial numbers.
|
||
- Generate CPU and PCIe serials only in the forms allowed by the contract.
|
||
- Mirror the applied contract in `bible-local/docs/hardware-ingest-contract.md`.
|
||
|
||
**Consequences:**
|
||
- Some previously exported diagnostic fields are intentionally dropped from the Reanimator payload
|
||
until the upstream contract adds them.
|
||
- Internal models may retain richer fields than the current export schema.
|
||
- `hardware.devices` is canonical only after merge with legacy hardware slices; partial parser-owned
|
||
canonical records must not hide CPUs, memory, storage, NICs, or PSUs still stored in legacy
|
||
fields.
|
||
- CSV and Reanimator exports must use the same merged canonical inventory to avoid divergent export
|
||
contents across surfaces.
|
||
- Future exporter changes must update both the code and the mirrored contract document together.
|
||
|
||
---
|
||
|
||
## ADL-024 — Component presence is implicit; Redfish linked metrics are part of replay correctness
|
||
|
||
**Date:** 2026-03-15
|
||
**Context:**
|
||
The upstream ingest contract allows `present`, but current export semantics do not need to send
|
||
`present=true` for populated components. At the same time, several important Redfish component
|
||
telemetry fields were only available through linked metric resources such as `ProcessorMetrics`,
|
||
`MemoryMetrics`, and `DriveMetrics`. Without collecting and replaying these linked documents,
|
||
live collection and raw snapshot replay still underreported component health fields.
|
||
|
||
**Decision:**
|
||
- Do not serialize `present=true` in Reanimator export. Presence is represented by the presence of
|
||
the component record itself.
|
||
- Do not export component records marked `present=false`.
|
||
- Interpret CPU `firmware` in Reanimator payload as CPU microcode.
|
||
- Treat Redfish linked metric resources `ProcessorMetrics`, `MemoryMetrics`, `DriveMetrics`,
|
||
`EnvironmentMetrics`, and generic `Metrics` as part of analyzer correctness when they are linked
|
||
from component resources.
|
||
- Replay logic must merge these linked metric resources back into CPU, memory, storage, PCIe, GPU,
|
||
NIC, and PSU component `Details` the same way live collection expects them to be used.
|
||
|
||
**Consequences:**
|
||
- Reanimator payloads are smaller and avoid redundant `present=true` noise while still excluding
|
||
empty slots and absent components.
|
||
- Any future exporter change that reintroduces serialized component presence needs an explicit
|
||
contract review.
|
||
- Raw Redfish snapshot completeness now includes linked per-component metric resources, not only
|
||
top-level inventory members.
|
||
- CPU microcode is no longer expected in top-level `hardware.firmware`; it belongs on the CPU
|
||
component record.
|
||
|
||
<!-- Add new decisions below this line using the format above -->
|
||
|
||
## ADL-025 — Missing serial numbers must remain absent in Reanimator export
|
||
|
||
**Date:** 2026-03-15
|
||
**Context:**
|
||
LOGPile previously generated synthetic serial numbers for components that had no real serial in
|
||
source data, especially CPUs and PCIe-class devices. This made the payload look richer, but the
|
||
serials were not authoritative and could mislead downstream consumers. Reanimator can already
|
||
accept missing serials and generate its own internal fallback identifiers when needed.
|
||
|
||
**Decision:**
|
||
- Do not synthesize fake serial numbers in LOGPile's Reanimator export.
|
||
- If a component has no real serial in parsed source data, export the serial field as absent.
|
||
- This applies to CPUs, PCIe devices, GPUs, NICs, and any other component class unless an
|
||
upstream contract explicitly requires a deterministic exporter-generated identifier.
|
||
- Any fallback serial generation defined by the upstream contract is ingest-side Reanimator behavior,
|
||
not LOGPile exporter behavior.
|
||
|
||
**Consequences:**
|
||
- Exported payloads carry only source-backed serial numbers.
|
||
- Fake identifiers such as `BOARD-...-CPU-...` or synthetic PCIe serials are no longer considered
|
||
acceptable exporter behavior.
|
||
- Any future attempt to reintroduce generated serials requires an explicit contract review and a
|
||
new ADL entry.
|
||
|
||
---
|
||
|
||
## ADL-026 — Live Redfish collection uses explicit preflight host-power confirmation
|
||
|
||
**Date:** 2026-03-15
|
||
**Context:**
|
||
Live Redfish inventory can be incomplete when the managed host is powered off. At the same time,
|
||
LOGPile must not silently power on a host without explicit user choice. The collection workflow
|
||
therefore needs a preflight step that verifies connectivity, shows current host power state to the
|
||
user, and only powers on the host when the user explicitly chose that path.
|
||
|
||
**Decision:**
|
||
- Add a dedicated live preflight API step before collection starts.
|
||
- UI first runs connectivity and power-state check, then offers:
|
||
- collect as-is
|
||
- power on and collect
|
||
- if the host is off and the user does not answer within 5 seconds, default to collecting without
|
||
powering the host on
|
||
- Redfish collection may power on the host only when the request explicitly sets
|
||
`power_on_if_host_off=true`
|
||
- when LOGPile powers on the host for collection, it must try to power the host back off after
|
||
collection completes
|
||
- if LOGPile did not power the host on itself, it must never power the host off
|
||
- all preflight and power-control steps must be logged into the collection log and therefore into
|
||
the raw-export bundle
|
||
|
||
**Consequences:**
|
||
- Live collection becomes a two-step UX: probe first, collect second.
|
||
- Raw bundles preserve operator-visible evidence of power-state decisions and power-control attempts.
|
||
- Power-on failures do not block collection entirely; they only downgrade completeness expectations.
|
||
|
||
---
|
||
|
||
## ADL-027 — Sensors without numeric readings are not exported
|
||
|
||
**Date:** 2026-03-15
|
||
**Context:**
|
||
Some parsed sensor records carry only a name, unit, or status, but no actual numeric reading. Such
|
||
records are not useful as telemetry in Reanimator export and create noisy, low-value sensor lists.
|
||
|
||
**Decision:**
|
||
- Do not export temperature, power, fan, or other sensor records unless they carry a real numeric
|
||
measurement value.
|
||
- Presence of a sensor name or health/status alone is not sufficient for export.
|
||
|
||
**Consequences:**
|
||
- Exported sensor groups contain only actionable telemetry.
|
||
- Parsers and collectors may still keep non-numeric sensor artifacts internally for diagnostics, but
|
||
Reanimator export must filter them out.
|
||
|
||
---
|
||
|
||
## ADL-028 — Reanimator PCIe export excludes storage endpoints and synthetic serials
|
||
|
||
**Date:** 2026-03-15
|
||
**Context:**
|
||
Some Redfish and archive sources expose NVMe drives both as storage inventory and as PCIe-visible
|
||
endpoints. Exporting such drives in both `hardware.storage` and `hardware.pcie_devices` creates
|
||
duplicates without adding useful topology value. At the same time, PCIe-class export still had old
|
||
fallback behavior that generated synthetic serial numbers when source serials were absent.
|
||
|
||
**Decision:**
|
||
- Export disks and NVMe drives only through `hardware.storage`.
|
||
- Do not export storage endpoints as `hardware.pcie_devices`, even if the source inventory exposes
|
||
them as PCIe/NVMe devices.
|
||
- Keep real PCIe storage controllers such as RAID and HBA adapters in `hardware.pcie_devices`.
|
||
- Do not synthesize PCIe/GPU/NIC serial numbers in LOGPile; missing serials stay absent.
|
||
- Treat placeholder names such as `Network Device View` as non-authoritative and prefer resolved
|
||
device names when stronger data exists.
|
||
|
||
**Consequences:**
|
||
- Reanimator payloads no longer duplicate NVMe drives between storage and PCIe sections.
|
||
- PCIe export remains topology-focused while storage export remains component-focused.
|
||
- Missing PCIe-class serials no longer produce fake `BOARD-...-PCIE-...` identifiers.
|
||
|
||
---
|
||
|
||
## ADL-029 — Local exporter guidance tracks upstream contract v2.7 terminology
|
||
|
||
**Date:** 2026-03-15
|
||
**Context:**
|
||
The upstream Reanimator hardware ingest contract moved to `v2.7` and clarified several points that
|
||
matter for LOGPile documentation: ingest-side serial fallback rules, canonical PCIe addressing via
|
||
`slot`, the optional `event_logs` section, and the shared `manufactured_year_week` field.
|
||
|
||
**Decision:**
|
||
- Keep the local mirrored contract file as an exact copy of the upstream `v2.7` document.
|
||
- Describe CPU/PCIe serial fallback as Reanimator ingest behavior, not LOGPile exporter behavior.
|
||
- Treat `pcie_devices.slot` as the canonical address on the LOGPile side as well; `bdf` may remain
|
||
an internal fallback/dedupe key but is not serialized in the payload.
|
||
- Export `event_logs` only from normalized parser/collector events that can be mapped to contract
|
||
sources `host` / `bmc` / `redfish` without synthesizing message content.
|
||
- Export `manufactured_year_week` only as a reliable passthrough when a parser/collector already
|
||
extracted a valid `YYYY-Www` value.
|
||
|
||
**Consequences:**
|
||
- Local bible wording no longer conflicts with upstream contract terminology.
|
||
- Reanimator payloads use contract-native PCIe addressing and no longer expose `bdf` as a parallel
|
||
coordinate.
|
||
- LOGPile event export remains strictly source-derived; internal warnings such as LOGPile analysis
|
||
notes do not leak into Reanimator `event_logs`.
|