Add PCI Vendor ID / Device ID to hardware.storage[] per the updated Reanimator
ingest contract, mirroring the existing pcie_devices[] fields. Populated for
Redfish-collected NVMe drives (live + TSR replay, via linked PCIeFunctions)
and for Inspur (from asset.json's own PcieInfo[], joined by PcieSlot). Also
fixes canonicalDevicesForExport dropping the fields when converting Storage
into the canonical HardwareDevice list used by the actual export path.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Implements the hardware.licenses[] contract section (v2.12, refreshed from
reanimator/core's hardware-ingest-contract.md — was v2.11 locally).
- models.License / HardwareConfig.Licenses mirror the contract field set.
- collector.collectLicenses() reads the standard DMTF
/redfish/v1/LicenseService/Licenses collection during Redfish-walk replay;
it's a generic DMTF resource, not Dell-specific, so any future vendor's
Redfish walk gets license collection for free through
ReplayRedfishFromRawPayloads.
- vendors/dell merges replayed Licenses like every other category.
- exporter.convertLicenses/dedupeLicenses wire hw.Licenses into the
reanimator export directly (no canonical-devices merge — licenses have no
physical identity to merge on), setting Present on every record from the
start (per the ADL-049 round-trip lesson).
- chart viewer renders a licenses section in /chart/current.
Verified end-to-end on the PowerEdge R7715 (1TVFYL4) TSR: 3 system-level
licenses extracted and correctly exported/rendered.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ReanimatorMemory.Present and ReanimatorPSU.Present were already declared as
*bool fields (matching ReanimatorStorage.Present), but convertMemoryFromDevices
and convertPSUsFromDevices never set them, unlike convertStorageFromDevices.
Exported JSON therefore had "present" for storage but not for memory/PSU
items. Re-importing a previously exported reanimator.json via
parseUploadedSnapshot (a direct json.Unmarshal into models.AnalysisResult)
left Present=false on those two categories, and the existing
IsInstalledInventory()/present-required filters then dropped them on the next
/chart/current render — reproduced live: fresh TSR upload showed Memory and
Power Supplies correctly, re-uploading the exported reanimator.json for the
same result did not.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Supermicro HGX BMC reports all 8 B200 GPU PCIe devices with Name
"PCIe Device" — a generic label shared by every GPU, not a unique
hardware position. pcieDedupKey used slot as the primary key, so all
8 GPUs collapsed to one entry in the UI (the first, serial 1654925165720).
Add isGenericPCIeSlotName to detect non-positional slot labels and fall
through to serial/BDF for dedup instead, preserving each GPU separately.
Positional slots (#GPU0, SLOT-NIC1, etc.) continue to use slot-first dedup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
isDeviceBoundFirmwareName did not catch Supermicro FirmwareInventory naming
conventions where a digit follows the type prefix directly ("GPU1 System Slot0",
"NIC1 System Slot0 AOM-DP805-IO") instead of a space. Also missing: "Power supply N",
"NVMeController N", and "Software Inventory" (generic label for all HGX per-component
firmware slots — GPU, NVSwitch, PCIeRetimer, ERoT, InfoROM, etc.).
On SYS-A21GE-NBRT (HGX B200) this caused 29 device-bound entries to leak into
hardware.firmware: 8 GPU, 9 NIC, 1 NVMe, 6 PSU, 4 PCIeSwitch, 1 Software Inventory.
Fix: extend isDeviceBoundFirmwareName with patterns for all four new cases.
Add TestIsDeviceBoundFirmwareName covering both excluded and kept entries.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement export to Reanimator format for asset tracking integration.
Features:
- New API endpoint: GET /api/export/reanimator
- Web UI button "Экспорт Reanimator" in Configuration tab
- Auto-detect CPU manufacturer (Intel/AMD/ARM/Ampere)
- Generate PCIe serial numbers if missing
- Merge GPUs and NetworkAdapters into pcie_devices
- Filter components without serial numbers
- RFC3339 timestamp format
- Full compliance with Reanimator specification
Changes:
- Add reanimator_models.go: data models for Reanimator format
- Add reanimator_converter.go: conversion functions
- Add reanimator_converter_test.go: unit tests
- Add reanimator_integration_test.go: integration tests
- Update handlers.go: add handleExportReanimator
- Update server.go: register /api/export/reanimator route
- Update index.html: add export button
- Update CLAUDE.md: document export behavior
- Add REANIMATOR_EXPORT.md: implementation summary
Tests: All tests passing (15+ new tests)
Format spec: example/docs/INTEGRATION_GUIDE.md
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>