Skip to content

WP-217 — audit residuals

Engineering log · Phase 19 — Codebase audit remediation

🔗 Depends on WP-216 · Needed by WP-218

⬅️ WP-216 · Roadmap · WP-218 ➡️

WP-217 — audit residuals

Finding. C-CONST left model ranking caps and the FLOP-counter image side as literals because models cannot import the decode layer. WP-205 normalized checkpoint tasks only during base construction: a subclass saving hyperparameters again could restore a Task member, which restricted checkpoint loading refuses. Oriented validation also converted axis-aligned predictions to the host before passing them to a strategy that discards them.

Change. The private detection cap lives in tasks.py, the existing stdlib-only leaf importable from both layers; decode.common.MAX_DETECTIONS retains its public name and object identity. Model ranking defaults share that cap, and the FLOP-counter side derives from the detection task spec. Every save_hyperparameters call normalizes recorded Task members and the logger snapshot, preserving Lightning's original caller frame and explicit arguments. The host conversion of the axis-aligned detections moves into _update_val_map, so the strategy that keeps that metric pays for it and the oriented strategy, which keeps none, no longer does; the rotated decoder and metric path stay unchanged. No public names, documented assumptions or goldens change.

Verification.

  • CPU. make gate green on this commit's tree. TestSubclassCheckpointTask.test_saved_task_is_plain_str, test_initial_snapshot_task_is_plain_str and test_checkpoint_loads_through_load_eval_module cover named and keyword-forwarding subclasses, including subclasses that save again. test_detection_cap_matches_model_ranking_defaults pins identity across all four ranking entry points, and test_flop_measurement_side_matches_coco_img_size pins the task-derived side.
  • Red before. Both re-saving subclass cases failed assert type(module.hparams["task"]) is str and the logger-snapshot assertion with <enum 'Task'>; both command-loader round trips failed with _pickle.UnpicklingError: Weights only load failed. The ranking-cap identity assertion failed while its numeric value remained 300.
  • Cause check. The original forwarding subclasses pass while both re-saving variants fail before checkpoint serialization. This rejects a loader-only fault and shows why constructor-only normalization is insufficient. The same assertions and restricted round trips pass after normalization moves to every save.
  • Goldens. scripts/check_goldens.py passes all 50 live and frozen files without moving any golden.
  • Oriented logs. One seeded real validation batch and epoch end retain exact equality of the returned loss and every val/* scalar before and after removing the conversion. _OrientedStrategy.update_box_validation discards axis-aligned predictions; update_extra_validation calls _update_val_rotated, which ranks and scores rotated boxes independently.
  • Not reproduced: single-file collection. The reported KeyError: 'keypoints' in test_sigma_choice_matches_coco_schema_only_at_seventeen_points does not reproduce on the WP-216 tree: the exact pytest --doctest-modules src/lucid_yolo/ptl/module.py tests/ptl/test_keypoint_training.py collection passes (60 tests) serially, under -n auto, under -n 2 -m "not gpu and not data" and with -p no:randomly, on pytest 9.1.1 and doctestplus 1.7.1. The keypoint accumulator the test feeds was replaced by WP-213's _KeypointAP after the report was written, and no traceback survives to say whether that is what removed it, so no patch and no regression test is added. A recurrence reopens it with its traceback.