βοΈ Decision Record¶
Architecture- and policy-level decisions. D1βD11 are transcribed from the governing blueprint (v1.5, 2026-07-10); D12 records execution-session amendments (2026-07-31). ADRs expand the decisions with lasting architectural consequences.
π Decisions¶
| ID | Decision | Resolution |
|---|---|---|
| D1 | Scope | Detection + instance segmentation + OBB, delivered as sequential release-train milestones (0.1 β 0.2 β 0.3, see D10) on top of the fully gated detector. Pose and classification remain future 0.x work; YOLOE-26 out of scope entirely. |
| D2 | Reproduction claim | Faithful method reproduction (from-scratch training), not exact-number reproduction. Targets are the paper's relative/ablation claims and the from-scratch reference in R1 Table 4. No Objects365 pretraining, no evolutionary hyperparameter search. |
| D3 | Scale strategy | Family-generic code. Iterate/debug at n-scale, headline runs at s-scale (all paper ablations are s-scale, including seg and OBB). |
| D4 | Framework | PyTorch Lightning LightningModule + Trainer, automatic optimization. MuSGD is a single custom torch.optim.Optimizer; ProgLoss is an epoch hook; close-mosaic and EMA are callbacks. Task heads reuse the same LightningModule with task-conditional loss composition. |
| D5 | Source allowlist | Strict: the three papers + their cited primary literature + neutral dataset/tooling documentation only. All Ultralytics web properties β including docs.ultralytics.com β are inadmissible, alongside source code, YAML model configs, and released weights. Full policy in AGENTS.md and docs/PROVENANCE.md. |
| D6 | Muon core | Implement NewtonβSchulz orthogonalization from scratch per R7/R8; no third-party optimizer dependency. |
| D7 | Identity | Repository/package name lucid-yolo (personal repository; employer sign-off required before any organizational nexus). "YOLO" used as the model-family/category term; naming evidence in docs/PROVENANCE.md. "YOLO26" and "Ultralytics" never appear in package, module, or model identifiers. |
| D8 | Verification | Published tables only. Fidelity gates use printed param counts, FLOPs, and mAP values from R1/R2 β Table 7 (detection), Table S9 (segmentation), Table S11 (OBB). No black-box runs of the reference package anywhere in the 0.x series. |
| D9 | Configuration strategy | Architecture in code; YAML for experiments only. See ADR-001. |
| D10 | Versioning and release policy | Perpetual 0.x β no 1.0 milestone is planned. See ADR-002. |
| D11 | Execution model | Autonomous agent execution under principal gates. See ADR-003. |
| D12 | Execution-session amendments (2026-07-31) | (a) Git flow: work lands as one commit per WP directly on local main; make gate green is the merge gate (replacing the blueprint's PR/squash-merge flow β single-operator repository, no branch protection available locally); pushes to the remote are batched at phase boundaries and each push requires explicit principal confirmation. (b) Synthetic fixtures and data stand-ins: test fixtures and offline [DATA]-WP development stand-ins are generated with fuse-augmentations (R21, Apache-2.0, pinned commit) instead of hand-annotated images β recorded as A26; real COCO/DOTA remain mandatory for tier acceptance. (c) Accelerator: [GPU] WPs attempt Apple MPS locally first; CUDA runs remain [PRINCIPAL]-gated. (d) Lint routing: all linters (ruff check/format, mypy, hygiene hooks) run exclusively through pre-commit run --all-files; make gate = precommit + test + golden. (e) Subpackage naming (2026-08-01): the Lightning-integration subpackage is src/lucid_yolo/ptl/ (blueprint sec. 7 named it lit/; renamed to avoid lucid_yolo.lit stutter); Phase 5 commit scopes use feat(ptl). (f) Package rename (2026-08-02): distribution lit-yolo -> lucid-yolo, import lit_yolo -> lucid_yolo, console scripts lucid-yolo/lucid-download, variants lucid-yolo-e2e-{n..x}. Rationale: the lit- prefix is Lightning AI's own project-naming convention (lit-llama, lit-gpt) and the project must not borrow any third party's branding; lucid- states the project's education/readability goal. Alternatives ruled out during the decision: open-yolo (occupied PyPI name) and plural *-yolos forms (collide with the unrelated YOLOS ViT detector, hustvl "You Only Look at One Sequence"). Verified at decision time: lucid-yolo free on PyPI (404) and one inactive hobby repository on GitHub. Naming-evidence record and its usage discipline (docs/PROVENANCE.md, the section this repository cites as "sec. 3.5") unchanged. What (f) names is what existed on 2026-08-02, and is left as the record of that date: lucid-download was removed in 0.4.0, as 0.3.0 said it would be, and the shipped console scripts are now four β lucid-yolo, lucid-data, lucid-eval, lucid-predict β declared in pyproject.toml's [project.scripts], which is where the current set is read. The lucid-yolo-e2e-{n..x} forms were never console scripts and are not declared anywhere: e2e is the feature name the decode path carries in code (DECODE_PATHS in predict.py), and the hyphenated variants are the model-identifier spelling the naming-evidence record reserves. The renames the row actually decided β the distribution, the import package, the ban on a version number in a model identifier β all stand. |
| D13 | Reference-implementation consultation (2026-08-05) | Allowlist widened, denylist unchanged. Detection implementations under a permissive license with no Ultralytics lineage may be read for reference when diagnosing a structural defect. Admissible licenses are exhaustively: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC (e.g. torchvision, YOLOX, MMDetection, PP-YOLOE). Inadmissible at any cost, regardless of how useful the content is: AGPL, GPL, LGPL and every other copyleft license; source-available, research-only and non-commercial licenses; anything commercially licensed or of unstated license. Unlicensed or ambiguously licensed code is treated as inadmissible, not as permissive. Three further conditions apply: (i) the repository's LICENSE and independent provenance are verified before it is opened, (ii) it is registered in PROVENANCE.md with the access date and what it informed, (iii) no code is ever copied β the sec. 7 prohibition on copying from external detection repositories is unchanged, as is the absolute Ultralytics denylist. Rationale: three Det-smoke attempts stalled at 4-6 mAP with the failure mechanisms only identifiable by comparison against a working reference; the papers alone under-specify normalization and assignment conventions. User decision, requested 2026-08-05. See ADR-004. |
| D14 | Releases ship no trained weights (2026-08-07) | Source, goldens and the reproduction report are the release artifacts; trained checkpoints are not published. The reproduction's claim is that the method reproduces from the papers, and that claim is carried by the frozen goldens and the fidelity gates, not by a binary anyone can retrain from the recipe. Publishing checkpoints would additionally require a provenance story for every artifact and a hosting commitment, neither of which serves the clean-room goal. Supersedes the "weights published" clause in the WP-046, WP-054 and WP-064 definitions of done, which predate this decision. |
| D15 | Bundled native libraries are audited; recognized license exceptions pass, and two vendored libraries are allowlisted (2026-08-11) | The license audit reads bundled License-File entries, not only the metadata license fields. Three rules follow. (a) A GPL-family declaration carrying a recognized exception is permissive by construction and is not a finding for any package β currently the GCC Runtime Library Exception, matched by expression rather than by package name, so a future dependency built by gcc needs no allowlist entry. (b) shapely is allowlisted for the LGPLv2.1 GEOS binaries its wheel carries. (c) numpy is allowlisted for libquadmath (LGPL-2.1-or-later) alone; its sibling libgfortran/libgcc pass under rule (a), and the exception is tested before the allowlist so that a package listed for one vendored library is not silently excused for every other one it ships. The numpy exposure was found by the very check this decision adds, on its first run β it is a runtime dependency whose declared license is BSD-3-Clause, and the GCC runtime it vendors was invisible to every audit the project had run until then. Found during WP-063: shapely declares License: BSD 3-Clause and its wheel bundles GEOS shared libraries under LGPLv2.1, so the audit β which read only License, License-Expression and License :: classifiers β passed while an LGPL binary sat in the environment. The blind spot is general, not shapely's: any wheel may vendor a native library under a license its own metadata never mentions, and the audit is the gate that is supposed to see it. The allowance is narrow and rests on four facts, each of which would have to stay true: shapely is a dev dependency-group package, src/ never imports it, GEOS is dynamically linked at test time only, and neither is vendored into this repository or present in any published artifact. LGPL is also not what the policy bans outright β AGPL and commercial licenses are β and a test-only dynamically-linked dependency is the weakest form of contact with weak copyleft. The oracle it provides is the point: A24's validation is an independent polygon implementation, and replacing it with our own float64 code would leave the kernel checked against something sharing its assumptions. Recorded rather than waved through, because the allowlist in scripts/lint/audit_licenses.py requires a decision entry before any entry is added. |
| D16 | Shipped binaries are audited by filename against a named table (2026-08-15) | The license audit reads a third surface: the files a wheel says it installs, not only what it declares and what its license documents say. supervision, sourced as the drawing library for WP-067's example, hard-requires av>=14.2; the av wheel declares BSD-3-Clause, ships a licenses/LICENSE.txt with no GPL mention anywhere in it, and ships av/.dylibs/libx264.165.dylib β x264 is GPL-2.0, offered commercially as the alternative. Both existing checks pass it clean, so the gate would have admitted a GPL binary in silence. supervision is refused on that basis and WP-067's example is drawn with matplotlib (R29), already a dependency. Three parts follow. (a) The scan matches shipped filenames against COPYLEFT_BINARIES, a table naming x264, x265, mp3lame, GEOS and the eight FFmpeg libraries, each entry carrying its license and where that license was read. (b) It narrows the hole rather than closing it, and the module docstring says so in those terms: a copyleft library the table has never heard of passes exactly as av did. The alternative β failing on every unrecognized binary β is not available, since torch alone ships hundreds and a gate that fires on every commit is a gate that gets disabled; a green run is evidence that no listed library is present and nothing more. (c) Its allowlist is keyed on (distribution, library) where the bundled-document allowlist beside it is keyed on the package alone, because D15's own rule is that a package excused for one vendored library is not excused for the next one it ships β the two entries it carries are D15's shapely/GEOS allowance reached by the file list instead of by the license document, not a widening of it. Additions require an entry here, as for both other allowlists. |
| D17 | The accelerator environment is not a dependency, and an unreadable licence is allowlisted by name (2026-08-17) | WP-115 made the absence of a licence a finding, and the first thing it found was cuda-toolkit. The wheel's dist-info holds METADATA, WHEEL and RECORD and nothing else β no License, no License-Expression, no License :: classifier, no licence document of any kind, verified from the wheel itself rather than from an index page. So the finding is correct: nothing in that distribution states its terms. Two things follow, and they are separate. (a) CUDA is out of scope as an environment, not admitted as a licence. The NVIDIA CUDA EULA is proprietary, which the permissive-only policy would otherwise refuse; the exemption is that pyproject.toml declares no CUDA package, this project redistributes no part of the toolkit, and it publishes no trained weights (D14), so what CUDA licenses is the machine an accelerator run happens on rather than anything this repository ships. Stated here so the exemption is a decision on record instead of a silence. (b) The mechanism is a fourth allowlist, UNREADABLE_ALLOWLIST, keyed by distribution. Kept separate from the three beside it because the exposures differ: ALLOWLIST excuses a package's own copyleft declaration, BUNDLED_ALLOWLIST and BUNDLED_BINARY_ALLOWLIST excuse a vendored copyleft library, and this one excuses metadata that says nothing at all. Folding them together would let one package's silence excuse another package's declaration. Additions require an entry here, as for all three others. cuda-toolkit is its only entry. |
| D18 | The WP contract ends with the reproduction; a new task restarts it (2026-09-02) | The one-WP-one-commit contract is a reproduction instrument, not a permanent process. It exists so that a from-scratch reproduction of three papers is auditable row by row, and once the reproduction report carries all four accepted tiers that purpose is served. Three preconditions, all outside any single row: O3 cleared, the repository made public, and WP-125 accepted at its principal gate. (a) What relaxes. A change that alters no shipped behaviour, adds or removes no public symbol, moves no golden and changes no documented assumption lands as an ordinary commit under the same make gate β typo fixes, docstrings, lint and CI maintenance, added tests. Everything else still opens a WP, and the gate itself never relaxes. (b) What restarts it. Adding a task to the model family β a fifth head after detection, segmentation, oriented detection and keypoints β re-triggers the full procedure: its own phase, numbered WPs, a smoke tier, a principal gate on a relative mechanism claim, and its own 0.MINOR. A new task is a new reproduction claim, and D2's standard applies to it exactly as it applied to the first four. (c) Git flow. D12a is unchanged for the principal: work still lands as one commit per WP directly on local main. Outside contributions arrive as pull requests against the same gate. (d) Admission is three layers, because one is not enough. The exposure is not Ultralytics specifically but any source this project cannot redistribute under Apache-2.0 β copyleft (AGPL, GPL, LGPL, SSPL), source-available (BSL, Elastic, PolyForm), paid, proprietary, or with a licence that cannot be read (D13, D17). No signature detects such code arriving, so the layers are chosen for how differently they fail. A DCO sign-off (WP-142) records ownership and right to submit: it makes the contributor's claim explicit and durable, which is what recourse and a good-faith record are built on, and it is enforced by a check in this repository rather than a third-party app, since every free hosted CLA service surveyed on 2026-09-02 was either archived, years stale, or a two-star project. A generalized attestation (WP-143) fixes what the claim covers β today's pull-request template names one vendor where the rule is a whole licence class. A provenance trailer on every contributor commit (WP-144) is the only layer producing evidence instead of a promise: a contributor must name what an algorithmic change derives from, resolvable against docs/PROVENANCE.md, and an unnamed derivation on a loss or an assigner is then visible at review. A signature is a liability instrument β it says who answers if the work was not theirs. It does not cure infringement in a published release, and it does not stand in for reviewing the diff. Whether a Contributor License Agreement is also required is a question for counsel alongside O3; the DCO is the floor, not the ceiling. |
| D19 | The augmentation engine moves to fuse-augmentations, behind a stated boundary (2026-09-02) |
Resampling and the coordinate transport riding with it are a general-purpose subject; task semantics are not. This project implements both today, and the augmentation half is a second implementation of a package the same author maintains. fuse becomes the engine and lucid-yolo becomes its first real-project consumer, under a boundary written down before any code moves. Nine sub-questions were put to the principal and accepted on 2026-09-02: fuse-side work runs in a separate session, so every capability arrives as a released pin rather than a same-session edit; multi-image assemblies and polygon rings stay local while rotated boxes move; a runtime dependency is accepted under four conditions; the guard is captured before any swap and keypoint export parity lands between them; and the effort spans at least two releases, the guard's own and the swaps'. See ADR-005. |
| D20 | fuse-augmentations becomes a runtime dependency on a commit pin, and the distribution becomes unpublishable to PyPI (2026-09-04) |
ADR-005's first condition is knowingly not met, and the alternative was worse. Promotion was gated on four conditions, the first being real SemVer releases to PyPI. PyPI's latest fuse-augmentations is 0.10.0.dev0, it carries no 0.11 or 0.12 at all, and every release there is a .dev0 pre-release; the capability floor Phase 14 stands on is the commit a5a276a. A direct-reference requirement is legal to build and install and illegal to upload, so this pin makes the distribution unpublishable to PyPI. What made refusal untenable is that Phase 14 already moved: five modules under data/ import fuse_augmentations at module level, so lucid_yolo.data β and predict, through letterbox β cannot import without it. Leaving it in the dev group meant every install without that group produced a package failing at import rather than one missing an optional extra, and ADR-005's own stated fallback ("a refusal returns the dependency story to a SHA pin, which keeps the augmentation stack local") was written while the stack was still local and no longer describes anything. The condition is accepted as failed because it protects nothing this project currently does: release.yml states publication to PyPI is itself an unmade [PRINCIPAL] decision and deliberately omits it, so no upload exists to be rejected. Conditions 2, 3 and 4 are met β the exact SHA is a stricter ceiling than a range, the promotion landed in its own work package with its own gate and licence-audit run, and this row is the record. Alpha-status runtime dependency accepted deliberately; revisit the day a 0.12 reaches PyPI, when the fix is a >=0.12,<0.13 range and nothing else changes. The build target named for PyPI outlives the ability to use it, and is kept rather than removed. make dist-pypi TAG=v0.M.P β the absolutize_readme.py rewrite that makes the long description's figures and links resolve off pypi.org β still exists and still works, and since this row it cannot produce an artifact PyPI would accept: the direct reference is legal to build and install and is refused at upload. It stays because what the rewrite fixes is the long description's broken relative links, which are broken for any reader who meets the distribution outside the repository β and release.yml runs it ahead of uv build for a distribution set it uploads as inspectable workflow artifacts, publishing to no index at all, exactly as that workflow's own comments say. Read its name as the build shaped for a package index, not as evidence that publishing to one is available; the target that would consume it is the unmade [PRINCIPAL] publication decision release.yml omits, and that decision now has this pin in front of it as well. Presented to the principal with three alternatives β hold the release until PyPI catches up, or split the promotion into a later row and ship 0.7.0 with the exposure documented rather than fixed β and this was chosen. See docs/ESCALATION.md, 2026-09-04. |
| D21 | D1's scope clause is spent on its keypoint half, and D1 is not edited (2026-09-05) | The keypoint tier shipped at 0.5.0; D1 still reads "pose and classification remain future 0.x work". D1 is transcribed from the governing blueprint and is a record of a decision taken on 2026-07-10, not a description of the repository, so it is left exactly as written β a decision log whose entries are rewritten to match what later happened stops being evidence that anything was decided. This row supersedes the keypoint half of that clause and nothing else: classification and YOLOE-26 remain out of scope entirely, and no row proposes them. Two qualifications the original wording could not carry. The shipped tier is keypoints, not pose β K is a constructor argument the way the class count is, and nothing in the head, the loss or the decode knows what a point means; human pose is one instantiation. And it is the one accepted tier not drawn from R1: its loss and evaluation protocol come from RLE (R14, arXiv:2107.11291) composed onto the same trunk, because no allowlisted paper publishes a keypoint architecture or parameter table to check the head against (A65, A66). D1's "pose" therefore never named what shipped, which is the second reason to supersede rather than amend. |
ποΈ ADR-001 β Architecture in code; YAML for experiments only (D9)¶
Status: accepted (blueprint v1.2).
Context: YOLO-lineage reference implementations describe model topology in YAML DSLs. This project must neither consult nor resemble that expressive artifact.
Decision: model topology and blocks are typed Python β builder functions plus a 5-row scale-multiplier dataclass registry. YAML (via LightningCLI/jsonargparse) covers only run-level configuration: data paths, tier schedules, optimizer/loss gains, augmentation strengths.
Consequences: (i) clean-room β a layer-list YAML DSL would structurally converge on the reference implementation's model-YAML format; (ii) the paper defines exactly one topology with five multiplier rows β a configurable graph engine is over-engineering; (iii) the Phase 2/7/8 param/FLOP gates test Python constructors directly, and mypy covers what a DSL cannot. No model-topology config format may ever be created (standing prohibition, AGENTS.md).
π ADR-002 β Perpetual 0.x release train (D10)¶
Status: accepted (blueprint v1.3); the weights clause of its Consequences is superseded by D14 (2026-08-07). Where the two disagree, D14 governs.
Context: the project tracks a living specification β the paper plus this project's assumption register. A 1.0 would imply an API-stability contract and a completeness claim a research reproduction should not make.
Decision: SemVer 0.MINOR.PATCH forever. Each 0.MINOR is a gated capability milestone (breaking changes permitted, called out in release notes); PATCH covers fixes, docs, and assumption-register revisions whose results stay within golden tolerances. Release train: 0.1.0 = detector (Phase 6 gate), 0.2.0 = +segmentation (Phase 7), 0.3.0 = +OBB (Phase 8), 0.4.0+ = rolling.
Consequences: each 0.MINOR freezes its golden metrics; later releases must never regress any frozen golden β frozen goldens are immutable, a genuine correction ships as the next 0.MINOR with an explicit changelog note. Immutable has one recorded route through it and two recorded uses of that route: escalation trigger 4 (AGENTS.md sec. 4), answered by the principal, which was granted twice on 2026-09-03 for goldens/frozen/0.6/aug_invariants.json β WP-154b and WP-155, both entries in docs/ESCALATION.md. Both are dated exceptions and neither is a standing waiver; the rule is stated here with its exceptions named because a rule whose exceptions live only elsewhere reads as either false or absolute, and it is neither. Every release ships with resolved run configs + seeds, its report section, a changelog, and β as this ADR was written β weights where dataset licenses permit. That last clause no longer holds and is left standing rather than edited away: D14 (2026-08-07) settles that releases ship no trained weights at all, on grounds that are not about dataset terms, so the licence condition is not narrowed by it but replaced. The ADR records what was decided at blueprint v1.3; D14 records what is done. No 1.0 is ever planned, promised, or tagged.
π¦ ADR-003 β Autonomous execution under principal gates (D11)¶
Status: accepted (blueprint v1.5); amended by D12(a) for local git flow.
Context: the roadmap decomposes into numbered work packages (docs/ROADMAP.md), each independently implementable and gateable β 67 of them when this ADR was written at blueprint v1.5, and it has grown by a phase at a time since. The current figure is a property of docs/ROADMAP.md and is read there, never restated here: a count copied into a decision record is stale by the next row that lands, and this one was.
Decision: an agent executes WPs in dependency order without per-step approval, subject to the contract in AGENTS.md. Each WP is one commit that must leave main green. Three classes require explicit principal action and are marked [PRINCIPAL]: (a) compute-heavy tier runs (>4 GPU-hours), (b) release tags, (c) legal/nexus review (O3) and dataset-licensed weight publication (O4).
Consequences: agents never widen the source allowlist, never create model-topology configs, and stop rather than guess (escalation protocol in AGENTS.md and docs/ESCALATION.md). The assumption register plus the escalation log is itself research output a from-code port could not produce.
π ADR-004 β Reference implementations readable, never copyable (D13)¶
Context. The blueprint's v1.4 tightening (D5) restricted implementation sources to the three papers, their cited primary literature, and neutral tooling documentation. Three Det-smoke attempts then stalled at 4-6 val mAP50-95 against a
25 criterion. Two root causes were found by measurement alone (WP-078 pixel-frame L1, WP-079 augmentation-RNG collapse), but the papers do not fix every normalization and assignment convention precisely enough to rule out a third.
Decision. Ultralytics-independent detection implementations under a permissive license β MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, and nothing else β are admissible as reading references for diagnosis. Each must be LICENSE- and provenance-verified before it is opened and registered in PROVENANCE.md. Copyleft (AGPL, GPL, LGPL), source-available, research-only, non-commercial, commercially licensed and unlicensed code stay inadmissible at any cost: the licence gate is decided before the content is known, so no diagnostic value can ever justify opening one. A repository whose license cannot be established is inadmissible by default. Copying code from any external detection repository remains prohibited (sec. 7), and the Ultralytics denylist stays absolute in every form: repository surfaces, package contents, docs site, and released weights.
Consequences. The clean-room position now rests on two claims instead of one: nothing from Ultralytics was consulted (unchanged, auditable via the fetch log), and nothing from any external repository was copied (enforced by the standing prohibition and the provenance trail). Reading a permissively licensed implementation to learn a convention is the ordinary practice the two-team clean-room pattern already contemplates for the specification side; what it must never become is transcription.
π§© ADR-005 β The fuse boundary and the battle-test contract (D19)¶
Status: accepted 2026-09-02. Records the agreement; consumes nothing yet. Phase 13 builds the guard, Phase 14 performs the swaps.
Context. src/lucid_yolo/data/ implements an augmentation engine β matrix sampling and composition, warping, letterboxing, per-modality target transport, photometric jitter, a post-warp instance filter β alongside the things that make it this project's pipeline: the Targets container, the R1 Table S3 recipe, dataset IO, DOTA tiling. The first half is not specific to detection, and fuse-augmentations (R21) exists to solve exactly it: composing compatible transforms into a single resampling pass instead of interpolating repeatedly. Maintaining both means maintaining two implementations of one subject, and the local one is the weaker of the two by design β it was written to serve a reproduction, not to be an engine.
Decision β the boundary. fuse owns the pixel-and-geometry engine: matrix sampling and composition, single-pass resampling, per-modality transport of boxes, keypoints, masks and rotated boxes, photometric ops, constant-fill padding, an aspect-preserving letterbox segment with an exact analytic inverse, and the post-warp instance filter. lucid-yolo owns the Targets container, the composition order, the R1 Table S3 recipe (build_scale_policy, close_mosaic), dataset IO and validation, DOTA tiling, polygon rings, multi-image assemblies, and everything from assign/ inward β model, losses, decode, evaluation, export, prediction. The rule that settles every case not enumerated: convention lives upstream, policy lives here. fuse owns how a matrix is built, composed and sampled; this project owns which numbers go into it. A specification that pushes a YOLO constant upstream is written wrong.
Three capabilities were argued and stay local. Multi-image assemblies β mosaic, mixup, copy-paste β do not resample at all, so a fusion engine gains nothing by holding them, and mosaic's four-images-in shape would need a second calling convention beside the one-image-in contract. Polygon rings are ragged, and clipping one at a canvas edge adds vertices, so upstreaming them would force a padded-tensor or list-of-tensors design onto a package whose every target is fixed-shape; it is avoidable, because under a single fused geometric segment the composed matrix fuse already returns is the same mapping it applied to the image, and applying that matrix to rings here makes the alignment invariant hold by construction rather than by agreement. Polygon rasterisation follows the rings. Rotated boxes move: five numbers, fixed-shape, batch-leading, exactly like the targets fuse already transports, and oriented detection is a field with its own literature rather than a YOLO idiom.
Decision β the migration protocol. Per capability, in this order and never out of it: (1) the upstream capability lands in fuse with its own acceptance tests; (2) a work package here bumps the pin and updates R21; (3) the frozen expectation suite passes unchanged against the newly pinned path, with the same explicit parameters; (4) the call site is swapped; (5) the local implementation and its now-duplicated tests are deleted. Steps 4 and 5 never precede 1β3. Step 3 never re-freezes: an expectation that turns red at a swap is diagnosed, and either the integration is fixed or a separate work package argues the old value was wrong β never both in one commit, because that combination is indistinguishable from adjusting the test until the new code passes. No capability ships half: an upstream release adding an API without its own tests cannot be pinned here, since a frozen suite proves the integration did not change behaviour and can never prove the upstream implementation correct in cases this project does not exercise.
Decision β the reciprocal battle-test contract. This project's smoke tiers, goldens and frozen augmentation expectations are the real-project evidence fuse is tested against, and that evidence stays here. The exchange is symmetric and worth stating so neither side later assumes the other holds it: fuse supplies an engine with its own unit acceptance, and lucid-yolo supplies the thing no unit test provides β four tasks, two datasets, published-number fidelity gates and trained tiers exercising the engine end to end. Neither substitutes for the other, and a capability is not considered proven until both have run.
Decision β four conditions on a runtime dependency. Promotion from a development pin to a runtime dependency is accepted, and gated on all four: (1) fuse cuts real SemVer releases to PyPI, one per capability landing β a git-URL requirement is legal in a dependency group and illegal in [project].dependencies, so a SHA pin is not publishable; (2) this project pins a range with a ceiling, on the hotcoco>=0.5,<0.6 precedent and for A73's reason, that a package whose incompatibilities fail silently needs re-verification per minor; (3) the promotion lands in its own work package with its own gate and licence-audit run, never folded into a capability swap; (4) it is recorded as a decision stating that an Alpha-status runtime dependency was accepted deliberately with the ceiling as the mitigation, so a later reader finds a judgement rather than an oversight. Condition 1 is an upstream commitment this project can state and cannot satisfy; it is unconfirmed at the time of writing, and a refusal returns the dependency story to a SHA pin, which keeps the augmentation stack local rather than making it unpublishable.
Consequences. The cost of the dependency itself is zero new packages: fuse requires numpy, pillow and torch, of which the first and third are already declared here and the second already arrives through four declared dependencies; its backends are optional extras and none is needed; Apache-2.0 clears the licence policy. The cost that is real is the coupling β this project's augmentation behaviour becomes a function of an upstream release cadence it does not control, which is why the guard is published as its own release before anything it guards moves, and why the boundary is written here rather than discovered per swap. What this project keeps after the move is what it was always for: architecture, task semantics, supervision targets, experimentation, export and inference.
π Open items¶
| ID | Question | Deadline | Default |
|---|---|---|---|
| O1 | GPU budget β tier commitment per task | before Phase 6 | All three A+B tiers, B on rented spot instances, sequenced Det β Seg β OBB; each 0.MINOR ships at A-tier if B still queued |
| O2 | Project name | resolved 2026-08-02 (D12f) | lucid-yolo; YOLO26 implementation exposed under feature name e2e |
| O3 | Employer nexus + counsel review of README/NOTICE naming | before the repository or any tag is public (before v0.1.0) | blocked-on-principal |
| O4 | OBB weight release policy given DOTA academic-use terms | resolved 2026-08-14 (v0.3.0) | Code + report Apache-2.0; DOTA-trained weights withheld, documented reproduction recipe |