# Fabric builder — lab INI → discovery → bindings → JSON **Goal:** Operators record **what they know** about the lab (each `**[machine.*]`** row: SSH, `**usb**` local/remote, expected Acroname / Monsoon hardware, site name, optional `**[fabric]**` / `**[fabric.rrh.*]**`) in the **same lab INI** used for `**fiwicontrol.lab`** / `**fiwicontrol.power --verify-inventory`**. The **fabric builder** then runs on a machine with Acroname **USB visibility**, performs **discovery**, guides **interactive bindings** (each hub port → `radio_id`), and writes a `**FabricDefinition`** JSON file used by `**scripts/system/`** harnesses (e.g. PCIe hot-swap). **Packages:** `fiwicontrol.fabric` (`builder`, `fabric` — JSON types + runtime `Fabric`, `definition_from_ini` — INI + discovery → `FabricDefinition`, `ini_merge`), `fiwicontrol.lab`, `fiwicontrol.power` (optional `[power]` for `brainstem`). **Related (not fabric JSON):** `fiwicontrol.concentrator` — local workstation CPU / PCIe / DMI snapshot used by `**scripts/system/dump_concentrator.py`**; see `**docs/system-test-scripts.md`**. --- ## What goes where | Artifact | Holds | | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Lab INI (`configs/*.ini`, `FIWI_LAB_INI`) | `[site]`, `[machine.*]` (SSH + `**usb**` local/remote + expected `**acroname**` / `**monsoon**`), optional `[fabric]` / `[fabric.rrh.*]` ( `**fabric_id**`, `**concentrator**`, Adnacom / patch-panel metadata, per-RRH overrides). | | Fabric JSON (output of this tool) | `discovery_fingerprint` (USB topology hash), `**rrhs**` array (`radio_id` ↔ Acroname `port` + module serial; Python: `FabricDefinition.rrhs`), concentrator SSH fields, optional `lab_ini` path string for audit. | Harnesses load **JSON**, then **merge** the same INI again so `**[fabric]`** can override concentrator / `fabric_id` / per-RRH fields without editing JSON (see `**docs/system-test-scripts.md`**). The Adnacom adapter count is read for reporting and tooling that consumes the INI overlay; it is **not** persisted in `**FabricDefinition`** JSON. --- ## Prerequisites - Editable install and `**[power]`** on the workstation where you run the builder (BrainStem over USB): `**pip install -e ".[power]"**` (see `**docs/install.md**`). - A valid lab INI with at least one machine or host row (required by `**load_lab_ini**` / `**load_inventory_ini**`). - Run `**build**` / `**bind**` on the host that **physically sees** the hub you are binding (often the concentrator workstation or the Pi, depending on wiring). --- ## Commands ### `build` — documented workflow (INI required) Requires a readable lab INI: use `**-c`** (e.g. `**configs/default.ini`**) or rely on `**FIWI_LAB_INI**` / the default path from `**fiwicontrol.lab.default_lab_ini_path()**` when that file exists. ```bash cd ~/Code/FiWiControl python3 -m fiwicontrol.fabric build -o configs/my-fabric.json -c configs/default.ini ``` Prints an INI summary, runs **local** Acroname discovery on **this** machine, prompts for module/port/radio bindings, writes JSON including `**lab_ini`** (resolved path used at build time). ### `bind` — same prompts, INI optional If the default lab INI path exists, it is loaded for summaries and prompt defaults. ```bash python3 -m fiwicontrol.fabric bind -o /tmp/fabric.json python3 -m fiwicontrol.fabric bind -o /tmp/fabric.json -c configs/default.ini ``` ### Optional: verify INI vs discovery before prompts Uses the same checks as `**python3 -m fiwicontrol.power --verify-inventory**` (every machine row, local and remote over SSH): ```bash python3 -m fiwicontrol.fabric build -o configs/my-fabric.json -c configs/default.ini --strict-ini # If mismatches are expected while debugging: python3 -m fiwicontrol.fabric build -o configs/my-fabric.json -c configs/default.ini --strict-ini --force ``` `**--ssh-controlmaster**` — pass through to remote verification (matches `**--verify-inventory**` usage). ### `status` — does JSON match live USB? ```bash python3 -m fiwicontrol.fabric status -f configs/my-fabric.json ``` Exit **0** only when `**READY`** (on-disk fingerprint matches live USB discovery on **this** machine). --- ## After the JSON exists - **Harness:** `**scripts/system/pcie_hotswap_harness.py --fabric-json …`** (merges lab INI again unless `**--no-lab-ini`**): `**docs/system-test-scripts.md**`. - **INI reference:** `**docs/power-control-and-inventory.md`** (`**[fabric]`** sections). --- ## Limitations - Interactive binding targets **one selected** Acroname module at a time; multi-hub benches may run the tool multiple times or extend the workflow. - `**patch_panel_port`** is captured per RRH at bind time; bulk patch panel size from `**[fabric]`** is metadata—you assign `**radio_id**` per hub port, then use `**[fabric.rrh.*]**` in the INI to override ports or serials when merging over JSON. --- ## Related docs - `**docs/install.md**` — install and verification. - `**docs/power-control-and-inventory.md**` — INI reference, `**[fabric]**`. - `**docs/system-test-scripts.md**` — harness `**--fabric-json**`, INI merge, and script patterns. - `**docs/pcie-hotswap-setup.md**` — PCIe hot-swap harness: install, INI, fabric JSON, and commands.