Skip to content

PCB-MVP-0 slice 2: register what a coordinate frame's numbers mean - #8206

Closed
briansrls wants to merge 5 commits into
session/pcb-mvp-0-devicefrom
session/pcb-mvp-0-frame-scale
Closed

briansrls wants to merge 5 commits into
session/pcb-mvp-0-devicefrom
session/pcb-mvp-0-frame-scale

Conversation

@briansrls

@briansrls briansrls commented Aug 13, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #8205.

std.coordinate_frame mints a frame identity and deliberately carries nothing else, deferring a frame's other facts to whatever registers frames. Nothing registered them. This is that registrar, and the first fact it carries is not a display fact — it is the frame's length unit, which every coordinate living in the frame silently depends on.

WHY IT BITES NOW. The affine layer fixes its component to SignedMillimeterComponent, so every coordinate in the corpus means millimetres by convention. That was true of every subject the layer had been asked to hold: racks, chassis, rooms. A printed circuit board is the first one it is false for. A TQ144 package sits on a 0.5 mm contact pitch, so in whole millimetres two adjacent pins occupy the same coordinate — the geometry does not lose accuracy, it loses the distinction, and every later question about clearance or collision is asked of a shape that has already collapsed.

WHY THE SCALE IS A VALUE. Measure carries its scale as a type argument, which is the honest static spelling, and making the affine types generic over it is exactly the repair this layer already tried and measured as false. std.coordinate_frame records the measurement: the v1 seed's argument-position judge compares nominal head names and discards applied type arguments, which is how a Point3 and a Point3 flowed through one subtraction and returned a plausible 9. A scale parameter would be erased by the same mechanism, so it would announce a wall that is not there. This follows that module's corrected pattern — carry the discriminator as a value the operations compare — rather than re-litigating it, and shares its dissolve-on.

REFUSAL RATHER THAN CONVERSION, IN BOTH DIRECTIONS. 500 um asked for in whole millimetres rounds to 0 or 1 and both are wrong invisibly. 3 mm asked for in micrometres is exactly 3000 and loses nothing — refused anyway, and that arm is pinned by its own witness, because the moment the function answers the easy direction it is a unit converter and the caller who wanted one received it as a side effect of asking what something measures.

Seven witnesses pass. They include the positive control without which every refusal claim is satisfied by a projection that refuses everything, plus: an unregistered frame has no unit rather than a millimetre default, a non-decimal Scale member cannot register a frame, and one identity cannot hold two units.

DECLARED SCOPE, stated rather than left to be found. The existing Millimeter-typed surface across orthogonal_geometry and orthogonal_topology still assumes its frame is a millimetre frame. This PR makes the unit readable and stops silent truncation; it does not guard that surface. Guarding it is the next increment.

Rung: checked derivation, not construction — the same honest claim the frame identity carries, and for the same reason.

std.coordinate_frame mints a frame identity and deliberately carries nothing
else, deferring a frame's other facts to "whatever registers frames". Nothing
registered them. This is that registrar, and the first fact it carries is not
a display fact: it is the frame's length unit, which every coordinate living
in the frame silently depends on.

The affine layer fixes its component to SignedMillimeterComponent, so every
coordinate in the corpus means millimetres by convention. That was true of
every subject the layer had been asked to hold — racks, chassis, rooms. A
printed circuit board is the first one it is false for: a TQ144 package sits
on a 0.5 mm contact pitch, so in whole millimetres two adjacent pins occupy
the same coordinate. The geometry does not lose accuracy, it loses the
distinction, and every later question about clearance is then asked of a shape
that already collapsed.

The scale is a value, not a type argument, and that is not a shortcut. It is
the pattern std.coordinate_frame arrived at by measurement: the v1 seed's
argument-position judge discards applied type arguments, which is how a
Point3<RoomFrame> and a Point3<BuildingFrame> flowed through one subtraction
and returned a plausible 9. A scale parameter would be erased by the same
mechanism and would announce a wall that is not there. Dissolve-on is shared
with that module's.

Projection refuses rather than converts, in BOTH directions. 500 um asked for
in whole millimetres rounds to 0 or 1 and both are wrong invisibly. 3 mm asked
for in micrometres is exactly 3000 and loses nothing — refused anyway, because
the moment it answers that one it is a unit converter, and a caller who wants
one should say so somewhere that names the factor rather than receiving it as
a side effect of asking what something measures. Both directions are pinned.

An unregistered frame has no unit rather than a millimetre default; a
non-decimal Scale member cannot register a frame at all; one identity cannot
hold two units. Seven witnesses pass, including the positive control without
which "it refuses" is satisfied by a projection that refuses everything.

Declared scope: the existing Millimeter-typed surface across
orthogonal_geometry and orthogonal_topology still assumes its frame is a
millimetre frame. This makes the unit readable and stops silent truncation; it
does not yet guard that surface. That is the next increment, named here rather
than left to be rediscovered.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot gunbai-bot Bot changed the title mobo design scoping PCB-MVP-0 slice 2: register what a coordinate frame's numbers mean Aug 13, 2026
@gunbai-bot
gunbai-bot Bot changed the base branch from main to session/pcb-mvp-0-device August 13, 2026 03:46
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 13, 2026 03:46
@gunbai-bot

gunbai-bot Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Consolidated into #8214 at the operator's request. These four were a linear stack and the tip branch already contained every commit from all of them, so nothing is lost by closing here — the same commits are in #8214, now based on main.

Worth stating the cost plainly rather than letting it pass silently: this discards the approval tally these PRs accumulated. The combined diff is a different subject from any one slice and needs reviewing as one, so those approvals were not transferable in any case.

Closing this one; review continues on #8214.

@gunbai-bot gunbai-bot Bot closed this Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant