# Schemas

> JSON Schemas for the reports, records and files RDMBench writes, each served at its $id.

- **Schemas:** 20
- **Dialect:** JSON Schema 2020-12
- **Version:** 0.2.0
- **Runs on:** macOS 15 Sequoia or later, Apple silicon or Intel
- **Needs:** An Enttec DMX USB Pro with its DMX/RDM firmware (major version 2)
- **Price:** Free

These are the schemas for the JSON RDMBench writes: the reports
`rdmbench-cli` prints with `--json`, the records the bench keeps in its
captures folder, and the files a fixture library is made of. Each one is
generated from the app's own types, so it changes when the JSON does.

A schema's `$id` is the address it is served from, so a validator can
fetch it by its `$id`. Its `description` says how the bench reads the
document, over and above what each field means.

Where a report says something in words, it carries `{ id, args, text }`.
`text` is the sentence in the bench's language, for a person to read.
Compare on `id`, never on `text`.

An assistant connected to the bench reads the same schemas as the MCP
resources `rdmbench://schema/<name>`. `fixture-profile.json` and
`manufacturer-pid-file.json` are also in
[rdmbench-pids](https://github.com/darinpope/rdmbench-pids), the public
fixture library, with the same `$id`.

## Documents

- [`apply-report.json`](https://www.rdmbench.com/schema/apply-report.json): **RDMBench template apply report.** What applying a settings template did: per unit, each setting's `before` / `wanted` / `after` with its `outcome` (`matched`, `changed`, `would_change` on a dry run, `refused`, `unreadable`, `unverified`) and the refusal's sentence, or the `skipped` sentence saying why the unit was left alone (another model, other firmware, the reference unit itself, silent). `template --json` writes it.
- [`backup.json`](https://www.rdmbench.com/schema/backup.json): **RDMBench backup manifest.** `backup.json` at the root of an `rdmbench-backup-<time>.zip`, which is laid out exactly like the bench's data folder: `captures/` (the repair history, whole), `manufacturer-pids/` and `gdtf/*.gdtf`. `counts` is files per part; `skipped` is what was in the data folder and left out, each with its `reason` (`link`, `unknown`, `credentials`, `backup`) — the Share password is never in a backup. `settings` is the app's own preferences, opaque to the core and absent from a CLI backup. A restore merges: it adds what is missing and never replaces a file that is there.
- [`behaviour-report.json`](https://www.rdmbench.com/schema/behaviour-report.json): **RDMBench behavior check.** Whether one responder follows the rules of E1.20, as `behaviour --json` writes it: one entry per rule with its stable `id`, the clause it cites as `section`, what the clause requires (`name`) and what the unit actually did (`detail`), each `outcome` being `passed`, `failed` or `skipped`. Conformance, not health — a unit can fail one of these and be perfectly serviceable, so nothing here feeds a snapshot's severity rollup.
- [`comparison.json`](https://www.rdmbench.com/schema/comparison.json): **RDMBench snapshot comparison.** Two snapshots of a fixture compared, earlier first: each `changes` entry is a typed `difference` with its own severity and a rendered `text`. `worst` is `ok` when nothing got worse.
- [`diagnostic-snapshot.json`](https://www.rdmbench.com/schema/diagnostic-snapshot.json): **RDMBench diagnostic snapshot.** One fixture's full diagnostic report, as `rdmbench-cli snapshot --json` and the app write it. `rollup` is the overall verdict; every `findings` list, `status` entry and `problems` line carries `{ id, args, text }` — compare on `id`, read `text`. Text the fixture wrote itself (labels, descriptions) is never translated.
- [`finish-record.json`](https://www.rdmbench.com/schema/finish-record.json): **RDMBench finish record.** What Finish Repair did to a unit — `<UID>/<time>-finish.json` in the captures folder, beside the closing report it was taken with (`finished_at_unix_ms` is that report's `taken_at_unix_ms`): the counters reset with what they read before, what RECORD_SENSORS reached, and what the fixture refused. It marks where one repair ends, which is how the repair sheet finds the report the next one opened with.
- [`fixture-profile.json`](https://www.rdmbench.com/schema/fixture-profile.json): **RDMBench fixture profile.** What a *model* is, captured from one unit of it: identity, product category and details, firmware, every DMX personality (name, footprint, E1.37-5 stable ID where the fixture has one), every sensor's definition, and the PIDs it lists — the file format under the library's `profiles/` directory and what `export-profile --out` writes. Harvested self-description: no values, no current state, no slot tables (reading those means switching the fixture's mode).
- [`hold-report.json`](https://www.rdmbench.com/schema/hold-report.json): **RDMBench DMX hold.** What the bench is holding on the wire, as `dmx --json` writes it: every channel that is up with its absolute DMX number, its number counted from the fixture's start address where a fixture's channels were asked for, and its level. The frame is held across RDM exchanges until it is released; `notes` says when a channel is past the fixture's footprint, which is on the wire but not read by it.
- [`load-report.json`](https://www.rdmbench.com/schema/load-report.json): **RDMBench load report.** A fixture driven in order to measure it — its footprint held at `level` (with `slots`, the profile's plan and the channels its own slot table `rested` on top), read while it was up, and output ended inside the same call (`output_ended`). `movements` is every sensor's `before`, `after` and `peak`, the ones that moved first; `status_appeared` what it reported under load that it did not at idle; `outcome` `moved` or `nothing_moved`, which is inconclusive rather than a fault. What the `load` tool and `rdmbench-cli load --json` return, and what each run is filed as under its unit — `<UID>/<time>-load.json` in the captures folder, stamped when output came down (`ended_ms`), whether the CLI, the MCP tool or the app's Monitor tab ran it. The repair sheet reads every run inside the repair.
- [`manufacturer-pid-file.json`](https://www.rdmbench.com/schema/manufacturer-pid-file.json): **RDMBench manufacturer PID table.** One brand's manufacturer-specific PID names and types — the file format under `manufacturer-pids/` and what `export-pids --out` writes. Sourced from manuals, the fixture's own PARAMETER_DESCRIPTION, or sniffing; never from OLA's PID store.
- [`monitor-stream.json`](https://www.rdmbench.com/schema/monitor-stream.json): **RDMBench monitor stream line.** One line of a `monitor --json` file (JSON Lines): the first line is `{ baseline }`, then one `{ t, events, sample }` per poll with `t` in seconds since the start, and finally `{ summary }`.
- [`pid-export.json`](https://www.rdmbench.com/schema/pid-export.json): **RDMBench manufacturer PID export.** The result of `export-pids`: a proposed `manufacturer-pids/` file (`file`) holding only what the fixture described that the loaded tables lack, with the `new` / `changed` / `known` / `undescribed` accounting.
- [`profile-export.json`](https://www.rdmbench.com/schema/profile-export.json): **RDMBench fixture profile export.** The result of `export-profile`: the profile (`file`), where it belongs under `profiles/` (`suggested_path`), why it cannot be published if it cannot (`problems`), what a curator should settle (`warnings`), and the per-PID reads that failed on the way (`read_problems`).
- [`quirk-report.json`](https://www.rdmbench.com/schema/quirk-report.json): **RDMBench fixture quirk report.** What a reported unit's *model* is known to get wrong, read off the `quirks` on its fixture profile: each quirk with the bench observation behind it, the findings in the stored report it contradicts, and — for a model that inverts IDENTIFY_DEVICE — what the flag means as against what the fixture reported. Produced beside a snapshot and never folded into it: the report keeps what the fixture said, and this says what it means.
- [`repair-note.json`](https://www.rdmbench.com/schema/repair-note.json): **RDMBench repair note.** What the bench did to a unit, in the technician's words — `<UID>/<time>-note.json` in the captures folder, beside the reports. `about_unix_ms` is the `taken_at_unix_ms` of the report it was written against (absent for a note about the unit in general). Never part of a snapshot, and nothing that leaves the machine.
- [`repair-sheet.json`](https://www.rdmbench.com/schema/repair-sheet.json): **RDMBench repair sheet.** What goes back to the customer with a unit: its latest repair read for someone who is not a tech, from the captures folder alone — the report it opened with (`opened`, the first since the previous Finish Repair) and the one it leaves with (`closed`), the complaint read against the opening report, what was `found`, the tech's `notes`, what the bench `done`, the channel walk it was `checked` with, each load run `under_load`, how it is `leaving`, and `remarks` about the sheet itself (`finished: false` when Finish Repair was not run). `rdmbench-cli sheet --json` prints it. Every sentence is `{ id, args, text }`, so a stored sheet renders again in the customer's language; the notes and the fixture's own text are quoted as written.
- [`session-summary.json`](https://www.rdmbench.com/schema/session-summary.json): **RDMBench monitor session summary.** What a live-monitoring session saw: per-sensor min/max/avg/worst, the timestamped events (sensor threshold crossings, status messages appearing and clearing, config changes, comms error counts rising, the device going silent), and the status conditions still active when it ended.
- [`settings-template.json`](https://www.rdmbench.com/schema/settings-template.json): **RDMBench settings template.** The writable configuration of one known-good unit — personality, lamp-on mode, the pan/tilt flags, the E1.37-1 no-signal modes and dimmer settings, never the DMX address — as `template --out` writes it and `template --file` reads it back, to bring other units of the same model and firmware to (`model_id` and `software_version_id` gate that). Each `value` is tagged by `kind` in the form its SET takes; `reading` is the reference unit's own words for it.
- [`walk-record.json`](https://www.rdmbench.com/schema/walk-record.json): **RDMBench channel walk record.** A channel walk — a person checking a fixture's channels by eye, one at a time — as `<UID>/<time>-walk.json` in the captures folder. Each channel the walk showed, with the name it was shown under and whose word that name is (`name_source`), the tech's `verdict` (`pass`, `fail`, `skip`; absent when the walk ended first) and their `note`, verbatim. `about_unix_ms` is the `taken_at_unix_ms` of the report it was taken against. The repair sheet reads the repair's last walk.
- [`wire-log.json`](https://www.rdmbench.com/schema/wire-log.json): **RDMBench wire log line.** One line of a wire log (JSON Lines) — `wire/<time>-wire.jsonl` in the captures folder, or the file `--record=FILE` names. The first line is `{ header }`; every line after it is one exchange with an interface, in order: its `kind` (`request`, `patient`, `discovery`, `dmx_hold`, `dmx_stop`), the bytes sent and the bytes that came back as hex, `outcome` (`on_time`, `late`, `none`, `error`), and `at_us` / `elapsed_us` in microseconds. The bytes are the record: nothing in the file is a decoded reading of them, so it can be checked against E1.20 directly and attached to a report to a manufacturer.

