# calibration/ — frame corpus for validation & regression Two artifacts, one frame pool: - `calibration_labels.json` — per-frame color labels. Used by `atm validate-calibration` to check the current palette classifies known-good dots correctly before a live session. - `scenarios.json` — ordered frame sequences per FSM scenario (full cycle, phase skip, catchup, post-fire suppression). Consumed by `tests/test_scenarios_regression.py` which runs each sequence through the full `Detector → _handle_tick` pipeline and asserts color, FSM reason/state, emitted alerts, and scheduler on/off. Frames live in `calibration/frames/` and are self-contained: purging `logs/fires/` or `samples/` does not break either artifact. ## calibration_labels.json schema ## Schema A JSON array of entries. Each entry: | Field | Type | Required | Description | |------------|---------|----------|----------------------------------------------------------------| | `path` | string | yes | Path to a PNG frame (relative to CWD or absolute). | | `expected` | string | yes | Expected color name: one of `turquoise`, `yellow`, `dark_green`, `dark_red`, `light_green`, `light_red`, `gray`. | | `note` | string | no | Freeform annotation; shown in SUGGESTIONS output. | ## Usage ```bash atm validate-calibration calibration/calibration_labels.json ``` Exit codes: - `0` — every sample PASS - `1` — one or more FAIL - `2` — label file missing or malformed JSON ## Adding new samples 1. Find a screenshot in `logs/fires/` whose dot color you can verify by eye. 2. **Copy it into `calibration/frames/`** — this directory is self-contained so `logs/fires/` and `samples/` can be emptied without breaking validation. 3. Append an entry with `path` (pointing to `calibration/frames/...`), `expected`, and an optional `note`. 4. Re-run validation. If it FAILs, the SUGGESTIONS section will tell you the RGB distance between the observed pixel and the expected color's center — use that as input for `atm calibrate`.