# 📦 WP-131 — `feat(data): keypoints fixture, geometric-only det/obb/seg categories`

> Engineering log · [Phase 12 — Keypoint detection, v0.5.0](https://borda.github.io/lucid-YOLO/engineering/phase-12-keypoints/)
>
> 🔗 Depends on [WP-121b](https://borda.github.io/lucid-YOLO/work_packages/wp-121b/) · Needed by [WP-132](https://borda.github.io/lucid-YOLO/work_packages/wp-132/)
>
> ⬅️ [WP-126](https://borda.github.io/lucid-YOLO/work_packages/wp-126/) · [Roadmap](https://borda.github.io/lucid-YOLO/ROADMAP/) · [WP-133](https://borda.github.io/lucid-YOLO/work_packages/wp-133/) ➡️


## WP-131 — a dependency fixed upstream, checked rather than trusted

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

The upstream half of [WP-121b](https://borda.github.io/lucid-YOLO/work_packages/wp-121b/)'s "still-open finding" landed same-day: `class_names(class_mode, shapes=...)` (opt-in, defaulting to the old full-vocabulary span when omitted, so every existing caller is unaffected), a mirrored `SyntheticConfig.colors` field, and the `Task.KEYPOINTS` segmentation-emission fix [WP-121b](https://borda.github.io/lucid-YOLO/work_packages/wp-121b/) already depended on. Verified rather than assumed fixed: the first check found the new parameter existed and its own tests passed, but `generate_dataset` -- the convenience function this project's fixtures actually call, not the primitive directly -- still called the bare unscoped `class_names(config.class_mode)` at its one writer-construction call site, so `generate_dataset(..., shapes=DEFAULT_SHAPES, ...)` kept emitting all 16 categories regardless. Reported back with the exact line and the one-line fix it needed; landed within the hour as an amended commit (`74af985`), re-verified empirically both ways -- `shapes=DEFAULT_SHAPES` now yields exactly `['circle', 'rectangle', 'square', 'triangle']`, `shapes=animal_shapes(2)` yields exactly `['duck', 'elephant']` -- before trusting it for anything downstream.

**Pinned by commit, not by version (R21).** `fuse-augmentations`' version string had not moved (`0.10.0.dev0`) across every commit in this saga, and PyPI forbids re-uploading that string, so a bare `uv lock` re-resolve would have kept silently re-pinning the stale 2026-08-02 wheel. `pyproject.toml`'s dependency became a git+commit-SHA pin instead (`git+https://...@74af985...`) -- matching R21's own provenance row, which already cited a fixed commit rather than a floating version, closer to A26's original intent than the PyPI-registry pin the project had drifted to. `uv lock`'s re-resolution incidentally also picked up `onnx`/`onnxruntime` into the lock for the first time; both had been declared in the `dev` dependency group but were absent from `uv.lock` entirely, a pre-existing drift unrelated to this row that a plain `uv sync --frozen` had exposed by removing the two packages someone had evidently `pip install`ed by hand outside the lock.

**Goldens verified unchanged, not re-frozen.** `generate_detseg_fixtures`/`generate_obb_fixtures` gained an explicit `shapes=DEFAULT_SHAPES` argument -- defensive, not corrective, since that was already the implicit default -- so the fix restores exactly the 4-category vocabulary the frozen goldens were built against. Full `make gate` after the pin bump: 2325 passed (2322 plus the two new keypoints-fixture tests plus one doctest), 27/27 goldens passed with no `--freeze` needed, confirming the restored parity rather than assuming it.

**`generate_keypoints_fixtures`.** 12 images, `animal_shapes(2)` -- duck and elephant, not fuse-augmentations' full 12-animal vocabulary -- specifically to keep an eventual overfit-style milestone run's category count low; more animal classes means a wider vocabulary a memorization-style run has to fit before its own metric means anything. Mirrors `generate_detseg_fixtures`/`generate_obb_fixtures`'s existing shape exactly: idempotent, seeded (`KEYPOINTS_SEED`), a matching `keypoints_fixture_dir` session fixture in `conftest.py`. `test_keypoints_set_loads` pins every annotation's landmark table at fuse-augmentations' fixed 16-point animal schema and the category count at or under `KEYPOINTS_ANIMAL_COUNT`; `test_keypoints_generation_deterministic` mirrors the existing det/obb determinism tests byte-for-byte.

