Skip to content

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

Engineering log · Phase 14 — Augmentation upstreaming to fuse, v0.7.0

🔗 Depends on WP-154 · Needed by WP-155, WP-157

⬅️ WP-154c · Roadmap · WP-155 ➡️

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

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, 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/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/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/156/157's work.