{
  "format": "heart-fault-codes/1",
  "version": "1.0",
  "source": "HEART Part 3: Information Model, Section 5. The codes, H-numbers and meanings here MUST equal its tables; spec/tools/validate.py checks this.",
  "prefix": "Outside messages, write a code as HEART <code>, such as HEART storage.full. Inside messages, write it bare.",
  "areas": [
    {
      "area": "system",
      "number": "01",
      "covers": "The whole system"
    },
    {
      "area": "power",
      "number": "02",
      "covers": "Supply, battery, charging"
    },
    {
      "area": "connectivity",
      "number": "03",
      "covers": "Network and links to other systems"
    },
    {
      "area": "storage",
      "number": "04",
      "covers": "Disk, memory cards, databases"
    },
    {
      "area": "performance",
      "number": "05",
      "covers": "Speed, load, heat"
    },
    {
      "area": "software",
      "number": "06",
      "covers": "Crashes, versions, updates, settings"
    },
    {
      "area": "ai",
      "number": "07",
      "covers": "AI providers, models, budgets"
    },
    {
      "area": "sensors",
      "number": "08",
      "covers": "Readings and calibration"
    },
    {
      "area": "actuators",
      "number": "09",
      "covers": "Motors, valves, heaters, compressors"
    },
    {
      "area": "data",
      "number": "10",
      "covers": "Data quality, sync, backups"
    },
    {
      "area": "security",
      "number": "11",
      "covers": "Logins, certificates, tampering"
    }
  ],
  "codes": [
    {
      "code": "system.main-function-lost",
      "h": "H-01001",
      "area": "system",
      "title": "Main function lost",
      "meaning": "The system cannot do its main job. Every HEART MUST be able to detect this.",
      "severity": "critical",
      "causes": [
        "A part the main job depends on has failed: a burner that will not light, a camera that does not answer, a pump that has tripped.",
        "A safety device has stopped the job on purpose: a thermal-runaway cut-out on a 3D printer, an RCD trip on an EV charger, a dry-run lock-out on a pump.",
        "A consumable has run out: filament, water in a tank, paper, space on a memory card.",
        "Power to the part that does the work is gone, while the controller still runs on a battery or UPS.",
        "Every worker or service that serves customers is stuck or down, as on a web shop where no order can be taken."
      ],
      "fixes": [
        "Read the alert's explanation and cause: they say which part stopped and why, often with a second fault code.",
        "If a safety device tripped, find the reason before you reset it. Never bypass a cut-out to get the job running again.",
        "Refill or replace what ran out (filament, water, paper, card), then resume the job.",
        "Check power and fuses to the working part, and look for messages from the product's own controller or display.",
        "Restart the product only if its manual says that is safe. If the job stops again, stop and call service.",
        "To prevent it: follow the maintenance schedule, and act on earlier warnings such as system.main-function-degraded, power.battery-low or storage.nearly-full."
      ],
      "heartDoes": "Every HEART must notice this (Autonomy Level A1). It raises a critical alert, sets its status to failing, and tells a person through the owner's escalation route at once. A Playbook may try one safe step that the product allows, such as restarting a stuck software worker, but a HEART never resets a safety device or works around an interlock. The alert resolves by itself when the main job works again.",
      "whenToCallService": "At once if a safety device tripped (a thermal cut-out, an earth-leak trip, a welded contactor), if anything smells hot or looks damaged, or if the job stops again after one restart. For medical or life-safety products, follow the product's own emergency instructions first.",
      "appliesTo": [
        "Every product with a HEART"
      ],
      "related": [
        "system.main-function-degraded",
        "actuators.not-responding",
        "power.supply-lost",
        "storage.full",
        "software.crash-loop"
      ]
    },
    {
      "code": "system.main-function-degraded",
      "h": "H-01002",
      "area": "system",
      "title": "Main function degraded",
      "meaning": "The main job works, but less well than normal.",
      "severity": "warning",
      "causes": [
        "A part is wearing or fouled: a blocked filter or strainer, a weak heater cartridge, a pump starting to cavitate.",
        "A supply is running low but has not run out: a water tank below 20 %, a battery that limits power.",
        "The product has reduced its own output to protect itself, such as an EV charger derating from 32 A to 16 A when its connector is hot.",
        "One of several redundant parts has failed, so the job runs on the rest: one pump out of two, one worker out of eight.",
        "The conditions are outside what the product was sized for: a very cold day for a heat pump, a crowd on a web shop."
      ],
      "fixes": [
        "Read the explanation: it says what is weaker than normal and by how much.",
        "Clean or replace what is fouled: filters, strainers, nozzles, fans, sensors.",
        "Refill or recharge what is low before it runs out.",
        "Check for a second open alert, such as performance.too-hot or sensors.drift: it is often the real cause.",
        "To prevent it: keep to the maintenance schedule, and watch for this warning becoming more frequent."
      ],
      "heartDoes": "It raises a warning alert and sets its status to degraded. A Playbook may take a small step the product allows, such as switching to a standby part or reducing load, within its guards. It tells a person if the condition lasts. The alert resolves by itself when the job is back to normal.",
      "whenToCallService": "If it lasts more than a day, keeps coming back after cleaning, or turns into system.main-function-lost.",
      "appliesTo": [
        "Every product with a HEART"
      ],
      "related": [
        "system.main-function-lost",
        "performance.too-hot",
        "actuators.short-cycling",
        "sensors.drift"
      ]
    },
    {
      "code": "system.flatline",
      "h": "H-01003",
      "area": "system",
      "title": "No Pulse (flatline)",
      "meaning": "No Pulse for three intervals. Raised by whoever is watching, not by the system itself.",
      "severity": "error",
      "causes": [
        "The product is switched off, or has lost power with no backup.",
        "Its network link is down, so its Pulse cannot get out (the product itself may be fine).",
        "Its HEART has crashed or hung, while the product goes on working.",
        "The product is asleep longer than it said it would be, or did not say it sleeps at all.",
        "A firewall, router or Gateway between the product and its watcher blocks its reports."
      ],
      "fixes": [
        "Check that the product has power and is switched on.",
        "Check its network: Wi-Fi, cable, mobile signal, or the Gateway it reports through.",
        "Look at the product itself: if it still works, its HEART or its link is the problem, not the product.",
        "Restart the HEART, or the product if that is safe.",
        "For battery products that sleep: make sure each report says how long it will sleep, so a sleep is not mistaken for a flatline."
      ],
      "heartDoes": "A system never raises this about itself: it cannot. Whoever watches it, such as a Gateway or HEART Hub, raises it after three Pulse intervals with no Pulse, sets the status to unknown, and tells the owner (HEART Hub sends one email). It resolves by itself with the next Pulse.",
      "whenToCallService": "If the product has power and network but stays silent after a restart, or if it is a product that must never be unwatched, such as a medical transmitter or a pump station.",
      "appliesTo": [
        "Anything watched by a Gateway, a Command Center or HEART Hub"
      ],
      "related": [
        "connectivity.link-lost",
        "power.supply-lost",
        "system.heart-unwell",
        "system.unexpected-restart"
      ]
    },
    {
      "code": "system.unexpected-restart",
      "h": "H-01004",
      "area": "system",
      "title": "Unexpected restart",
      "meaning": "The system restarted without being asked to.",
      "severity": "warning",
      "causes": [
        "A short power cut or brown-out reset the processor.",
        "A watchdog reset the product because its software hung.",
        "The software crashed and restarted itself.",
        "The product overheated and shut down to protect itself.",
        "A hardware fault: a loose connector, a failing power supply, a damaged board."
      ],
      "fixes": [
        "Look in the Rhythm for what happened just before: a power event, a crash, a temperature rise.",
        "Check the power supply and its connections, and whether other devices on the same supply also restarted.",
        "Check for software.crashed or performance.too-hot alerts around the same time.",
        "Install the latest software update if one fixes resets.",
        "To prevent it: use a stable supply (a UPS for important equipment), and keep vents clear."
      ],
      "heartDoes": "After the restart it records the start (system.started, or system.restarted when it resumes from saved state), sees that nobody asked for a restart, and raises this alert with what it knows of the reason. It tells a person if restarts repeat.",
      "whenToCallService": "If it restarts several times a day, or after any restart that left the product in a wrong state.",
      "appliesTo": [
        "Every product with a HEART"
      ],
      "related": [
        "power.supply-unstable",
        "software.crashed",
        "software.crash-loop",
        "performance.too-hot"
      ]
    },
    {
      "code": "system.heart-unwell",
      "h": "H-01005",
      "area": "system",
      "title": "The HEART itself is unwell",
      "meaning": "The HEART itself has a problem. The product may be fine.",
      "severity": "warning",
      "causes": [
        "The HEART cannot save its state: its storage is full or read-only.",
        "One of its own checks or Playbooks keeps failing.",
        "Its configuration or signal table is invalid, so it cannot watch everything it should.",
        "It is short of memory or time on a small processor, so checks run late.",
        "It cannot read the product's data, for example after a firmware change on the product side."
      ],
      "fixes": [
        "Read the explanation: it says which part of the HEART is affected.",
        "Check the HEART's configuration and signal table against the product's current firmware.",
        "Free space or memory for the HEART, or restart it.",
        "Update the HEART software to the latest version."
      ],
      "heartDoes": "It reports this about itself, while the product goes on doing its job. It keeps watching what it still can, and tells a person. It does not act on the product while it is unwell.",
      "whenToCallService": "If it does not clear after a restart and an update. The product may still work, but it is not being watched properly.",
      "appliesTo": [
        "Every product with a HEART"
      ],
      "related": [
        "system.flatline",
        "software.config-invalid",
        "storage.write-failed",
        "performance.memory-exhausted"
      ]
    },
    {
      "code": "system.undo-failed",
      "h": "H-01006",
      "area": "system",
      "title": "A change could not be undone",
      "meaning": "A change the HEART made could not be undone, so the system is left changed. A person must look.",
      "severity": "critical",
      "causes": [
        "The HEART tried a change as a Trial, and the step that puts things back failed.",
        "The part it changed stopped answering, so the old setting could not be written back.",
        "Someone or something else changed the same setting in the meantime.",
        "The link to the product was lost during the undo."
      ],
      "fixes": [
        "Read the alert: it names the change, the old value and the new one.",
        "Check the setting on the product, and set it back by hand if it is still changed.",
        "Find out why the undo failed (a part not answering, a lost link) before allowing that Playbook again."
      ],
      "heartDoes": "It records tending.undo-failed, raises this critical alert, tells a person at once, and makes no further automatic change of the same kind until a person has looked.",
      "whenToCallService": "If you cannot set the value back yourself, or the changed setting matters for safety or for the product's main job.",
      "appliesTo": [
        "Products whose HEART makes changes on its own (Autonomy Level A3 and above)"
      ],
      "related": [
        "actuators.not-responding",
        "connectivity.link-lost",
        "system.main-function-degraded"
      ]
    },
    {
      "code": "power.supply-lost",
      "h": "H-02001",
      "area": "power",
      "title": "Main power lost",
      "meaning": "Main power is gone. Running on battery or backup, if any.",
      "severity": "error",
      "causes": [
        "A power cut in the building or the area.",
        "A tripped breaker or blown fuse on the product's supply.",
        "A loose or unplugged power cable or charger.",
        "A failed power adapter or internal power supply."
      ],
      "fixes": [
        "Check whether other equipment nearby also lost power.",
        "Check the breaker, fuse, plug and cable.",
        "If it runs on a battery or UPS now, note how long that lasts, and save work or stop safely before it runs out.",
        "Replace a failed adapter with one of the right rating.",
        "To prevent it: give important equipment a UPS or backup battery, and test it."
      ],
      "heartDoes": "If it has a battery, UPS or a supercapacitor, it sends this alert while it still can, and tells a person. It may reduce its own load to last longer. It resolves the alert by itself when main power returns. With no backup at all, its watcher sees system.flatline instead.",
      "whenToCallService": "If power does not return after checking breakers and fuses, or a breaker trips again at once.",
      "appliesTo": [
        "Mains-powered products, especially those with a battery, UPS or backup supply"
      ],
      "related": [
        "power.supply-unstable",
        "system.flatline",
        "power.battery-low",
        "system.unexpected-restart"
      ]
    },
    {
      "code": "power.supply-unstable",
      "h": "H-02002",
      "area": "power",
      "title": "Power supply unstable",
      "meaning": "Voltage or supply is outside the normal range.",
      "severity": "warning",
      "causes": [
        "Grid voltage outside its range, such as outside 207 to 253 V on a 230 V supply.",
        "A weak or overloaded adapter, or a long thin cable that drops voltage under load.",
        "Large loads switching nearby: motors, compressors, welders.",
        "A loose connection that heats and makes voltage jump."
      ],
      "fixes": [
        "Check the readings in the alert: too high, too low, or jumping.",
        "Check plugs, terminals and cables for looseness or heat.",
        "Use the right adapter, and a shorter or thicker cable.",
        "Move the product to another circuit, away from large switching loads.",
        "To prevent it: a line conditioner or UPS for sensitive equipment."
      ],
      "heartDoes": "It raises a warning with the readings, and may ask the product to reduce load or delay heavy work, if the product allows it. It resolves when the supply is back in range.",
      "whenToCallService": "If it comes from the building's supply (call an electrician or the grid operator), or if any connection is warm or discoloured.",
      "appliesTo": [
        "Mains- and battery-powered products",
        "Chargers, motors and anything that draws a large current"
      ],
      "related": [
        "power.supply-lost",
        "system.unexpected-restart",
        "actuators.overcurrent"
      ]
    },
    {
      "code": "power.battery-low",
      "h": "H-02003",
      "area": "power",
      "title": "Battery low",
      "meaning": "The battery needs charging soon.",
      "severity": "warning",
      "causes": [
        "Normal use since the last charge.",
        "Too little sun or wind for a self-charging product, such as a solar camera in winter.",
        "Cold weather, which lowers a battery's usable charge.",
        "More use than normal: more reports, more pictures, a longer motor run.",
        "An implant or long-life device reaching its planned replacement point."
      ],
      "fixes": [
        "Charge or replace the battery.",
        "For solar products: clean the panel and check that it faces the sun.",
        "Reduce what drains it, such as how often it reports, if the product allows it.",
        "For a medical implant: book the planned replacement with the clinic, as the alert says.",
        "To prevent it: charge on a schedule, and replace batteries before winter."
      ],
      "heartDoes": "It raises a warning with the charge left and, where it knows it, the time left. It may save power on its own, such as reporting less often, if a Playbook allows it. It resolves when the battery is charged.",
      "whenToCallService": "Only if the battery does not charge, or empties much faster than before: then see power.battery-failing.",
      "appliesTo": [
        "Battery products: trackers, sensors, cameras, wall units, implants, robots"
      ],
      "related": [
        "power.battery-failing",
        "power.supply-lost",
        "system.flatline"
      ]
    },
    {
      "code": "power.battery-failing",
      "h": "H-02004",
      "area": "power",
      "title": "Battery failing",
      "meaning": "The battery no longer holds charge as it should.",
      "severity": "error",
      "causes": [
        "The battery is old: its capacity has faded after many charge cycles.",
        "Heat has damaged it, for example from a device left in a hot car or in the sun.",
        "A deep discharge or long storage when empty.",
        "A failed cell, or a fault in the charging circuit."
      ],
      "fixes": [
        "Replace the battery with the type the maker specifies.",
        "If it is swollen, hot or leaking, stop using the product, and keep it away from anything that burns.",
        "Check the charger and cable: a fault there can look like a bad battery.",
        "To prevent it: avoid heat, avoid running it flat, and store batteries part-charged."
      ],
      "heartDoes": "It raises an error alert, using the trend of charge and discharge it has seen, and tells a person. It cannot fix a battery.",
      "whenToCallService": "Always, if the battery is built in, swollen or hot, or belongs to a medical or safety product.",
      "appliesTo": [
        "Battery products"
      ],
      "related": [
        "power.battery-low",
        "performance.too-hot",
        "system.unexpected-restart"
      ]
    },
    {
      "code": "connectivity.link-lost",
      "h": "H-03001",
      "area": "connectivity",
      "title": "Network link lost",
      "meaning": "A network link is down.",
      "severity": "warning",
      "causes": [
        "The Wi-Fi access point or router is off, restarting or out of range.",
        "A changed Wi-Fi password, or a router replaced by a new one.",
        "No mobile signal, such as a tracker in thick woods or underground.",
        "A cable unplugged or damaged.",
        "The network operator or internet provider has an outage."
      ],
      "fixes": [
        "Check that the router or access point is on, and that other devices can connect.",
        "Move the product or the access point closer, or add a repeater.",
        "Re-enter the Wi-Fi details if the network changed.",
        "Check cables and connectors.",
        "To prevent it: a stable access point within good range, and a wired link for important equipment."
      ],
      "heartDoes": "It goes on working without the network: it keeps watching, keeps private events on the product, and may try to reconnect. It sends this alert when the link is back, so a watcher may first see system.flatline. It resolves when the link works again.",
      "whenToCallService": "If the link drops every day, or the product cannot rejoin a network that works for everything else.",
      "appliesTo": [
        "Every connected product"
      ],
      "related": [
        "connectivity.link-unstable",
        "system.flatline",
        "connectivity.dependency-unreachable"
      ]
    },
    {
      "code": "connectivity.link-unstable",
      "h": "H-03002",
      "area": "connectivity",
      "title": "Network link unstable",
      "meaning": "A link keeps dropping or is very slow.",
      "severity": "warning",
      "causes": [
        "Weak signal at the edge of Wi-Fi or mobile range.",
        "Radio interference: microwaves, other networks on the same channel, metal walls.",
        "A crowded network, or a router that is overloaded.",
        "A loose or damaged cable or antenna."
      ],
      "fixes": [
        "Check the signal strength the product reports, if it does.",
        "Move the product or the access point, or fit a better antenna.",
        "Change the Wi-Fi channel, or move to a less crowded band.",
        "Replace damaged cables or connectors."
      ],
      "heartDoes": "It raises a warning with how often the link dropped, and may send fewer or smaller reports while the link is poor. It resolves when the link has been steady for a while.",
      "whenToCallService": "If the link stays unstable after moving the product and checking the network.",
      "appliesTo": [
        "Every connected product"
      ],
      "related": [
        "connectivity.link-lost",
        "performance.slow",
        "data.missing"
      ]
    },
    {
      "code": "connectivity.dependency-unreachable",
      "h": "H-03003",
      "area": "connectivity",
      "title": "A service it relies on cannot be reached",
      "meaning": "An outside service or system it relies on cannot be reached.",
      "severity": "error",
      "causes": [
        "An outside service is down: a payment provider, a cloud API, a backend.",
        "A controller the HEART reads from stopped answering, such as a PLC behind a gateway or a charger's main controller.",
        "Wrong address, or credentials that expired.",
        "A firewall rule or network change blocks the way."
      ],
      "fixes": [
        "Read the alert: it names the service or part that does not answer.",
        "Check that service's own status page, or the controller's power and cable.",
        "Check addresses, keys and certificates in the settings.",
        "Check firewall and network changes made recently.",
        "To prevent it: a second provider where possible, and timeouts that fail safely."
      ],
      "heartDoes": "It raises an error alert, often after several failed tries (component.failed events) in a short time. A Playbook may retry or switch to a second provider if the product has one. It resolves when the service answers again (component.recovered).",
      "whenToCallService": "If the service is one you run yourself, or the controller stays silent with power and cable in order.",
      "appliesTo": [
        "Servers and apps that use outside services",
        "Gateways in front of controllers or PLCs"
      ],
      "related": [
        "connectivity.link-lost",
        "ai.provider-unavailable",
        "performance.backlog"
      ]
    },
    {
      "code": "connectivity.clock-unsynced",
      "h": "H-03004",
      "area": "connectivity",
      "title": "Clock not synchronised",
      "meaning": "The clock cannot be checked against a time source.",
      "severity": "warning",
      "causes": [
        "No network access to a time server (NTP), or NTP blocked by a firewall.",
        "A flat clock battery, so the clock resets after each power cut.",
        "A wrong time-server address in the settings.",
        "A product that has been offline for a long time."
      ],
      "fixes": [
        "Check that the product can reach a time server.",
        "Replace the clock battery if it has one.",
        "Set the right time-server address.",
        "Run sync_time if the product offers it."
      ],
      "heartDoes": "It raises a warning and marks the times it records as uncertain. A Playbook may run sync_time. It resolves once the clock has been checked against a time source. A wrong clock matters: certificates, logs and schedules depend on it.",
      "whenToCallService": "If the clock keeps drifting or resetting after a new battery.",
      "appliesTo": [
        "Every connected product, especially those using certificates or schedules"
      ],
      "related": [
        "security.certificate-expired",
        "data.invalid",
        "connectivity.link-lost"
      ]
    },
    {
      "code": "storage.nearly-full",
      "h": "H-04001",
      "area": "storage",
      "title": "Storage nearly full",
      "meaning": "Storage is almost full (the system states the threshold).",
      "severity": "warning",
      "causes": [
        "Pictures, video or recordings not yet collected, such as on a camera's memory card.",
        "Log files that are never rotated.",
        "A database growing without clean-up.",
        "Updates or temporary files left behind."
      ],
      "fixes": [
        "Collect or move the data you want to keep.",
        "Delete old logs, temporary files and old updates.",
        "Set log rotation and retention, so old data is removed by itself.",
        "Fit a larger card or disk."
      ],
      "heartDoes": "It raises a warning at the threshold the product states, such as 10 % free. A Playbook may rotate old logs or run compact_storage, within its guards. It resolves when space is back above the threshold.",
      "whenToCallService": "Rarely. Only if space fills again within hours, which points to a fault that writes too much.",
      "appliesTo": [
        "Cameras, recorders, servers, gateways, anything that stores data"
      ],
      "related": [
        "storage.full",
        "storage.write-failed",
        "data.backup-failed"
      ]
    },
    {
      "code": "storage.full",
      "h": "H-04002",
      "area": "storage",
      "title": "Storage full",
      "meaning": "Storage is full. Writing new data fails.",
      "severity": "error",
      "causes": [
        "A storage.nearly-full warning was not acted on.",
        "A fault writes far too much, such as a log in a tight error loop.",
        "Recordings not collected, so the card filled.",
        "A backup or update that needs more space than there is."
      ],
      "fixes": [
        "Free space now: move or delete old recordings, logs and temporary files.",
        "Find what filled it: look at the biggest and newest files.",
        "Fix the cause if one program writes too much, then set retention limits.",
        "Fit a larger card or disk.",
        "To prevent it: act on storage.nearly-full, and keep automatic clean-up switched on."
      ],
      "heartDoes": "It raises an error alert. New data is being lost, so it may also raise system.main-function-lost if the main job needs storage, such as a camera that cannot save pictures. A Playbook may rotate logs or remove temporary files. It resolves when writing works again.",
      "whenToCallService": "If space cannot be freed, or it fills again soon after.",
      "appliesTo": [
        "Cameras, recorders, servers, gateways, anything that stores data"
      ],
      "related": [
        "storage.nearly-full",
        "storage.write-failed",
        "system.main-function-lost"
      ]
    },
    {
      "code": "storage.write-failed",
      "h": "H-04003",
      "area": "storage",
      "title": "Write failed",
      "meaning": "Data could not be written, for a reason other than being full.",
      "severity": "error",
      "causes": [
        "A memory card or disk is failing, or was removed.",
        "The file system was switched to read-only after an error.",
        "Wrong permissions on a folder.",
        "A network drive or database that is not reachable."
      ],
      "fixes": [
        "Check that the card or disk is in place and seated well.",
        "Check the file system for errors, and its permissions.",
        "Replace a card or disk that keeps failing.",
        "Restore from backup if data was damaged."
      ],
      "heartDoes": "It raises an error alert with the path or store that failed, and may retry. It cannot repair hardware. It resolves when writes succeed again.",
      "whenToCallService": "If the store is built in, or writes fail after the card or disk has been replaced.",
      "appliesTo": [
        "Anything that stores data"
      ],
      "related": [
        "storage.corrupted",
        "storage.wearing-out",
        "storage.full"
      ]
    },
    {
      "code": "storage.wearing-out",
      "h": "H-04004",
      "area": "storage",
      "title": "Storage wearing out",
      "meaning": "Storage hardware is near the end of its life.",
      "severity": "warning",
      "causes": [
        "Flash memory near its rated number of writes, as on SD cards and eMMC.",
        "A disk reporting reallocated or pending sectors.",
        "Heavy logging to cheap flash for a long time."
      ],
      "fixes": [
        "Back up the data now.",
        "Plan to replace the card or disk soon.",
        "Write less: lower log levels, keep logs in memory, use storage made for endurance."
      ],
      "heartDoes": "It raises a warning from the storage's own health figures (such as SMART or flash wear), and tells a person well before the store fails. It resolves only when the store is replaced.",
      "whenToCallService": "If the storage is built in and cannot be replaced by the owner.",
      "appliesTo": [
        "Products with flash cards, eMMC, SSDs or disks"
      ],
      "related": [
        "storage.write-failed",
        "storage.corrupted",
        "data.backup-failed"
      ]
    },
    {
      "code": "storage.corrupted",
      "h": "H-04005",
      "area": "storage",
      "title": "Storage corrupted",
      "meaning": "Stored data or the file system is damaged.",
      "severity": "error",
      "causes": [
        "Power lost while writing.",
        "A failing card, disk or flash chip.",
        "A software bug that wrote bad data.",
        "A card removed while in use."
      ],
      "fixes": [
        "Stop writing to it, so nothing more is lost.",
        "Run the file-system check or the product's repair tool.",
        "Restore from the last good backup.",
        "Replace the storage if it keeps happening.",
        "To prevent it: a stable supply, and safe removal of cards."
      ],
      "heartDoes": "It raises an error alert, stops using the damaged data where it can, and falls back to defaults or the last good copy if the product has one. It tells a person.",
      "whenToCallService": "If the product will not start properly, or data that matters cannot be restored.",
      "appliesTo": [
        "Anything that stores data"
      ],
      "related": [
        "storage.write-failed",
        "data.integrity-failed",
        "power.supply-lost"
      ]
    },
    {
      "code": "performance.slow",
      "h": "H-05001",
      "area": "performance",
      "title": "Responses slow",
      "meaning": "Responses take much longer than normal.",
      "severity": "warning",
      "causes": [
        "A slow database or outside service.",
        "Too little CPU or memory for the load.",
        "A full disk or a failing one.",
        "A slow or unstable network link."
      ],
      "fixes": [
        "Look at what is slow: the alert gives the time taken against the normal time.",
        "Check the services it waits on, and their own speed.",
        "Check CPU, memory and disk use.",
        "Add capacity, or move heavy work to a quieter time."
      ],
      "heartDoes": "It raises a warning when responses pass the product's stated limit, such as 1.5 s at the 95th percentile, and resolves it when they are back under it. A Playbook may clear a cache or throttle low-priority work, within its guards.",
      "whenToCallService": "If it lasts and you cannot find a cause in load, network or outside services.",
      "appliesTo": [
        "Servers, apps, gateways, any product that answers requests"
      ],
      "related": [
        "performance.overloaded",
        "performance.backlog",
        "connectivity.link-unstable"
      ]
    },
    {
      "code": "performance.overloaded",
      "h": "H-05002",
      "area": "performance",
      "title": "Overloaded",
      "meaning": "More work is arriving than can be handled.",
      "severity": "warning",
      "causes": [
        "A peak in demand: a sale on a web shop, many devices reporting at once.",
        "Fewer workers or servers than normal, after some failed.",
        "A client or device sending far too many requests.",
        "Heavy background work at a busy time."
      ],
      "fixes": [
        "Check whether the load is real demand or a fault (one client sending too much).",
        "Add capacity, or turn on more workers.",
        "Limit the rate of busy clients, and delay background work."
      ],
      "heartDoes": "It raises a warning, and may throttle low-priority work if a Playbook allows it. It does not add paid capacity by itself: it asks a person. It resolves when load is back within capacity.",
      "whenToCallService": "If the load comes from a fault or an attack, or capacity cannot be added.",
      "appliesTo": [
        "Servers, apps and gateways"
      ],
      "related": [
        "performance.backlog",
        "performance.slow",
        "security.anomaly"
      ]
    },
    {
      "code": "performance.backlog",
      "h": "H-05003",
      "area": "performance",
      "title": "Backlog growing",
      "meaning": "A queue of waiting work keeps growing.",
      "severity": "warning",
      "causes": [
        "Work arrives faster than it is handled.",
        "A worker or consumer is stuck, so its queue grows.",
        "An outside service it hands work to is down.",
        "Messages waiting to be sent while a link is down."
      ],
      "fixes": [
        "Find which queue grows, and what should be emptying it.",
        "Restart a stuck worker, or add workers.",
        "Fix the outside service or link, then let the queue drain."
      ],
      "heartDoes": "It raises a warning when the queue passes the product's limit, such as 500 waiting requests. A Playbook may restart a stuck worker. It resolves when the queue is back under the limit.",
      "whenToCallService": "If the queue keeps growing with workers running and services up.",
      "appliesTo": [
        "Servers, apps, gateways and devices that queue data"
      ],
      "related": [
        "performance.overloaded",
        "connectivity.dependency-unreachable",
        "software.crashed"
      ]
    },
    {
      "code": "performance.memory-exhausted",
      "h": "H-05004",
      "area": "performance",
      "title": "Memory exhausted",
      "meaning": "Memory is (nearly) used up.",
      "severity": "error",
      "causes": [
        "A memory leak in a program.",
        "A cache allowed to grow without limit.",
        "More load than the memory was sized for.",
        "Too many programs on a small device."
      ],
      "fixes": [
        "Find which program uses the memory.",
        "Restart it to recover memory now.",
        "Limit cache sizes, and fix or update a program that leaks.",
        "Add memory, or move work to a larger machine."
      ],
      "heartDoes": "It raises an error alert at the product's limit, such as 90 % used. A Playbook may clear a cache or restart the component that holds the memory, within its guards and interlocks (for example only if the cache is not doing its job). It resolves when use falls back.",
      "whenToCallService": "If it comes back within hours after a restart: that points to a leak.",
      "appliesTo": [
        "Servers, apps, gateways, controllers with an operating system"
      ],
      "related": [
        "software.crashed",
        "performance.slow",
        "system.heart-unwell"
      ]
    },
    {
      "code": "performance.too-hot",
      "h": "H-05005",
      "area": "performance",
      "title": "Too hot",
      "meaning": "The device is overheating and may slow itself down.",
      "severity": "warning",
      "causes": [
        "A fan stopped or a vent is blocked by dust.",
        "The product is in the sun, in a closed box, or in a parked car.",
        "A motor, pump or connector working harder than it should, or a loose high-current connection.",
        "A heatsink that came loose."
      ],
      "fixes": [
        "Check fans and vents; clean the dust.",
        "Move the product out of the sun, or shade its box.",
        "Check connectors for discoloured or loose contacts.",
        "Let it cool before using it hard again.",
        "To prevent it: keep air flowing, and keep filters clean."
      ],
      "heartDoes": "It raises a warning before the product's own protection cuts in, with the temperature and the limit. The product itself may already slow down or derate (an EV charger dropping to 16 A, a processor slowing). A HEART never overrides that protection. It resolves when the temperature falls back.",
      "whenToCallService": "If anything smells hot or looks scorched, if a motor or connector is hot, or it keeps coming back with fans and vents clean.",
      "appliesTo": [
        "Every product with electronics, motors, heaters or batteries"
      ],
      "related": [
        "system.main-function-degraded",
        "actuators.overcurrent",
        "power.battery-failing"
      ]
    },
    {
      "code": "performance.overshoot",
      "h": "H-05006",
      "area": "performance",
      "title": "Overshoot",
      "meaning": "A controlled value goes past its target by more than the system's stated limit, such as a room getting colder than its setpoint.",
      "severity": "warning",
      "causes": [
        "A controller tuned too aggressively, such as a PID on a 3D printer's hotend.",
        "Outside heat or cold the controller does not see: sun through a window, a door left open.",
        "A sensor in the wrong place, or reading late.",
        "A valve or heater that does not shut off fully."
      ],
      "fixes": [
        "Check the readings: how far past the target, and for how long.",
        "Check the sensor's place and reading against another thermometer or gauge.",
        "Re-tune the controller, or use the product's auto-tune.",
        "Check that the valve or heater really switches off."
      ],
      "heartDoes": "It raises a warning when the value goes past its target by more than the product's stated limit, such as 1.5 °C. It does not retune the controller by itself. It resolves when the value is back near the target.",
      "whenToCallService": "If it continues after tuning, or the value overshoots in a way that could do harm (too hot, too high a pressure).",
      "appliesTo": [
        "Thermostats, heating and cooling, irrigation, printers, anything that controls a value"
      ],
      "related": [
        "sensors.drift",
        "actuators.position-mismatch",
        "actuators.short-cycling"
      ]
    },
    {
      "code": "software.error-spike",
      "h": "H-06001",
      "area": "software",
      "title": "Error spike",
      "meaning": "Errors are happening far more often than normal.",
      "severity": "warning",
      "causes": [
        "A new release with a bug.",
        "An outside service returning errors.",
        "Bad input from one client or device.",
        "A setting changed by mistake."
      ],
      "fixes": [
        "Look at which errors grew, and since when.",
        "Compare with recent releases or setting changes, and roll back if one matches.",
        "Check outside services it uses."
      ],
      "heartDoes": "It raises a warning when the error rate is far above normal. A Playbook may roll back a recent change or switch providers, within its guards. It resolves when the rate is back to normal.",
      "whenToCallService": "If the errors affect customers or the main job, and no recent change explains them.",
      "appliesTo": [
        "Servers, apps and any product with logs of errors"
      ],
      "related": [
        "software.crashed",
        "connectivity.dependency-unreachable",
        "software.config-invalid"
      ]
    },
    {
      "code": "software.crashed",
      "h": "H-06002",
      "area": "software",
      "title": "Crashed",
      "meaning": "A program or component crashed.",
      "severity": "warning",
      "causes": [
        "A bug met an unusual input.",
        "Memory ran out.",
        "A worker hung and stopped answering.",
        "A library or driver failed."
      ],
      "fixes": [
        "Restart the component.",
        "Check memory, and the logs just before the crash.",
        "Update the software if a fix exists."
      ],
      "heartDoes": "It raises a warning, and a Playbook may restart the component (restart_component) within its limits, such as six a day and 60 s apart. If it crashes again soon after, the alert becomes software.crash-loop and goes to a person. It resolves when the component answers again.",
      "whenToCallService": "If it crashes more than once a day.",
      "appliesTo": [
        "Every product with software"
      ],
      "related": [
        "software.crash-loop",
        "performance.memory-exhausted",
        "system.unexpected-restart"
      ]
    },
    {
      "code": "software.crash-loop",
      "h": "H-06003",
      "area": "software",
      "title": "Crash loop",
      "meaning": "A component keeps crashing and restarting.",
      "severity": "error",
      "causes": [
        "A fault a restart cannot fix: bad settings, damaged data, a missing file.",
        "A broken update.",
        "A part it needs at start-up is missing or down."
      ],
      "fixes": [
        "Stop restarting it: read the logs of the first crash.",
        "Roll back the last update or setting change.",
        "Check the files and services it needs at start-up."
      ],
      "heartDoes": "It stops restarting the component on its own, raises an error alert, and escalates to a person. This is what a failed restart Playbook leaves behind. It resolves when the component runs steadily again.",
      "whenToCallService": "If rolling back does not stop it.",
      "appliesTo": [
        "Every product with software"
      ],
      "related": [
        "software.crashed",
        "software.update-failed",
        "software.config-invalid"
      ]
    },
    {
      "code": "software.update-failed",
      "h": "H-06004",
      "area": "software",
      "title": "Update failed",
      "meaning": "An update did not install.",
      "severity": "warning",
      "causes": [
        "The download was cut off or damaged.",
        "The signature check failed, so the update was refused.",
        "Not enough space.",
        "Power or network lost during installation."
      ],
      "fixes": [
        "Check space, power and network, then try again.",
        "Make sure the update comes from the maker and is signed.",
        "If the product rolled back, it is safe on the old version: try later."
      ],
      "heartDoes": "It raises a warning with the reason, and keeps or returns to the last working version. It never installs an unsigned update. It resolves when an update succeeds or a person dismisses it.",
      "whenToCallService": "If updates keep failing, or the product does not start after one.",
      "appliesTo": [
        "Every product that receives updates"
      ],
      "related": [
        "software.version-mismatch",
        "storage.full",
        "security.tamper-detected"
      ]
    },
    {
      "code": "software.config-invalid",
      "h": "H-06005",
      "area": "software",
      "title": "Settings invalid",
      "meaning": "Settings are wrong or contradict each other.",
      "severity": "error",
      "causes": [
        "A setting outside its allowed range.",
        "Two settings that contradict each other.",
        "A file edited by hand with a mistake.",
        "Settings left over from an older version."
      ],
      "fixes": [
        "Read the alert: it names the setting.",
        "Correct it, or roll back to the last good settings.",
        "Check settings after each update."
      ],
      "heartDoes": "It refuses the bad settings where it can and keeps the last good ones. It raises an error alert. A Playbook may roll back to the last good version.",
      "whenToCallService": "If you cannot find the setting, or the product will not start.",
      "appliesTo": [
        "Every product with settings"
      ],
      "related": [
        "software.crash-loop",
        "software.version-mismatch",
        "system.heart-unwell"
      ]
    },
    {
      "code": "software.version-mismatch",
      "h": "H-06006",
      "area": "software",
      "title": "Version mismatch",
      "meaning": "Parts that must work together have incompatible versions.",
      "severity": "warning",
      "causes": [
        "Only one of two parts was updated.",
        "A spare part with older firmware was fitted.",
        "An app and its device on different versions."
      ],
      "fixes": [
        "Read which parts and versions disagree.",
        "Update the older part, or roll back the newer.",
        "Use the maker's update tool, which updates them together."
      ],
      "heartDoes": "It raises a warning and names the parts and versions. It may refuse to use a feature both do not support.",
      "whenToCallService": "If the parts cannot be brought to matching versions by the owner.",
      "appliesTo": [
        "Products made of several parts with their own software"
      ],
      "related": [
        "software.update-failed",
        "software.config-invalid"
      ]
    },
    {
      "code": "ai.provider-unavailable",
      "h": "H-07001",
      "area": "ai",
      "title": "AI provider unavailable",
      "meaning": "The AI model or provider cannot be reached.",
      "severity": "warning",
      "causes": [
        "The AI provider has an outage, or limits the product's requests.",
        "The network link to the provider is down.",
        "An API key that expired or was revoked.",
        "A local model that did not load, for lack of memory or a missing file."
      ],
      "fixes": [
        "Check the provider's status page.",
        "Check the network and the API key.",
        "For a local model: check memory and the model file.",
        "Set a second provider or a local model, so the product can fall back."
      ],
      "heartDoes": "It falls back to its next way of thinking (from cloud to local, or to rules only), records ai.tier.changed, and keeps doing its job without the model. A Playbook may switch providers (switch_provider). It raises a warning, and resolves it when the provider answers again.",
      "whenToCallService": "Rarely: a HEART must work without its model. Only if the fallback does not work.",
      "appliesTo": [
        "Products that use an AI model"
      ],
      "related": [
        "ai.lease-expired",
        "connectivity.dependency-unreachable",
        "ai.budget-exceeded"
      ]
    },
    {
      "code": "ai.cost-spike",
      "h": "H-07002",
      "area": "ai",
      "title": "AI cost spike",
      "meaning": "AI spending is rising much faster than normal.",
      "severity": "warning",
      "causes": [
        "A loop that calls the model again and again.",
        "Much more use than normal, or a new feature that calls the model often.",
        "A change to a larger, more expensive model.",
        "Someone else using the product's API key."
      ],
      "fixes": [
        "Look at which calls grew, and since when.",
        "Fix loops, and cache answers that repeat.",
        "Check that the key is not leaked; rotate it if in doubt.",
        "Set or lower the budget."
      ],
      "heartDoes": "It raises a warning when spending rises much faster than normal. It may throttle model calls or move to a cheaper way of thinking, if a Playbook allows it. It resolves when spending is back to its normal rate.",
      "whenToCallService": "If the key may have leaked, or the cost cannot be explained.",
      "appliesTo": [
        "Products that use an AI model"
      ],
      "related": [
        "ai.budget-near-limit",
        "ai.budget-exceeded",
        "security.anomaly"
      ]
    },
    {
      "code": "ai.budget-near-limit",
      "h": "H-07003",
      "area": "ai",
      "title": "AI budget near its limit",
      "meaning": "AI spending has reached 80% of the budget.",
      "severity": "info",
      "causes": [
        "Normal use that has reached 80 % of the budget.",
        "A budget set too low for real use.",
        "A cost spike earlier in the period."
      ],
      "fixes": [
        "Look at what used the budget so far this period.",
        "Check for a cost spike or a loop, and fix it first.",
        "Decide whether to raise the budget or to use the model less for the rest of the period."
      ],
      "heartDoes": "It tells a person, and may use the model less for the rest of the period. It resolves at the start of the next budget period, or when the budget is raised.",
      "whenToCallService": "Not needed.",
      "appliesTo": [
        "Products that use an AI model"
      ],
      "related": [
        "ai.budget-exceeded",
        "ai.cost-spike"
      ]
    },
    {
      "code": "ai.budget-exceeded",
      "h": "H-07004",
      "area": "ai",
      "title": "AI budget used up",
      "meaning": "The AI budget is used up. AI calls are stopped.",
      "severity": "warning",
      "causes": [
        "Normal use has spent the budget for the period.",
        "A cost spike or a loop used it up early.",
        "The budget was set lower than real use needs."
      ],
      "fixes": [
        "Find and fix any loop or spike first.",
        "Raise the budget if the use was worth it, or wait for the next period.",
        "Check that the product still does its job without the model, as a HEART must."
      ],
      "heartDoes": "It stops calling the model, and goes on with local thinking or rules only. It never spends past the budget. It resolves when the next period starts or the budget is raised.",
      "whenToCallService": "Not needed, unless the product does not work without the model, which a HEART must.",
      "appliesTo": [
        "Products that use an AI model"
      ],
      "related": [
        "ai.budget-near-limit",
        "ai.cost-spike",
        "ai.provider-unavailable"
      ]
    },
    {
      "code": "ai.model-drift",
      "h": "H-07005",
      "area": "ai",
      "title": "AI model drift",
      "meaning": "The AI model's answers have changed in quality or behaviour.",
      "severity": "warning",
      "causes": [
        "The provider changed or updated the model behind the same name.",
        "The product's data has changed, so the model sees things it was not tested on.",
        "A new model was adopted that behaves differently."
      ],
      "fixes": [
        "Compare recent answers against the product's own checks and test cases.",
        "Pin a model version if the provider allows it.",
        "Roll back to the model that worked, and test the new one before adopting it."
      ],
      "heartDoes": "It raises a warning when the quality or behaviour of answers changes, measured against its own checks. It may stop using the model for actions while the alert is open.",
      "whenToCallService": "If the model takes part in decisions that matter, and the drift cannot be explained.",
      "appliesTo": [
        "Products that use an AI model"
      ],
      "related": [
        "ai.output-rejected",
        "ai.answer-rejected",
        "ai.disagreement"
      ]
    },
    {
      "code": "ai.output-rejected",
      "h": "H-07006",
      "area": "ai",
      "title": "AI output rejected",
      "meaning": "AI suggestions keep failing the HEART's checks.",
      "severity": "warning",
      "causes": [
        "The model proposes actions outside what the product allows.",
        "It names parts, settings or values that do not exist.",
        "The model or its instructions changed.",
        "A poor prompt, or missing data in what the model is given."
      ],
      "fixes": [
        "Look at the rejected suggestions and the reason for each.",
        "Check the model version and its instructions.",
        "Use a better model, or give it the data it lacks."
      ],
      "heartDoes": "It refuses each suggestion that fails its checks, so nothing unsafe is done, records why, and raises a warning when this keeps happening. It may stop asking the model until a person looks.",
      "whenToCallService": "Not usually: the HEART has already refused the bad suggestions.",
      "appliesTo": [
        "Products that use an AI model"
      ],
      "related": [
        "ai.model-drift",
        "ai.answer-rejected",
        "ai.disagreement"
      ]
    },
    {
      "code": "ai.lease-expired",
      "h": "H-07007",
      "area": "ai",
      "title": "Brain lease expired",
      "meaning": "The brain lease ran out without a renewal, so the system is brainless.",
      "severity": "warning",
      "causes": [
        "The Command Center that renews the lease is unreachable.",
        "The network link is down.",
        "The lease was deliberately not renewed.",
        "The product's clock is wrong, so the lease looks expired."
      ],
      "fixes": [
        "Check the link to the Command Center.",
        "Check the product's clock.",
        "Renew the lease from the Command Center once it is reachable."
      ],
      "heartDoes": "It works on without its brain, as it must: rules and local checks only. It acts no further on the brain's advice. It resolves when a valid lease arrives.",
      "whenToCallService": "If the lease cannot be renewed with the network and Command Center working.",
      "appliesTo": [
        "Products with a brain lease (Autonomy Level A3 and above with a brain)"
      ],
      "related": [
        "ai.brain-revoked",
        "connectivity.link-lost",
        "connectivity.clock-unsynced"
      ]
    },
    {
      "code": "ai.brain-revoked",
      "h": "H-07008",
      "area": "ai",
      "title": "Brain revoked",
      "meaning": "The brain was cut: by a Command Center signal, by the owner, or by the system's own tripwire.",
      "severity": "warning",
      "causes": [
        "The owner cut the brain on purpose.",
        "A Command Center sent the cut signal, for example for a fleet-wide problem.",
        "The product's own tripwire cut it, after the brain did something it must not."
      ],
      "fixes": [
        "Read who cut it, and why.",
        "Fix the reason before giving the brain back.",
        "Restore the brain only through the owner or the Command Center."
      ],
      "heartDoes": "It stops using the brain at once and works on without it. It does not give the brain back by itself.",
      "whenToCallService": "If the tripwire cut it and you do not know why.",
      "appliesTo": [
        "Products with a brain lease"
      ],
      "related": [
        "ai.lease-expired",
        "ai.disagreement",
        "security.anomaly"
      ]
    },
    {
      "code": "ai.answer-rejected",
      "h": "H-07009",
      "area": "ai",
      "title": "Brain answer rejected",
      "meaning": "A brain answer was refused: unsigned, wrongly signed, for another request, or outside the lease.",
      "severity": "warning",
      "causes": [
        "An answer that is not signed, or signed with the wrong key.",
        "An answer meant for another request, or an old one sent again.",
        "An answer outside what the lease allows.",
        "Someone trying to send the product false answers."
      ],
      "fixes": [
        "Check the signing keys on both sides.",
        "Check the clock on both sides.",
        "If answers keep failing, treat it as possible tampering."
      ],
      "heartDoes": "It refuses the answer and acts on none of it, records why, and raises a warning. It does not lower its checks.",
      "whenToCallService": "If it keeps happening with correct keys and clocks: it may be an attack.",
      "appliesTo": [
        "Products with a brain lease"
      ],
      "related": [
        "ai.output-rejected",
        "security.anomaly",
        "ai.brain-revoked"
      ]
    },
    {
      "code": "ai.disagreement",
      "h": "H-07010",
      "area": "ai",
      "title": "Brain disagrees with the system's checks",
      "meaning": "The brain's answer disagreed with the system's own checks on something safety-relevant.",
      "severity": "warning",
      "causes": [
        "The brain is wrong: it lacks data, or misread the situation.",
        "A sensor is wrong, so the system's own check is the one misled.",
        "The safety limits are set too tight or too loose."
      ],
      "fixes": [
        "Compare what the brain said with the system's readings.",
        "Check the sensors involved.",
        "Check the limits."
      ],
      "heartDoes": "On anything safety-relevant, it trusts its own checks over the brain, does not act on the brain's answer, and asks a person.",
      "whenToCallService": "If the disagreement is about safety and you cannot tell which side is right.",
      "appliesTo": [
        "Products with a brain lease"
      ],
      "related": [
        "ai.output-rejected",
        "sensors.disagree",
        "ai.brain-revoked"
      ]
    },
    {
      "code": "sensors.no-reading",
      "h": "H-08001",
      "area": "sensors",
      "title": "No reading",
      "meaning": "A sensor gives no value.",
      "severity": "warning",
      "causes": [
        "A sensor unplugged, or its wire broken.",
        "A sensor that has failed.",
        "No signal for a radio sensor: GNSS indoors or in thick woods, a wireless probe out of range.",
        "A flat battery in a wireless sensor."
      ],
      "fixes": [
        "Check the sensor's plug and wiring.",
        "For radio sensors: move to open sky, or closer to the receiver.",
        "Replace the battery of a wireless sensor.",
        "Replace the sensor if it still gives nothing."
      ],
      "heartDoes": "It raises a warning after a number of missed readings (such as 3 failed fixes and 150 s with no position), and stops trusting that value. It resolves when readings return.",
      "whenToCallService": "If wiring and batteries are fine and still nothing is read.",
      "appliesTo": [
        "Products with sensors: thermostats, chargers, pumps, printers, trackers, medical devices"
      ],
      "related": [
        "sensors.stuck",
        "sensors.out-of-range",
        "data.missing"
      ]
    },
    {
      "code": "sensors.out-of-range",
      "h": "H-08002",
      "area": "sensors",
      "title": "Reading out of range",
      "meaning": "A reading is outside what is physically possible.",
      "severity": "error",
      "causes": [
        "An open circuit: a thermistor connector open often reads about -38 °C.",
        "A short circuit, which reads at the top of the scale.",
        "A wrong sensor type or wrong scale in the settings.",
        "Damage to a lead or cable, such as a pacemaker lead with impedance outside 200 to 2000 ohms."
      ],
      "fixes": [
        "Check the connector and wiring for opens and shorts.",
        "Check the sensor type and scale in the settings.",
        "Replace the sensor or its lead."
      ],
      "heartDoes": "It raises an error alert and treats the value as bad. The product's own firmware often refuses to act on it (a printer refusing to heat). It resolves when readings are back within what is possible.",
      "whenToCallService": "At once for medical leads and safety sensors. Otherwise if the reading stays impossible after checking the wiring.",
      "appliesTo": [
        "Products with sensors: thermostats, chargers, pumps, printers, trackers, medical devices"
      ],
      "related": [
        "sensors.no-reading",
        "sensors.stuck",
        "system.main-function-lost"
      ]
    },
    {
      "code": "sensors.stuck",
      "h": "H-08003",
      "area": "sensors",
      "title": "Reading stuck",
      "meaning": "A reading has not changed when it should have.",
      "severity": "error",
      "causes": [
        "A sensor frozen by a fault, giving the same value again and again.",
        "A reading copied from a cache when the real sensor stopped.",
        "A bus or driver error that keeps the last value.",
        "A probe that came out of what it measures, such as a soil probe pulled from the soil."
      ],
      "fixes": [
        "Compare with a second reading: a hand thermometer, a gauge, another sensor.",
        "Check that the probe is in place.",
        "Restart the sensor or its bus.",
        "Replace it if it freezes again."
      ],
      "heartDoes": "It raises an error alert when the value has not changed while it should have, such as 90 s without change through watering, or no change while the GNSS shows movement. It stops trusting the value. The product's firmware often cannot see this if the frozen value is near the target. It resolves when the value moves again.",
      "whenToCallService": "If the sensor matters for safety, or freezes again after a restart.",
      "appliesTo": [
        "Products with sensors: thermostats, chargers, pumps, printers, trackers, medical devices"
      ],
      "related": [
        "sensors.no-reading",
        "sensors.disagree",
        "sensors.drift"
      ]
    },
    {
      "code": "sensors.noisy",
      "h": "H-08004",
      "area": "sensors",
      "title": "Readings noisy",
      "meaning": "Readings jump around far more than normal.",
      "severity": "warning",
      "causes": [
        "Electrical interference from motors, chargers or radios.",
        "A loose connection or poor earth.",
        "A damaged cable shield.",
        "A sensor near the end of its life."
      ],
      "fixes": [
        "Check connections and earthing.",
        "Move cables away from power lines and motors, or use shielded cable.",
        "Replace the sensor if the noise stays."
      ],
      "heartDoes": "It raises a warning and may smooth or ignore the noisy readings. It resolves when the readings are steady again.",
      "whenToCallService": "At once for medical devices, where noise can be mistaken for real signals. Otherwise if it stays after checking connections.",
      "appliesTo": [
        "Products with sensors: thermostats, chargers, pumps, printers, trackers, medical devices"
      ],
      "related": [
        "sensors.out-of-range",
        "sensors.disagree",
        "power.supply-unstable"
      ]
    },
    {
      "code": "sensors.drift",
      "h": "H-08005",
      "area": "sensors",
      "title": "Sensor drift",
      "meaning": "A sensor has slowly moved away from the true value.",
      "severity": "warning",
      "causes": [
        "Age: many sensors drift slowly over months or years.",
        "Dirt or deposits on the sensor.",
        "Heat or humidity outside its rating.",
        "A missed calibration."
      ],
      "fixes": [
        "Compare with a reference reading.",
        "Clean the sensor.",
        "Calibrate it (calibrate or zero, if the product offers them).",
        "Replace it if calibration does not hold."
      ],
      "heartDoes": "It raises a warning when the slow change is clear, often found by comparing with another sensor or with a model of the system. It is often the cause of another alert, such as short-cycling. It resolves after calibration or replacement.",
      "whenToCallService": "If the product has no calibration the owner can do.",
      "appliesTo": [
        "Products with sensors: thermostats, chargers, pumps, printers, trackers, medical devices"
      ],
      "related": [
        "sensors.disagree",
        "performance.overshoot",
        "actuators.short-cycling"
      ]
    },
    {
      "code": "sensors.disagree",
      "h": "H-08006",
      "area": "sensors",
      "title": "Sensors disagree",
      "meaning": "Two sensors that should agree do not.",
      "severity": "warning",
      "causes": [
        "One of the two sensors has drifted or failed.",
        "They are in places with really different conditions.",
        "Different units or calibrations."
      ],
      "fixes": [
        "Check both against a reference.",
        "Check their places and settings.",
        "Calibrate or replace the one that is wrong."
      ],
      "heartDoes": "It raises a warning, and stops relying on either value for decisions that matter until it can tell which is right. It resolves when they agree.",
      "whenToCallService": "If the sensors are safety sensors.",
      "appliesTo": [
        "Products with redundant or related sensors"
      ],
      "related": [
        "sensors.drift",
        "sensors.stuck",
        "ai.disagreement"
      ]
    },
    {
      "code": "actuators.not-responding",
      "h": "H-09001",
      "area": "actuators",
      "title": "Actuator not responding",
      "meaning": "A motor, valve or similar part does not react to commands.",
      "severity": "error",
      "causes": [
        "A burnt-out coil or motor, such as a contactor that will not close.",
        "No power to the part, or a blown fuse.",
        "A broken wire to it, or a failed driver.",
        "A part held by a safety interlock or a lock-out.",
        "A valve stuck, or a line blocked, so the command has no effect."
      ],
      "fixes": [
        "Check power and fuses to the part.",
        "Check wiring and the driver.",
        "Check whether a safety interlock is holding it.",
        "Free or replace a stuck valve; clear a blocked line."
      ],
      "heartDoes": "It raises an error alert when a command has no effect, and often system.main-function-lost too. It does not keep commanding the part, and never works around an interlock.",
      "whenToCallService": "Usually: actuators run on power that needs care, such as mains, high current or pressure.",
      "appliesTo": [
        "Products with motors, valves, pumps, heaters, compressors, contactors or other moving parts"
      ],
      "related": [
        "actuators.stalled",
        "actuators.position-mismatch",
        "system.main-function-lost"
      ]
    },
    {
      "code": "actuators.position-mismatch",
      "h": "H-09002",
      "area": "actuators",
      "title": "Position mismatch",
      "meaning": "It ended up somewhere other than where it was told to go.",
      "severity": "error",
      "causes": [
        "Lost steps on a stepper motor: a layer shift on a 3D printer.",
        "A slipping belt, pulley or coupling.",
        "An obstruction.",
        "A position sensor that is wrong."
      ],
      "fixes": [
        "Check belts, pulleys and couplings.",
        "Remove any obstruction.",
        "Home the axis (home), and check the position sensor."
      ],
      "heartDoes": "It raises an error alert with the position asked for and the one reached. It does not move the part again until a person has looked, if moving could cause harm.",
      "whenToCallService": "If it repeats after checking the mechanics.",
      "appliesTo": [
        "Products with motors, valves, pumps, heaters, compressors, contactors or other moving parts"
      ],
      "related": [
        "actuators.stalled",
        "actuators.overcurrent",
        "sensors.drift"
      ]
    },
    {
      "code": "actuators.stalled",
      "h": "H-09003",
      "area": "actuators",
      "title": "Actuator stalled",
      "meaning": "It is blocked or cannot move.",
      "severity": "error",
      "causes": [
        "Something blocks it.",
        "A seized bearing or gearbox.",
        "Too heavy a load.",
        "Ice or dirt."
      ],
      "fixes": [
        "Switch off and make safe before touching it.",
        "Remove the blockage.",
        "Check bearings and gears."
      ],
      "heartDoes": "It raises an error alert. The product's own protection should cut power to the motor. A HEART does not try to force it.",
      "whenToCallService": "If it is not a simple blockage, or the part is heavy machinery.",
      "appliesTo": [
        "Products with motors, valves, pumps, heaters, compressors, contactors or other moving parts"
      ],
      "related": [
        "actuators.overcurrent",
        "actuators.not-responding",
        "performance.too-hot"
      ]
    },
    {
      "code": "actuators.short-cycling",
      "h": "H-09004",
      "area": "actuators",
      "title": "Short-cycling",
      "meaning": "It switches on and off far too often.",
      "severity": "warning",
      "causes": [
        "A wrong or drifting sensor, so the controller switches too soon.",
        "Too small a gap between on and off (hysteresis).",
        "Low flow cutting a burner's flame.",
        "An oversized unit for its job."
      ],
      "fixes": [
        "Check the sensor and its place.",
        "Widen the on-off gap, or set a minimum run time.",
        "Check flow, filters and pumps."
      ],
      "heartDoes": "It raises a warning, often with a cause such as sensors.drift. A Playbook may set a minimum run time, if the product allows it. It resolves when cycling is back to normal.",
      "whenToCallService": "If it continues: short-cycling wears compressors and burners fast.",
      "appliesTo": [
        "Heating, cooling, compressors, pumps, burners"
      ],
      "related": [
        "sensors.drift",
        "performance.overshoot",
        "system.main-function-degraded"
      ]
    },
    {
      "code": "actuators.overcurrent",
      "h": "H-09005",
      "area": "actuators",
      "title": "Overcurrent",
      "meaning": "It is drawing more current than it should.",
      "severity": "error",
      "causes": [
        "A heavy or blocked load.",
        "A failing motor winding.",
        "A short circuit in the wiring.",
        "A failed driver."
      ],
      "fixes": [
        "Stop the part and make it safe.",
        "Check the load for blockage.",
        "Have the motor and wiring tested."
      ],
      "heartDoes": "It raises an error alert. Current limits belong to the product's own protection, which a HEART never overrides.",
      "whenToCallService": "Yes, if it repeats: high current means heat and fire risk.",
      "appliesTo": [
        "Products with motors, valves, pumps, heaters, compressors, contactors or other moving parts"
      ],
      "related": [
        "actuators.stalled",
        "performance.too-hot",
        "power.supply-unstable"
      ]
    },
    {
      "code": "data.invalid",
      "h": "H-10001",
      "area": "data",
      "title": "Data invalid",
      "meaning": "Data fails its checks.",
      "severity": "warning",
      "causes": [
        "A device or client sends data in the wrong shape, such as a missing field or text where a number belongs.",
        "One side was updated and changed its format, and the other was not.",
        "Wrong units, such as Fahrenheit sent where Celsius is expected.",
        "Data damaged on a poor link, so a checksum fails.",
        "A value outside the range the product accepts."
      ],
      "fixes": [
        "Read the alert: it names the data that failed and the check it failed.",
        "Check the versions of the sender and the receiver, and update the older one.",
        "Check units and scales in the sender's settings.",
        "Fix the sender, or ask its maker to, if it keeps sending bad data."
      ],
      "heartDoes": "It refuses data that fails its checks, so bad values are not acted on, and records why. It raises a warning when it keeps happening. It resolves when good data flows again.",
      "whenToCallService": "If the sender is a part you cannot change, or bad data reaches decisions that matter.",
      "appliesTo": [
        "Every product that receives data from sensors, devices or other systems"
      ],
      "related": [
        "software.version-mismatch",
        "data.integrity-failed",
        "data.missing",
        "sensors.out-of-range"
      ]
    },
    {
      "code": "data.missing",
      "h": "H-10002",
      "area": "data",
      "title": "Data missing",
      "meaning": "Expected data has not arrived.",
      "severity": "warning",
      "causes": [
        "A source has stopped sending: a sensor, a device in the field, an upstream system.",
        "The link between them is down.",
        "A scheduled job that should produce the data did not run.",
        "The source is asleep longer than expected, or its battery is flat."
      ],
      "fixes": [
        "Read the alert: it names what is missing, and since when.",
        "Check the source: power, battery, and its own alerts.",
        "Check the link between the source and the product.",
        "Check that scheduled jobs ran, and run a missed one by hand."
      ],
      "heartDoes": "It raises a warning when expected data is late, and never fills the gap with invented values. It may mark results that depend on the missing data as uncertain. It resolves when the data arrives.",
      "whenToCallService": "If the source works and the link is up, but the data still does not arrive.",
      "appliesTo": [
        "Every product that expects data from sensors, devices or other systems"
      ],
      "related": [
        "sensors.no-reading",
        "connectivity.link-lost",
        "data.out-of-sync",
        "system.flatline"
      ]
    },
    {
      "code": "data.out-of-sync",
      "h": "H-10003",
      "area": "data",
      "title": "Data out of sync",
      "meaning": "Two copies of the same data disagree.",
      "severity": "warning",
      "causes": [
        "A sync stopped halfway, after a lost link or a restart.",
        "The same data was changed in two places at once.",
        "Clocks that disagree, so the newer copy looks older.",
        "A sync job switched off or failing for some time."
      ],
      "fixes": [
        "Read the alert: it names the two copies and how they differ.",
        "Decide which copy is right, and sync from it.",
        "Check both clocks.",
        "Check that the sync job runs, and look at its last result."
      ],
      "heartDoes": "It raises a warning. It does not overwrite either copy by itself when it cannot tell which is right. It resolves when the copies agree.",
      "whenToCallService": "If the copies cannot be brought together, or the data is shared with other people or systems.",
      "appliesTo": [
        "Products that keep copies of data in more than one place: an app and its cloud, a gateway and its devices"
      ],
      "related": [
        "data.integrity-failed",
        "connectivity.clock-unsynced",
        "data.missing"
      ]
    },
    {
      "code": "data.backup-failed",
      "h": "H-10004",
      "area": "data",
      "title": "Backup failed",
      "meaning": "A backup did not complete.",
      "severity": "warning",
      "causes": [
        "No space left where backups are stored.",
        "The backup target, such as a server or cloud bucket, cannot be reached.",
        "Credentials for the backup target expired or were changed.",
        "Files locked or changing while the backup ran.",
        "The source storage is failing, so reading it fails."
      ],
      "fixes": [
        "Read the alert: it gives the reason.",
        "Check space and access at the backup target.",
        "Renew credentials if they expired.",
        "Run the backup again by hand, and check that it completes.",
        "To prevent it: test a restore from time to time. A backup that has never been restored is not proven."
      ],
      "heartDoes": "It raises a warning with the reason. A Playbook may try the backup again later, within its guards. It resolves after the next good backup.",
      "whenToCallService": "If backups keep failing for more than a day or two, or the data cannot be lost.",
      "appliesTo": [
        "Servers, gateways and products that keep backups"
      ],
      "related": [
        "storage.full",
        "connectivity.dependency-unreachable",
        "storage.wearing-out"
      ]
    },
    {
      "code": "data.integrity-failed",
      "h": "H-10005",
      "area": "data",
      "title": "Data integrity check failed",
      "meaning": "Data has been changed or damaged when it should not have been.",
      "severity": "error",
      "causes": [
        "Damaged storage changed the data.",
        "A software bug wrote over it.",
        "Someone changed it without permission.",
        "A file only partly written after a power cut."
      ],
      "fixes": [
        "Stop using the damaged data.",
        "Restore it from a good backup.",
        "Check the storage for errors.",
        "Find out how it changed: look at the access records around that time."
      ],
      "heartDoes": "It raises an error alert and stops trusting that data. Where tampering is possible, it raises a security code as well.",
      "whenToCallService": "If the data matters for safety, money or other people, or tampering is possible.",
      "appliesTo": [
        "Every product that stores data"
      ],
      "related": [
        "storage.corrupted",
        "security.tamper-detected",
        "data.invalid"
      ]
    },
    {
      "code": "security.login-failures",
      "h": "H-11001",
      "area": "security",
      "title": "Many failed logins",
      "meaning": "Many failed login attempts.",
      "severity": "warning",
      "causes": [
        "Someone is guessing passwords.",
        "A device, script or app still uses an old password.",
        "A person forgot their password and keeps trying.",
        "A default password left in place and found by a scanner."
      ],
      "fixes": [
        "Read where the attempts come from: an address, a device, a user name.",
        "Update the old password in the device, script or app that keeps failing.",
        "Change any default password.",
        "Use strong passwords, and a second sign-in factor where the product offers it."
      ],
      "heartDoes": "It raises a warning, and slows down or blocks the source for a time. It resolves when the attempts stop.",
      "whenToCallService": "If the attempts come from outside your network and do not stop.",
      "appliesTo": [
        "Every connected product"
      ],
      "related": [
        "security.unexpected-access",
        "security.anomaly"
      ]
    },
    {
      "code": "security.unexpected-access",
      "h": "H-11002",
      "area": "security",
      "title": "Unexpected access",
      "meaning": "Access from an unknown place, or at an unusual time.",
      "severity": "warning",
      "causes": [
        "A sign-in from a new place, network or device.",
        "Access at a time nobody normally uses it.",
        "Stolen or leaked credentials.",
        "A shared account used by someone new."
      ],
      "fixes": [
        "Check whether it was you or someone you allowed.",
        "If not: change passwords, and revoke sessions and API keys.",
        "Check what was done during that access.",
        "Stop sharing accounts: give each person their own."
      ],
      "heartDoes": "It raises a warning with when and from where. It does not lock out the owner by itself.",
      "whenToCallService": "If it was not you or anyone you allowed.",
      "appliesTo": [
        "Every connected product"
      ],
      "related": [
        "security.login-failures",
        "security.anomaly",
        "security.policy-violation"
      ]
    },
    {
      "code": "security.certificate-expiring",
      "h": "H-11003",
      "area": "security",
      "title": "Certificate expiring",
      "meaning": "A security certificate expires soon.",
      "severity": "warning",
      "causes": [
        "A certificate is near its end date.",
        "Automatic renewal was never set up.",
        "Automatic renewal is failing, such as a renewal server that cannot be reached."
      ],
      "fixes": [
        "Renew the certificate.",
        "Set up automatic renewal, or fix it if it is failing.",
        "Check the product's clock, so the dates are read right."
      ],
      "heartDoes": "It raises a warning well before the end date, so there is time to act. It resolves when a new certificate is in place.",
      "whenToCallService": "If the certificate is built into the product and you cannot renew it yourself.",
      "appliesTo": [
        "Every connected product"
      ],
      "related": [
        "security.certificate-expired",
        "connectivity.clock-unsynced"
      ]
    },
    {
      "code": "security.certificate-expired",
      "h": "H-11004",
      "area": "security",
      "title": "Certificate expired",
      "meaning": "A security certificate has expired.",
      "severity": "error",
      "causes": [
        "A certificate was not renewed in time.",
        "Automatic renewal failed.",
        "The product's clock is wrong, so a valid certificate looks expired."
      ],
      "fixes": [
        "Check the clock first.",
        "Renew the certificate, and install it.",
        "Set up automatic renewal, so it does not happen again."
      ],
      "heartDoes": "It raises an error alert. Secure connections that rely on the certificate fail, as they must: a HEART does not turn off the check. It resolves when a valid certificate is in place.",
      "whenToCallService": "If you cannot renew it yourself.",
      "appliesTo": [
        "Every connected product"
      ],
      "related": [
        "security.certificate-expiring",
        "connectivity.clock-unsynced",
        "connectivity.dependency-unreachable"
      ]
    },
    {
      "code": "security.tamper-detected",
      "h": "H-11005",
      "area": "security",
      "title": "Tampering detected",
      "meaning": "Someone may have opened or altered the device or its software.",
      "severity": "critical",
      "causes": [
        "The case was opened, and a tamper switch tripped.",
        "Software changed without a valid signature.",
        "A debug or service port was used.",
        "A seal broken during authorised service, which is not tampering but looks the same."
      ],
      "fixes": [
        "Check whether service work explains it.",
        "If not: take the product off the network.",
        "Reinstall signed software from the maker.",
        "Change the passwords and keys it held."
      ],
      "heartDoes": "It raises a critical alert, tells a person at once, and refuses to run unsigned software where the product supports that.",
      "whenToCallService": "Yes, unless authorised service work explains it.",
      "appliesTo": [
        "Devices with a tamper switch, secure boot or signed software"
      ],
      "related": [
        "security.anomaly",
        "data.integrity-failed",
        "software.update-failed"
      ]
    },
    {
      "code": "security.policy-violation",
      "h": "H-11006",
      "area": "security",
      "title": "Policy violation",
      "meaning": "Something broke the owner's rules, such as data that should not have left.",
      "severity": "error",
      "causes": [
        "Data tried to leave that the owner's rules keep private.",
        "An action was asked for that the owner's rules do not allow.",
        "A setting was changed in a way that breaks a rule.",
        "A rule that is wrong, and blocks normal use."
      ],
      "fixes": [
        "Read the alert: it names the rule and what broke it.",
        "Fix whatever tried to break it.",
        "If the rule is wrong, change the rule, not the check."
      ],
      "heartDoes": "It blocks what broke the rule where it can, such as data held back by the Valve, and raises an error alert.",
      "whenToCallService": "If personal or protected data may have left.",
      "appliesTo": [
        "Every connected product"
      ],
      "related": [
        "security.anomaly",
        "security.unexpected-access",
        "data.integrity-failed"
      ]
    },
    {
      "code": "security.anomaly",
      "h": "H-11007",
      "area": "security",
      "title": "Security anomaly",
      "meaning": "Unusual activity that may be an attack.",
      "severity": "warning",
      "causes": [
        "Network traffic to places the product never talks to.",
        "Commands or requests unlike normal use.",
        "A sudden burst of requests, or scanning of its ports.",
        "Signs of an attack, or of malware on the product."
      ],
      "fixes": [
        "Read what was unusual.",
        "If in doubt, take the product off the network.",
        "Update its software, and change its passwords and keys."
      ],
      "heartDoes": "It raises a warning, and may limit what the product accepts until a person looks. It resolves when activity is normal again, or a person dismisses it.",
      "whenToCallService": "If an attack is possible.",
      "appliesTo": [
        "Every connected product"
      ],
      "related": [
        "security.login-failures",
        "security.unexpected-access",
        "security.tamper-detected"
      ]
    }
  ]
}
