Skip to content

📦 WP-153c — docs: Phase 14 rows split around the conventions and the measurements

Engineering log · Phase 13 — Contributor admission, augmentation guard and keypoint parity, v0.6.0

🔗 Depends on WP-153b · Needed by WP-154

⬅️ WP-153b · Roadmap · WP-154 ➡️

WP-153c — the rows split so that no commit both delegates and re-freezes

WP-153b corrected what the Phase 14 rows said about fuse and deliberately left the structure alone, because the structure depended on decisions that were still open. They closed, so this row does the splitting. Six rows become eight, and the single rule that produced every split is the one §6.5 already stated: a frozen value must never move in the same commit as a call-site swap, because the two are indistinguishable afterwards from adjusting the test until the new code passes.

Applying that rule strictly turns out to require moving conventions early rather than late. Two of the frozen values Phase 14 touches move for an honest reason — this project adopts upstream's composition centre and upstream's mirror axis, so literals that encode (W/2, H/2) and width / 2 are simply describing a convention the project no longer holds. The tempting arrangement is to let them move with the delegation that motivates them, which is exactly the arrangement the rule forbids. The workable one is to change the convention first, in the local implementation, where the literals move alongside a one-line arithmetic edit that anyone can read, and to let the delegation that follows move nothing at all. WP-154b is that row. It buys something beyond bookkeeping: after it lands, WP-155, WP-156 and WP-157 can be held to the strict reading — any tier-A, B or C value that moves inside one of them is a defect, and the row that moved it is where the defect is — which is a claim the earlier structure could not have made about WP-157.

WP-154 splits along the same seam. The pin bump is not a swap and its re-freeze is not a choice: upstream rebuilt the synthetic fixtures, and the goldens they feed have zero tolerance. WP-154 carries the bump, the two loud breaks it causes, and that re-freeze, with nothing delegated; WP-154b carries the conventions and the FA-1, FA-2 and FA-3 assertions. The loud breaks are worth naming because they are the pleasant kind. tests/fixtures/synthetic.py imports animal_shapes, which upstream's restructure removed, so the pin bump fails at collection rather than at some later assertion; the replacement is tuple(AnimalShape)[:KEYPOINTS_ANIMAL_COUNT], which is what the helper did, and the other three imports from that package are untouched. The fixture drift is louder still — a golden with zero tolerance cannot drift quietly. The discipline the row owes is not detection but tracing: every changed value is matched to a named upstream change before it is re-frozen, and one that cannot be matched is a regression rather than re-freeze fodder.

The letterbox gets a row because its failure is the quiet kind. Decision 6 delegates the resize and asks for the eval delta to be measured in a row of its own, which WP-155b is. The geometry matches exactly and the resampling does not, so every coordinate round-trip test stays green while image-derived metrics move on the evaluation path across six call sites. A delta that hides behind a green suite has to be measured on purpose or it is not measured at all; the row records the number whether or not it is zero, since "nothing moved" is a finding and an absent measurement is not.

Three DoD lines were added for traps that fail silently, each from §8.12's measurement. Upstream's instance_keep_mask defaults are 0.0 and 0.0 against this project's 2.0 and 0.1 — deliberately, on the reasoning that a library should not encode a plausible-looking minimum on the caller's behalf — so an omitted argument at any call site keeps every instance including ones pushed entirely off canvas, with no exception and no shape change. WP-155 now asserts both thresholds at every call site. return_matrix is None for exact-only and letterbox-only pipelines, not merely partial for split ones, so WP-156's consumer check is two conditions rather than one. And permute_keypoint_pairs moves coordinates without touching visibility flags, so WP-157 keeps the local keypoint_vis permutation instead of deleting _mirror_targets outright; dropping it would leave every mirrored sample with a visible point marked occluded and its partner marked visible, shapes identical throughout.

One claim was retired rather than moved. WP-158 said it re-freezes the tier-D determinism values against the now-upstream implementations. Tier D has no values: the module asserts same-seed-equal and different-seed-differ and nothing else, holds no literal, and appears in no golden — which was the point of separating it, since a seed-dependent frozen number would break at every swap for reasons unrelated to correctness and invite precisely the re-freeze-under-pressure the guard exists to prevent. So there is nothing there to re-freeze, and the row now says so. The sentence had been carrying an implication the design had already ruled out.

And the scope prose moved out of the table. Phase 14's cells had grown to three times the register's median length — around 1,500 characters where 374 is typical — because each row carries a boundary that is easy to cross by accident, and stating where a large swap stops takes paragraphs rather than a clause. A roadmap table is a register, not a specification, and prose that wide stops being readable as either. The full text now lives in Phase 14 — what each row does, and where its boundary is, one anchored entry per row, and each cell keeps a summary and a link. Nothing was dropped in the move; the entries are the cells' own words with room to breathe.

What this row does not do. It writes no code and moves no value. It also does not reorder the phase's dependencies beyond threading the new rows into the existing chain, and it does not revisit either decision it implements — both were the principal's, and this row is their mechanical consequence.