# Shelf label files Ground truth for the identity evaluators (`code/eval_identity.py`, `code/eval_live.py`) and for the evidence scripts in `docs/research/2026-09-28-recognition-architecture/evidence/`. {"image": "add/image6.jpg", "version": 2, "facings": [ ... ]} `image` is the photo the boxes index into. `facings` is one row per detected product facing, in that photo's own pixel coordinates. ## Row schema | Field | Required | Meaning | |---|---|---| | `index` | yes | Row identity. Stable across label revisions, so a run's per-facing log joins to truth by `index`, never by array position. | | `box` | yes | `[x1, y1, x2, y2]` in `image` pixels. | | `label` | yes | Canonical SKU id (`sku_l01`), `unknown` for a facing that is not in the catalog, or `exclude` for a facing no lane can be scored on. | | `source` | yes | How the label was decided. `v1-confirmed-visual` = the v1 label was checked against the package and kept; `visual-audit-2026-09-28` = the label was re-read from the package in the 2026-09-28 audit. | | `v1_label` | yes | The label this row carried in v1. Kept so claims computed on v1 stay reproducible and the 26 corrections stay auditable. | | `note` | when `label != v1_label` | Why the label changed. Also on a few unchanged rows that need a remark (e.g. `#46-48`, the tare bottles that may be what `stock.csv` calls l12). | | `match` | no | v1 provenance only: the field DECISION.md §3 reads as a match IoU, and as evidence that v1 labels were propagated from tag or box matching rather than read off packages. Values here are 0.0, 0.911, 1.0. No scorer reads it; it is carried through unchanged for traceability. | `label` takes a canonical SKU id, `unknown`, or `exclude`. This file uses `sku_l01`-`sku_l11`: l12 has no real facing on the shelf, so no row carries it. `exclude` rows stay in the file so the facing inventory is complete; every scorer drops them before computing a rate. The evaluators read `index`, `box`, and `label`; the provenance fields are additive. `image6.json` is the corrected v2 set: 111 rows, 109 scored (2 `exclude`), 61 in-catalog across 11 SKUs, 48 `unknown`, 26 labels changed from v1. It is a copy of `docs/research/2026-09-28-recognition-architecture/evidence/image6_v2.json`; edit the evidence copy and re-copy, so the two cannot drift. ## Schema check DECISION.md §7 sets the rule for every label file: > Every label row carries `source`, `confidence`, and `labeler`. A label file > without them fails a schema check. The current file does not meet it. All 111 rows carry `source` and `v1_label`, but none carries `confidence` or `labeler`: the file records where each label came from and what it replaced, not a per-row certainty or a labeler name. Inventing confidence values after the fact would be worse than the gap, so they are absent rather than guessed. Tier-2 labels must add both. `confidence` is the labeler's own certainty for that row; `labeler` names the person or pass that produced it, because Tier 2 is double-labelled and a disagreement has to be traceable to a pass. Tier 1 (`image6_v2.json`) is dev-only and its numbers never ship, so it stays as it is.