# 📦 WP-154b — `refine(data): fuse's geometric conventions replace this project's`

> Engineering log · [Phase 14 — Augmentation upstreaming to `fuse`, v0.7.0](https://borda.github.io/lucid-YOLO/engineering/phase-14-augmentation-upstreaming/)
>
> 🔗 Depends on [WP-154](https://borda.github.io/lucid-YOLO/work_packages/wp-154/) · Needed by [WP-155](https://borda.github.io/lucid-YOLO/work_packages/wp-155/), [WP-157](https://borda.github.io/lucid-YOLO/work_packages/wp-157/)
>
> ⬅️ [WP-154c](https://borda.github.io/lucid-YOLO/work_packages/wp-154c/) · [Roadmap](https://borda.github.io/lucid-YOLO/ROADMAP/) · [WP-155](https://borda.github.io/lucid-YOLO/work_packages/wp-155/) ➡️


## WP-154b — two conventions given up, and one frozen golden overridden to hold them

<a id="wp-154b"></a>

Two local geometric conventions move to match `fuse-augmentations`, both before any delegation row touches these files. `AffineParams.matrix` (`data/affine.py`) composes rotation, scale and shear about `((W-1)/2, (H-1)/2)` rather than `(W/2, H/2)`. `mirror_rboxes` (`data/rotated_aug.py`) and `HorizontalFlip._mirror_targets` (`data/augment.py`) mirror about `(width-1)/2` rather than `width/2`. Neither file imports `fuse_augmentations`; this row is the convention alone, not the delegation.

**Every dependent literal traced before it moved, never pasted from output.** `goldens/aug_invariants.json`'s producer was re-run with the centre reverted and nothing else; all fifteen stored values reproduced bit-exactly, certifying that the whole movement in the live re-freeze is the centre change and nothing else. Seven metrics moved — `affine_image_mean`, `affine_bbox_coord_sum`, `affine_polygon_area`, `fused_image_mean`, `fused_bbox_coord_sum` past tolerance, `mixup_image_mean` and `rotated_rbox_area` within it but re-frozen anyway for the same traced cause. The mirror axis is not exercised by this producer (no `HorizontalFlip` or `mirror_rboxes` call inside it), and none of its metrics moved from that change, exactly as predicted. `goldens/data_checksums.json` (`"freezable": false` since [WP-154c](https://borda.github.io/lucid-YOLO/work_packages/wp-154c/), no frozen copy) moved from both conventions at once — the producer runs the whole WP-015 pipeline including the flip — and a four-way attribution run (both old, centre-only, mirror-only, both new) split `bbox_coord_sum`'s move into `-242.000` from the mirror (every one of 242 drawn x-coordinates shifts by exactly one pixel — a mirror is an isometry, so `bbox_area_sum` is untouched by it) and `+13.363` from the centre, with the both-old reconstruction reproducing the stored values bit-exactly as the control.

**The brief's rule for tier-A/C contract tests needed a correction, not a waiver.** The expectation going in was that invariant cases (an involution is an involution under either pixel convention) need no changes and any break there is a real bug — that held. What it missed: a *point-anchored derived* case states the old convention in its own closed-form arithmetic, so five cases in `test_aug_contract.py`, `test_photometric.py` and `test_rotated_aug.py` needed re-derivation, not correction-by-code-output. Each was worked by hand from the new convention — a quarter turn about `(3.5, 3.5)` sending `(1,2)→(5,1)` under the new centre, a mirror axis at `2.5` on a six-pixel canvas, and so on — and only then checked against the running code, so a hand-derivation error would have surfaced as a test failure rather than silently demoting a tier-A derivation to a tier-B characterization. Every one matched. `test_aug_frozen.py`'s five affected cases (`test_boxes_land_on_frozen_coordinates`, `test_polygon_ring_lands_on_frozen_vertices`, `test_boxes_land_on_frozen_output_canvas_coordinates`, `test_sheared_rotated_box_lands_on_frozen_parameters`, `test_mirrored_then_warped_keypoints_land_on_frozen_coordinates`) were recomputed from the code path directly, being tier B by definition. The rotated-box case's own signature confirmed the mechanism: `w`, `h` and `theta` held to six decimals and only the centre coordinates moved, which is exactly what a translation of the composed map should do to a shape's position and not to its extent.

**One frozen golden could not be satisfied by any resolution the brief was authorized to make.** `goldens/frozen/0.6/aug_invariants.json` — a pure-code snapshot the v0.6.0 release (`22739e1`) wrote — pins the same five metrics past their tolerance, and AGENTS.md §7 lists modifying a frozen golden as a standing prohibition, not one of the escalation triggers a ruling can waive case by case. This is not [WP-132](https://borda.github.io/lucid-YOLO/work_packages/wp-132/)/WP-154's category: those two goldens were generator-derived and could never again be satisfied by any code change, a category error in what got snapshotted rather than a real guard; this one is pure local code and was a genuine guard for 0.6.0's behaviour, broken here by a deliberate, traced convention change rather than by drift. An entry went to `docs/ESCALATION.md` (2026-09-03) with three options — remove the file on the [WP-132](https://borda.github.io/lucid-YOLO/work_packages/wp-132/)/WP-154 precedent, update its five values in place (which §7 forbids outright), or re-scope the row to 0.7 and block every remaining Phase 14 row on that wait, all of which depend on this one landing. Presented with the no-rule-override alternative, the principal chose the override: the file's seven traced metrics are updated in place to match the live golden exactly, on record in `docs/ESCALATION.md`, rather than removed. §7's prohibition otherwise stands; this is one dated exception, not a precedent for the next one.

Left untouched by design: `rotated_geom.py`'s `canonicalize`, every invariant-based contract case, `goldens/frozen/0.5/` and every other `0.6/` file, and no `fuse_augmentations` import anywhere in this row — the delegation itself is [WP-155](https://borda.github.io/lucid-YOLO/work_packages/wp-155/)/156/157's work.

