ADR-015 — Derive the template datum from geometry, never from the reported parametric window¶
Status: Accepted
Date: 2026-09-05
Amends: PRD 7.14 (recorded there as a hazard), PRD 11.14 (the measurement)
Deciders: orchestrator
Raised by: reviewer R-C1, finding N6 — which judged that updating PRD 7.14 alone might suffice. The decision to record an ADR was not the reviewer’s.
Evidence: live measurement on Fusion 2704.1.53 (PRD 11.14)
Context¶
A miter template is a paper wrap. It is useless unless the fabricator can align it to a
known line on the tube — the datum (PRD 4, FR-3.1). The datum is an angular origin on
a cylindrical or conical face, so the obvious implementation is to take the face’s
parametric window and measure from its start: θ = v − vmin.
That obvious implementation is wrong, and it fails silently. Measured across nine
cylindrical faces at r = 14.3 mm on Fusion 2704.1.53 (PRD 11.14):
Source |
Reported |
|---|---|
|
|
|
|
|
|
One face, two APIs, two windows. The window is a per-face, per-API report, not a property of the surface.
The underlying parameterization is stable: v = 0 landed on +X on all nine faces
measured, worst deviation 0.000e+00. Only the reported window moves. So a datum taken
as v − vmin shifts by π — half a wrap, 44.925 mm of arc at r = 14.3 mm — between
a trimmed and an untrimmed face of the same tube.
This is the failure mode PRD 7 exists to catalogue: the template still prints, still looks correct, still wraps. It is simply clocked half a turn around the tube, and the error is only discovered after the metal is cut.
The hazard is not hypothetical bookkeeping. Trimming is not something the add-in controls — it is a consequence of how the user modeled the intersection, and PRD 2 fixes that the add-in reads geometry and never creates it. So both cases will occur in normal use, on the same tube, in the same document.
Decision¶
The datum is derived from an explicit geometric direction and asserted against PRD 4.
No datum, anywhere in the codebase, is derived from vmin or vmax.
Concretely, for a face with axis a and a chosen reference direction d in the plane
perpendicular to a:
Take
dfrom geometry that exists independently of the parameterization — the intersection direction, an explicit user selection (FR-3.1 “clock to”), or a documented world-axis fallback.Compute the angle of a point as
atan2(P·(a × d), P·d), a value that does not depend on what window any API reports.Assert the handedness convention of PRD 4 in code, not in a comment. PRD 7.1 records that a mirrored template looks perfect and fits nothing.
parametricRange() remains fine for what it actually is: a width, used to place samples
inside the face. Its endpoints are never a datum.
Consequences¶
Every datum implementation carries a geometric reference direction. There is no code path that reads
vminto establish an origin, and its absence is checkable by grep in review.The datum survives the user trimming, re-cutting or rebuilding a face, because it never depended on how the kernel reported that face’s window.
tests/must include a face in both trimmed and untrimmed form and assert the datum agrees between them. That test is the one that would catch a regression here, and it cannot be written without a fixture pair — PRD 13.2’s programmatic corpus.A cost: the reference direction must be chosen and justified per surface type, which is more work than reading
vmin. That is the point.
Alternatives rejected¶
Normalize the window first (shift whatever is reported to a canonical
[0, 2π]). Rejected: it assumes the two APIs disagree only by a phase offset, which is exactly the unverified assumption that produced the hazard. It also leaves the datum defined in terms of a reported quantity, so the next API that reports a third window reintroduces the bug.Always read the window from one chosen API (
parametricRange()only). Rejected: the measurement shows that the same API reports different windows for trimmed and untrimmed faces of the same tube, so fixing the API does not fix the datum.Document the hazard and rely on care. Rejected. This defect class already survived one review cycle in this repo as PRD 6.0’s cone row, and it survived precisely because it was prose that no test reads. A constraint that only lives in prose is not enforced.