📦 WP-158 — docs: the augmentation stack after upstreaming¶
Engineering log · Phase 14 — Augmentation upstreaming to
fuse, v0.7.0🔗 Depends on WP-156, WP-157 · Needed by WP-159, WP-161, WP-163
WP-158 — what "reduced to what survives" was measured as¶
The scope asked for the export list to be "reduced to what survives, so the public surface states what this project still implements", and read literally that instruction does nothing: exactly one name did not survive Phase 14, FusedAffineLetterbox, and WP-156 already removed it. So the row's first job was to choose what the phrase is measured as, and to say so rather than leave the choice implicit in a diff.
The measure taken. A name stays if some consumer reaches for it through the package — from lucid_yolo.data import X from outside the module that defines it — or if living-doc prose names it. Measured by AST walk over src/, tests/ and scripts/, 30 of 54 names have a package-level importer and 24 have none, and every one of those 24 is consumed through its defining submodule instead (from lucid_yolo.data.coco import CocoDetectionDataset, and so on). There is no runtime attribute access on the package anywhere; src/ and scripts/ never import from the package at all, only tests/ do. The living-doc prong rescued six the import census alone would have dropped, build_scale_policy most pointedly — ADR-005 names it as a thing lucid-yolo owns, which is the sentence the whole row is trying to make the surface say. The list goes 54 to 37, and every submodule still declares its own __all__, so nothing published became unpublished: the package list is an index, and the module list is the declaration. The docstring now says that, so the next reader does not re-add names out of habit.
Two readings rejected, both defensible. The stricter one observes that every doc naming a rescued symbol cites its submodule path alongside it and never the package surface, so no document rescues anything and the list lands at 30. The other runs on ownership rather than use — publish what this project still implements, drop the four rotated transports that are now adapters — and lands near 45. It was rejected on its own example: warp_rboxes is not a thin adapter, it carries this row's narrow-inside-the-callback decision, so "drop what upstream owns" splits the transport family on a judgement no firmer than "who imports it", and it would publish zero-consumer names on ownership grounds alone. Use is the measure, and the docstring states that membership tracks use rather than ownership so the list is not misread as the boundary.
One name added back against the measure. HSVJitter has no package-level importer and the census removed it, which left six of the pipeline's seven transforms published and one missing — while the docstring introducing the list named the transforms as a group. An index whose description contradicts its contents teaches worse than an index with one arguable member, so the group is published whole. That is the single place in this row where the stated measure was overridden, and it is recorded rather than absorbed.
What each document needed, including the ones that needed nothing. A10 was a bare "Letterbox, aspect-preserving" and now records what delegated and what did not — the inverse stays closed-form because A10's own round trip has to be exact and a numerical inversion leaves a residual in it — closing on the boundary's actual content: pixels moved, geometry did not. A26 stops describing a test-only dependency: one pin now moves fixtures and training-time behaviour together, and what keeps them apart is freezable: false on the two generator-derived goldens rather than care. docs/PROVENANCE.md's R21 cell gains the second role in acquisition order, with the clean-room line restated — a permissive general-purpose package admitted as a dependency, never as a source to read a method from — and its per-commit fixture trace untouched. A21 needed nothing, evidenced: data/tiling.py is not in Phase 14's diff at all. The four model cards needed nothing, evidenced three ways: they are dated records of runs trained before the swap and retro-editing their procedure tables would falsify how those checkpoints were produced; "fused affine+letterbox" is still a true recipe description, since WP-156 preserved the fusion rather than dissolving it; and they contain zero references to any symbol Phase 14 deleted.
A11 was left alone, and why is worth recording. The scope paragraph calls A11 "the half-open rasterisation rule". A11's own row is anchor centre placement, (i+0.5)*stride; the half-open pixel-centre membership rule is cited as A11 from A37(iii). So the register carries one id for two rules, which the scope inherited. Nothing in A11 concerns the augmentation engine either way, so the row's outcome is no change — but the inconsistency is named here rather than silently reinterpreted, since the next reader to follow that citation will hit it too.
Nothing was left to re-freeze, which is the outcome the three delegation rows predicted: 36/36 with git status goldens/ empty. WP-155 moved letterbox_image_mean and re-froze it inside its own row; WP-156 and WP-157 moved nothing. Tiers A through D are untouched, tier D having no literal and no golden to re-freeze by design. README.md gained the decision it was missing — ADR-005/D19 removed a whole subsystem and was not among the six shaping choices the README enumerates, now seven — and one stale count was corrected in passing, 63 numbered assumptions against the register's actual 73. Its Current release: 0.4.0 is two releases behind __version__ and is left for the release row, which is what moves it.