_structured/ — Machine-Readable Diagnostic Data

This directory holds the structured (JSON) data sources that power the interactive Fault-Finding Wizard. The markdown corpus remains the long-form reference layer; these JSON trees link into the markdown docs, they do not replace them.

build.ps1 validates every file here and compiles them into data/fault-trees.js (window.TS_FAULT_TREES). The build fails loudly on any schema violation, so a broken tree can never ship silently.

Fault-tree file

One file per tree in fault-trees/, named <brandSlug>-<modelSlug>.json (e.g. kickinghorse-a100.json) or _<family>.json for generic family trees (e.g. _generic-inverter.json).

{
  "id": "kickinghorse/a100",
  "title": "KickingHorse A100",
  "family": "stick-inverter",
  "entries": {
    "dead": "dead-input",
    "no-output": "ocv-check"
  },
  "nodes": {
    "ocv-check": {
      "type": "measurement",
      "prompt": "Measure OCV across the output studs.",
      "hint": "Machine powered, no arc attempted.",
      "meter": "DCV, 200 V range",
      "expect": "about mid-80 V class OCV",
      "valueClass": "model",
      "source": "measurement-cards/kickinghorse/a100-measurement-card.md",
      "stopRule": "Output studs are live whenever the machine is on.",
      "branches": [
        { "label": "In range", "next": "external-path" },
        { "label": "Zero or very low", "next": "igbt-branch" }
      ]
    },
    "igbt-branch": {
      "type": "terminal",
      "cause": "Output or IGBT branch",
      "action": "Follow the board-opening-map output/IGBT branch.",
      "stopRule": "Discharge bus caps before touching the primary side.",
      "docs": ["board-opening-maps/kickinghorse/a100-board-opening-map.md"]
    }
  }
}

Top-level fields

Field Required Meaning
id yes <brandSlug>/<modelSlug> (must match the catalog) or generic/<family>
title yes Display name shown in the wizard header
family yes Free-form family tag (stick-inverter, mig, tig-hf, plasma, engine-driven)
entries yes Map of symptom slug → starting node id. Every value must exist in nodes. Canonical symptom slugs: dead, no-output, weak-output, thermal, wire-feed, hf-start. A tree may define any subset, plus model-specific extras (e.g. blinking-light).
nodes yes Map of node id → node object. Node ids are kebab-case, unique within the file.

Node types

question — a yes/no or multi-choice observation. Requires: prompt, branches (≥2). Optional: hint, stopRule.

measurement — a physical measurement with a pass/fail verdict. Requires: prompt, meter, expect, branches (≥2). Optional: hint, valueClass, source, stopRule.

terminal — a conclusion. Requires: cause, action. Optional: stopRule, docs (array of corpus-relative .md paths, rendered as chips), branches not allowed.

Field rules

Validation (build.ps1 enforces)

  1. File parses as JSON.
  2. id, title, family, entries, nodes present.
  3. Every entries value and every branches[].next resolves to an existing node.
  4. Node type is question | measurement | terminal; required fields per type present.
  5. terminal nodes have no branches; non-terminal nodes have ≥ 2 branches.
  6. Every node is reachable from at least one entry (no orphan nodes).

Authoring workflow

  1. Read the model's fault-workflow router (complaint order + stop rules) and measurement card (checkpoints + healthy expectations). The guide's fast-triage table is the fallback when a router is missing.
  2. Map each router complaint to an entries slug.
  3. Build nodes from measurement-card checkpoints, in the router's order.
  4. Terminals link the docs the router names for that complaint (docs array).
  5. Re-run build.ps1 — it will reject the file with a specific error if anything dangles.