📦 WP-178 — fix(keypoints): R1 does publish the pose objective¶
Engineering log · Phase 17 — R1 pose-objective parity
🔗 Depends on WP-177 · Needed by WP-179, WP-180, WP-181, WP-182
WP-178 — the pose section was there all along¶
A false premise, found from outside. Issue 2 on the tracker reports what the record should have caught itself: R1 sec. 3.4.2 is a pose-estimation section — a sigmoid-bounded sigma branch, Eq. 10's normalized residual, Eq. 11's RLE term and an OKS-based loss the two are combined with — Table 9 ablates the OKS/RLE split and Table S10 publishes every pose scale's size, all inside R1's allowlisted role. D21, A65, A68, _build_keypoint_stem's docstring, test_param_flops.py's comment, the WP-139 entry above and both keypoint sections of the reproduction report say R1 has no such section. The citation map shows how: sec. 3.4.1 and 3.4.3 are cited across the tree, Eq. 7–9 and 13–15 likewise, and nothing between them — the gap was visible without opening the paper, and model_cards/keypoints.md had quoted Table 9's 63.0 since 0.5.0 while calling it a different paper's number. Confirmed 2026-09-17 against the arXiv PDF, not against the issue's paraphrase.
What changes and what does not. D22 withdraws D21's rationale clause and nothing else — the tier stays keypoints-not-pose, classification and YOLOE-26 stay out — and states what shipped as a partial reproduction of R1's objective: Eq. 11's RLE term, transcribed from R14 where R1 itself draws it, without the OKS term. In the registers and logs — DECISIONS, ASSUMPTIONS, this log, PROVENANCE — every stale sentence is struck in place with the date, on D21's own reasoning about records; the reproduction report, append-only under D10, gets a correcting note after its last section and its 0.5.0 section stays byte-identical; the model card, two docstrings and a test comment are rewritten outright with a dated note, since none of those is a record of a decision. Three findings the section forces are registered rather than resolved. A75: R1 gives the OKS loss no formula and cites it to a paper outside the allowlist, so losses/oks_loss.py derives 1 - OKS from R12's own definition — box area for s^2, since a keypoints batch carries no segment area — and enters at oks_gain = 0.0, keeping the shipped objective bit-exact and WP-125's paired-run evidence meaningful; Table 9's (24, 1) is the published split no run here has tested. A76: R1's printed Eq. 11 carries log sigma twice, once as the reparameterization Jacobian and once inside a Laplace term written in the un-normalized frame, where R14 Eq. 8 — what the code carries — has it once; the two differ by a 1/sigma gradient on every scale, and which R1 means is not settled by its text, so the form stays and the paired run that would settle it is a roadmap item. A77: measured at Table S10's protocol the point stem is 13.0% / 26.5% under the paper's n params / FLOPs and converges by l/x — the same finding A20 made for the angle stem before its width was chosen against Table S11, and it gets the same treatment: recorded, gate deferred until a width is selected against the table, nothing tuned in a correction commit.
What the term costs switched off. _score_branch gathers each branch's assigned positives once and scores them with both terms, so the added cost at oks_gain = 0 is one OKS evaluation per branch per step over already-gathered tensors — an exponential over the labelled points, no decode and no second argsort. It is logged pre-gain as train/oks for the same reason every other term is, so a run can see the number it is not yet optimizing.
The lesson is a check, not a resolution. Before the record says a source does not cover something, grep what the record already cites from that source and look for the hole: two adjacent subsections cited and the one between them never is not an absence in the paper. .notes/lessons.md carries it as a rule.