# 📦 WP-136 — `refine(configs): unify config names, fold det_yolo_smoke into docs`

> Engineering log · [Phase 12 — Keypoint detection, v0.5.0](https://borda.github.io/lucid-YOLO/engineering/phase-12-keypoints/)
>
> 🔗 Depends on [WP-040](https://borda.github.io/lucid-YOLO/work_packages/wp-040/), [WP-088](https://borda.github.io/lucid-YOLO/work_packages/wp-088/), [WP-099c](https://borda.github.io/lucid-YOLO/work_packages/wp-099c/), [WP-125](https://borda.github.io/lucid-YOLO/work_packages/wp-125/), [WP-135](https://borda.github.io/lucid-YOLO/work_packages/wp-135/) · Needed by none
>
> ⬅️ [WP-135](https://borda.github.io/lucid-YOLO/work_packages/wp-135/) · [Roadmap](https://borda.github.io/lucid-YOLO/ROADMAP/) · [WP-137](https://borda.github.io/lucid-YOLO/work_packages/wp-137/) ➡️


## WP-136 — a filename is not a scratch space for whatever axis is on your mind that day

<a id="wp-136"></a>

`src/lucid_yolo/configs/` had grown eight files under what read as one two-token scheme (`<task>_<tier>.yaml`), but a closer look found three separate inconsistencies rather than one: two files used a third token to mean something no sibling file's name carried at all, one word (`ablation`) meant two structurally different things across two files, and the scheme itself never named the one axis every config actually sets differently -- `variant`. User direction (mid-session, superseding this row's own first draft) was to stop patching the two collisions and instead put every config on one explicit scheme: `<task>_<variant>_<tier>[_<detail>].yaml`, variant spelled out in full rather than left as the bare letter the CLI and each file's own `variant:` field use.

**The full rename, driven by what each file's own `variant:` line already said (checked, not assumed):**

| old | new | why |
| -- | -- | -- |
| `det_smoke.yaml` | `det_nano_smoke.yaml` | `variant: n`, task truncated as it already was |
| `seg_smoke.yaml` | `seg_nano_smoke.yaml` | `variant: n` |
| `obb_smoke.yaml` | `obb_nano_smoke.yaml` | `variant: n` |
| `pose_smoke.yaml` | `pose_nano_smoke.yaml` | `variant: n`; `pose` kept as `task: keypoints`'s established domain term (roadmap's own "Pose-smoke tier" language, not a choice this row introduced) |
| `det_ablations.yaml` | `det_small_ablations.yaml` | `variant: s` -- the one config in the directory that is not `n`, previously invisible in its own filename |
| `overfit_100.yaml` | `det_nano_overfit_100.yaml` | had no task prefix at all, relying on `task`'s implicit `"detect"` default; `variant: n`; `100` kept as [WP-040](https://borda.github.io/lucid-YOLO/work_packages/wp-040/)'s own detail (image count, not a tier word) |
| `det_yolo_smoke.yaml` | *dropped* | see below |
| `pose_smoke_ablation.yaml` | `pose_nano_smoke_laplace_nll.yaml` | `ablation` collided with `det_ablations.yaml`'s different sense (a whole blueprint tier, sec. 10 tier B, ~120-epoch paired runs, its own sign-matching acceptance against R1 Tables 2/3/5/6) where this file is a same-budget arm of the *smoke* tier; `laplace_nll` names the mechanism swapped in, matching how the loss class and the `DetectionLitModule` docstring already refer to the arm |

**`det_yolo_smoke.yaml` was dropped, not renamed.** It was first renamed `det_smoke_layout.yaml` (naming the `--data.layout` axis, not the one value it took), then reconsidered a second time against `det_nano_smoke.yaml` sitting beside it in a listing -- "layout" alone read as no more specific than the word it replaced, so the candidate became `det_nano_smoke_yolo.yaml`, spelling the actual value. Diffing it against `det_nano_smoke.yaml` at that point (checked, not assumed) found the two differ in exactly three things: the `data:` block (a YOLO root and its `layout: yolo`), `model.num_classes` (`3` for the demo root vs COCO's `80` -- a property of the demoed root, not an independent axis), and header prose. Everything else -- schedule, gains, optimizer, `variant: n` -- is identical. A whole config file whose only content beyond a data override and its dependent class count is header prose is not a ninth point in the scheme; it is three CLI flags on `det_nano_smoke.yaml` that never needed a file of their own. The prose itself was not lost: `docs/DATASETS.md`'s "Dataset formats" section already carries the deeper mechanics (`layout` vs `format`, `YOLO_CANDIDATES`, `data.yaml` priority, why `segment` is unavailable), so the file's comments were largely restating what that section already says more completely. `docs/TRAINING.md` gains a "A YOLO-format root instead of COCO's" section instead: the three-flag override, why `--data.layout yolo` is stated rather than probed (A63's undecidable-tie case), the `num_classes` coupling to the root's own `data.yaml`, and the `segment` refusal, each in one paragraph rather than a whole file's worth of header comments.

**Variant spelled out, deliberately creating a second vocabulary.** Every config's own `variant:` field and the `--variant` CLI flag stay bare letters -- that is the real API and does not change here. The filename now spells `nano`/`small` for readability at the cost of a reader having to know `nano == n` when connecting a filename to the config's own content or an override. Confirmed with the user rather than assumed, since nothing else in this codebase (code, docs, or CLI) has ever spelled these out.

**What that scheme cannot promise, stated rather than left implicit.** A filename's variant token is the config's *default*; `--variant s` on `det_nano_smoke.yaml` still runs an s-scale job under an n-named file, exactly as `keypoint_gain 1.0` in a filename would not survive a `--model.keypoint_gain` override. The name documents the shipped default, not a runtime guarantee -- the same caveat every config's own header comment already states about `variant` ("this file's default scale, not a claim about the run").

**What did not move: the historical record.** `docs/REPRODUCTION_REPORT.md`'s rows are explicit about being "the exact commands as they were run at the time" (`docs/TRAINING.md`), and the `ROADMAP.md`/`ENGINEERING_LOG.md` rows for [WP-040](https://borda.github.io/lucid-YOLO/work_packages/wp-040/), [WP-099c](https://borda.github.io/lucid-YOLO/work_packages/wp-099c/), and [WP-135](https://borda.github.io/lucid-YOLO/work_packages/wp-135/) describe what those WPs built and named *then*. [WP-129](https://borda.github.io/lucid-YOLO/work_packages/wp-129/) already set this project's precedent for exactly this situation: moving `audit_licenses.py`/`check_commit_trailers.py` into `scripts/lint/` did not rewrite [WP-084](https://borda.github.io/lucid-YOLO/work_packages/wp-084/)'s, [WP-109](https://borda.github.io/lucid-YOLO/work_packages/wp-109/)'s or [WP-115](https://borda.github.io/lucid-YOLO/work_packages/wp-115/)'s rows, which still cite the pre-move path. None of those earlier rows are touched here; this section is where all eight old names are cited for the last time.

**What did move: everything a reader or the tool itself would act on.** `README.md`, `docs/TRAINING.md`, `AGENTS.md`, `docs/DATASETS.md` (live usage docs, not a historical ledger -- a stale name there is just a broken command); `scripts/overfit_micro.py`'s and `scripts/shapes_regression.py`'s `_RECIPE_PATH` (functional, not prose -- the old name pointed at a file that no longer exists under it); `src/lucid_yolo/cli/train.py`'s `_DEFAULT_CONFIG` and its own doctests; `tests/ptl/test_cli.py`'s hardcoded `test_configs_dir_non_empty` set and every parametrized config-name literal; and every config's own internal header comment that named a sibling file. `CHANGELOG.md`'s still-open `## [Unreleased]` section also updated, on the same live-vs-historical reasoning -- it describes what the next release will ship, not what a past WP called something at the time, so a stale name there would mislead exactly the reader it exists for.

No test needed a structural change: `tests/ptl/test_cli.py`'s `_CONFIG_PATHS` is `_CONFIGS_DIR.glob("*.yaml")`, so all eight renamed files are discovered and dry-parsed under their new names automatically. The one hardcoded list (`test_configs_dir_non_empty`'s membership assertion) and the several tests parametrized on a literal config name still needed the literals updated by hand, since a glob does not know what a test author meant to assert about.

