docs: the M3 paragraph, SOLVER §5b's arc/circle rules, FUSION_LOG 5/6/9/14
CLAUDE.md gains one M3 paragraph before the M2-B one: what landed
(fourteen sketch tools, inference on every commit with its three filters,
the drag, the Project tool, construction geometry, trim/split,
click-the-number dimensions, sketch pattern, offset and hinged planes
with `RePlaneSketch`, format 24, `NOT_YET` empty, 40 selftest checks in
lane order), the L2 gate now DRIVEN as well as headless, the deviations
each lane recorded, and the four gaps the driven gate itself found — the
cut chip that no circle selection can reach, the trim's orphan point, the
label that takes a viewport click, and the ribbon that overflows.
SOLVER.md §5b: the arc and circle rules, and two corrections that came out
of lane A's review rather than its plan. The rules look at STRICTLY
EARLIER entities, which is what makes them stable when several curves are
committed at once — an "all but self" reading has a hexagon's edge 0
propose `Parallel{0,3}` and edge 3 propose `Parallel{3,0}`, one relation
under two values that no dedup by value can see — with endpoint
coincidence the stated exception, since a point id has no ordering
relation to a curve id. And the rules are a LIBRARY, not a policy: the
app's commit path adds three filters of its own, the last of which only
the solver can decide (a proposal the sketch already IMPLIES).
FUSION_LOG: entries 5, 6 and 9 close with what M3 landed — tangency is
now proposed and drawable (`TangentArc`), trim and split have the picking
gesture the entry left open, a spline's fit points drag. Two residues are
recorded rather than left implicit: a trim leaves its old endpoint behind
and NO gesture deletes a sketch entity, which is the same missing
primitive that stops a spline's fit-point SEQUENCE being editable. New
entry 14 records that variables and expressions are deferred to M6, with
the measurement behind it (an XL that touches every dimension-carrying
payload, plus a second format break in one milestone before M5-1's
migration ladder exists) rather than the impression. And an unnumbered
note that `DRAW_SNAP_MM` (2 mm) subsumes the 0.5 mm inference tolerance
for `Coincident`/`Concentric` from a click — the relation between the two
numbers is nobody's decision yet, which is why it is written down.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -94,6 +94,76 @@ creation and the rename button can only rename a row to its current name; the dr
|
||||
send Alt, so a script cannot suppress inference. Still unmeasurable here: the RADV-to-lavapipe
|
||||
hot-pixel budget (no lavapipe ICD).
|
||||
|
||||
**M3 (sketching parity) landed 2026-09-07, in a serial prelude plus three parallel lanes.**
|
||||
The sketch canvas went from eight tools to fourteen — `Select`, `Line`, `Circle`, `Arc`,
|
||||
`Rectangle`, `Slot`, `Spline`, `Point`, and now `CentreRectangle`, `Polygon`, `ThreePointArc`,
|
||||
`TangentArc`, `Trim`, `Split` — and every drawing gesture now COMMITS INFERRED CONSTRAINTS
|
||||
(`vernier-solver`'s `infer_*`, at all four commit sites), with Alt suppressing, and with three
|
||||
filters that are the difference between a guess and noise: never what the sketch states
|
||||
verbatim, never a primitive's curve against another curve of the same primitive, and never one
|
||||
whose trial solve makes the sketch `Redundant` — the solver's verdict decides, since a slot
|
||||
stating `Parallel` itself makes a second `Horizontal` a duplicate no value comparison can see.
|
||||
Sketch points and curves DRAG against the solver (a continuation drag with an applied echo, so
|
||||
a locked rectangle does not move and a free point tracks). The **Project tool** pulls a face
|
||||
centroid, an edge's ends or an edge's centre into the sketch as references, `ProjectEdgeEnds`
|
||||
composing three commands behind one gesture; **construction geometry** is a per-curve flag with
|
||||
a `┄` tile and a dashed drawing, refused as a profile by name; **trim and split** cut a curve at
|
||||
a click, with the branch table's own refusals (a click on a curve's own end is refused rather
|
||||
than silently duplicating the shared corner); **dimensions** gained arc radius, a `⌀ diameter`
|
||||
reading, `RemoveConstraint`, and CLICK-THE-NUMBER — every `Distance`/`Radius`/`Angle` constraint
|
||||
paints its value in the viewport and clicking it opens a card that edits it in place; **sketch
|
||||
pattern** repeats picked curves linearly or circularly; and **construction planes** landed as
|
||||
`SketchPlane::Offset` and `SketchPlane::Angled` (a hinge of two sketch points plus an angle),
|
||||
with `RePlaneSketch` moving an existing sketch onto either. `SketchData.plane` has carried a
|
||||
`SketchPlane` since 2026-09-02; what M3 adds is that a GESTURE chooses it — the base plane
|
||||
buttons, the offset and angle steppers, and two re-plane rows — so the variants stopped being
|
||||
document-layer-only. Document format **24**. The three repoints Lane C
|
||||
wired (`SetLoftSections`, `SetSweepOrientation`, `SetSweepGuide`) were the last entries of
|
||||
`reachability.rs`'s `NOT_YET`, so **the built-but-unreachable list is EMPTY for the first time
|
||||
since it was written** and its expiry machinery (`Blocker`, the UI-enum reader, the prose pin)
|
||||
is deleted; what remains is the guard — `SOURCES`, both directory walks, and `Role::Commands`
|
||||
over `vernier-doc/src/command/`, which counts a command composed inside another command's
|
||||
`apply()` as reached. `--selftest` holds **40 checks**, in lane order A · B · C (the report
|
||||
digest moved once, deliberately; nothing stores it).
|
||||
**The L2 gate is now DRIVEN, not only headless** (`scripts/drive/l2-enclosure.json` + its
|
||||
negative control): the enclosure is built through the real shell from an EMPTY document —
|
||||
centre rectangle, locked centre, typed dimensions, an inferred `Horizontal`, a trim, the
|
||||
construction toggle, a sketch created on a FACE and re-planed onto an offset plane by the
|
||||
ribbon's stepper, a CUT extrude through the `cut` chip, a linear pattern, and a dimension
|
||||
edited by clicking its number, which propagates through the cut and all four instances. Its
|
||||
volumes are analytic except the shelled body, which has no closed form and takes the oracle's
|
||||
own plausibility band plus exact face and solid counts, with every later operation asserted as
|
||||
an analytic delta from that export.
|
||||
**Recorded M3 deviations.** A click within `DRAW_SNAP_MM` (2 mm) reuses the existing point, so
|
||||
`Coincident` and `Concentric` are not what a drawing gesture demonstrates — the draw snap
|
||||
subsumes the 0.5 mm inference tolerance, and two of lane A's own tests were passing on a
|
||||
constraint that made the sketch `Redundant`. The drag echo is cleared on every refusal path in
|
||||
`handle`, not in the arm, because a step the COMMAND accepts and the COMPILE refuses is rolled
|
||||
back there. A cut click that lands on a point MARK (±1 mm of model space, arms reaching past
|
||||
the corner) used to resolve to the point and be dropped in silence, so the refusal written for a
|
||||
click on a corner was unreachable for exactly those clicks; `cut::curve_at` leaves the marks out
|
||||
of a CUT pick only. The hover preview is answered as `Ask`/`Clear`/`Keep` with the armed tool
|
||||
inside the question, because arming Select raises no pointer event and the trim cross went on
|
||||
being painted under a tool that picks. Dimension labels are painted for exactly ONE sketch — the
|
||||
one being drawn into, or the one selected in the timeline — because a label is an interactive
|
||||
target that takes the click before the viewport sees it. The re-plane gestures ride ribbon
|
||||
STEPPERS rather than value-card params, because `card_for` would float an offset field over an
|
||||
empty viewport. There is no `show_datums` toggle yet, and a datum resolves a click only where
|
||||
the ID buffer has no face.
|
||||
**Four gaps the driven gate found, none of them fixed here.** (1) **A circular bore cannot be
|
||||
cut through the GUI at all**: a cut extrude reads `ShellState::extrude_cut`, only the `cut` chip
|
||||
writes it, the chip is painted only on the EXTRUDE card — and a picked circle floats the RADIUS
|
||||
card instead, since `card_for` prefers a `Surface::Value` row. No selection puts the chip and a
|
||||
circle on screen together, so the L2 gate's bolt holes are square pockets drawn as closed
|
||||
chains. (2) **A trim leaves its old endpoint behind** as a free point of the sketch and no
|
||||
gesture deletes a point, so reaching zero degrees of freedom costs a lock on geometry that draws
|
||||
nothing. (3) **A dimension label takes a viewport click before the sketch does** (measured: a
|
||||
click on one edge selected the neighbouring edge's label). (4) **The ribbon is one non-wrapping
|
||||
row and overflows**: at 2400 px the sketch workspace clips its last four constraint tiles — lock,
|
||||
unlock, construction, remove — so four committed M3 drive scripts are red at that width for no
|
||||
other reason, the `$` command bar is the standing route to a clipped button, and the L2 gate
|
||||
runs at 2600. Wrapping or collapsing the row is owed before the tool count grows again.
|
||||
|
||||
**M2-3/4/5 (booleans and seams) landed 2026-09-06.** Every production boolean runs
|
||||
`simplify: true` under Option C — a target face that absorbs tool faces of the same
|
||||
operation keeps its id and the absorbed tool faces are `Merged` into it; two target faces in
|
||||
|
||||
@@ -462,6 +462,16 @@ variant-addition should have carried.
|
||||
picking gesture: line-to-circle, circle-to-circle, arc-to-arc, and every mix. Nothing named by
|
||||
this entry remains open.
|
||||
|
||||
**Closed by M3 (2026-09-07): tangency is now PROPOSED as well as expressible, and there is a
|
||||
tool that draws it.** `infer_arc_constraints` / `infer_circle_constraints` (SOLVER.md §5b)
|
||||
offer tangent-to-line and tangent-to-circle on every drawing gesture, deciding the side and the
|
||||
external/internal sense once and never re-deriving them, and `SketchTool::TangentArc` continues
|
||||
a chain with an arc that leaves the previous curve tangentially — so the relation this entry
|
||||
was about can be drawn rather than only constrained after the fact. Two caveats, both measured
|
||||
rather than assumed: a proposal the sketch already IMPLIES is dropped by trial solve (a slot
|
||||
states `Parallel` between its own lines, so a second `Horizontal` would make it `Redundant`),
|
||||
and a tangency between two curves of the SAME primitive is never proposed at all.
|
||||
|
||||
### 6. Sketch geometry's curve-editing tools don't reach every curve kind — offset, mirror-within-a-sketch, sketch-fillet, trim/extend and curve splitting are now all built. — **RESOLVED FOR WHAT THIS ENTRY ASKED**
|
||||
|
||||
**Evidence this narrowed.** `SketchCurve` is four variants now (`Line`, `Arc`, `Circle`,
|
||||
@@ -578,6 +588,24 @@ trimming or extending a line or arc to a point, and splitting one into two are n
|
||||
ordinary sketch-canvas capabilities headlessly (trim/extend and splitting both pending their
|
||||
picking gesture). Nothing this entry named remains unbuilt.
|
||||
|
||||
**Closed by M3-4 (2026-09-07): trim and split have their picking gesture, and it is a TOOL
|
||||
rather than a selection.** `SketchTool::Trim` and `SketchTool::Split` interpret an arbitrary
|
||||
click near a curve — which is what this entry left open, and the reason it was left open was
|
||||
that a click near a curve is not a selection of an entity. The armed tool answers the question
|
||||
the click could not: under `Trim` the near half is kept and the far end moves to the click,
|
||||
under `Split` the curve becomes two sharing one point. The branch table's refusals are reachable
|
||||
and named: a click on a curve's OWN end refuses instead of minting a duplicate point at the
|
||||
shared corner, and a split outside the span refuses. Both are driven through the real shell in
|
||||
`scripts/drive/m3-b-trim-split.json`.
|
||||
|
||||
**One residue this entry did not name, found by the L2 gate: a trim leaves its old endpoint
|
||||
behind.** The far point is not deleted — it becomes a free point of the sketch, with two
|
||||
degrees of freedom and nothing drawn at it — and NO GESTURE DELETES A POINT. So a trimmed sketch
|
||||
cannot reach zero free degrees of freedom until someone locks geometry that draws nothing, which
|
||||
is exactly what `scripts/drive/l2-enclosure.json` does before it can assert an empty warning
|
||||
list. The missing primitive is "remove a sketch entity", and it belongs with the
|
||||
curve-mutation work this entry already describes.
|
||||
|
||||
---
|
||||
|
||||
## Rung L2 — blocks the jig and the enclosure
|
||||
@@ -648,6 +676,14 @@ names.
|
||||
(revolve, sweep, loft), control-point authoring, tangency and curvature-continuity
|
||||
constraints, and editing a spline's shape after the fact.
|
||||
|
||||
**Narrowed again by M3-11 (2026-09-07): a spline's fit points can be DRAGGED.** "Editing an
|
||||
existing spline's point sequence" was this entry's last piece of the curve-mutation gap, and
|
||||
half of it is now ordinary: a fit point drags against the solver like any other point, alone,
|
||||
without dragging its neighbours (`sketch-drag`, and `scripts/drive/m3-a-drag.json` through the
|
||||
real shell). What is still absent is changing the SEQUENCE — adding a fit point to an existing
|
||||
spline, or removing one — which needs the same "remove a sketch entity" primitive entry 6's own
|
||||
residue now names.
|
||||
|
||||
### 10. Loft is ruled only, with no tangency and no guides. — **PARTIAL, INVESTIGATED 2026-08-29, NOT A FLAG TO FLIP**
|
||||
|
||||
**Evidence.** `FeaturePayload::Loft` documents the choice explicitly and honestly: *"The
|
||||
@@ -836,6 +872,45 @@ wanted. And the m3 bracket's solved mirror plane — tilted ~1.5e-10 rad, enough
|
||||
a near-coincidence generator in its own right: the caps unify, the walls do not, and no linear
|
||||
tolerance changes that.
|
||||
|
||||
### 14. There are no variables and no expressions. Every dimension is a literal. — **DEFERRED TO M6, MEASURED**
|
||||
|
||||
**What is absent.** A dimension is an `f64` in the document and nothing else: there is no named
|
||||
parameter, no expression, no `= wall * 2`, no table of driving values. A part whose wall
|
||||
thickness appears in nine dimensions is nine numbers to retype, and a design intent that says
|
||||
"these two are always equal" can only be written as a constraint between geometry, never
|
||||
between NUMBERS.
|
||||
|
||||
**Why it is not in M3, and the measurement rather than the impression.** It was sized during
|
||||
M3's planning and came out XL on its own: a `Value` that may be a literal or an expression
|
||||
touches every dimension-carrying payload (extrude height, revolve angle, every
|
||||
`SketchConstraint` that holds a number, fillet radius, shell thickness, draft angle, pattern
|
||||
count and spacing, hole diameter and depth), needs an expression parser and an evaluation order
|
||||
with a cycle guard, needs the solver to be handed the EVALUATED numbers while the document keeps
|
||||
the unevaluated ones, and needs the UI to show both. It is also a second break of the save
|
||||
format inside one milestone — M3 already spends version 24 on construction geometry and
|
||||
`SketchPlane::Angled` — and the migration ladder M5-1 owes has not landed, so a second break
|
||||
would be a second unmigrated file generation.
|
||||
|
||||
**The decision (2026-09-06): M6, after the migration ladder.** Recorded here rather than left
|
||||
as a hole in the list, because "no variables" is the single most visible difference between this
|
||||
and any parametric CAD a person has used, and its absence should be a dated decision rather
|
||||
than an oversight.
|
||||
|
||||
### The click snap subsumes two inference rules (M3-1, 2026-09-07)
|
||||
|
||||
`DRAW_SNAP_MM` is 2 mm and the inference distance tolerance is 0.5 mm, so a click near enough
|
||||
to infer `Coincident` or `Concentric` has ALREADY reused the existing point: the two curves
|
||||
share one point entity and the relation holds by identity, with nothing left to constrain. Both
|
||||
rules remain reachable through a drag or a solve, and the hover glyph is unaffected. Two of M3
|
||||
lane A's own tests were asserting those rules through a gesture that cannot exercise them, and
|
||||
were green on a constraint that made the sketch `Redundant`.
|
||||
|
||||
Not a Fusion gap and not a defect — a tolerance relationship nobody chose. Whether the two
|
||||
numbers should be RELATED (one derived from the other, or the snap stated in terms of the
|
||||
inference tolerance) is an open question for whoever tunes snapping at dogfooding time; it is
|
||||
recorded here so the answer is not re-derived from scratch the first time an inference looks
|
||||
like it did nothing.
|
||||
|
||||
## What this list is not
|
||||
|
||||
It contains no assemblies, joints, drawings or multi-body work, and no CAM, simulation,
|
||||
|
||||
@@ -188,6 +188,40 @@ tolerances (2°, 0.5 mm). Inferred constraints reach saved documents, so
|
||||
inference falls under invariant #1; the UI's only role (Phase 5) is
|
||||
choosing whether to apply the proposals.
|
||||
|
||||
Extended (M3-1) to arcs and circles, as two more pure functions with the
|
||||
same contract: `infer_arc_constraints` and `infer_circle_constraints`, in
|
||||
fixed rule order — concentric (nearest earlier centre), endpoint
|
||||
coincidence (arcs only), tangent-to-line (side decided once, never
|
||||
re-derived), tangent-to-circle (external/internal decided once) — and
|
||||
looking only at STRICTLY EARLIER entities, which is what makes a rule
|
||||
stable when several curves are committed at once: an "all but self"
|
||||
reading has a hexagon's edge 0 propose `Parallel{0,3}` and edge 3 propose
|
||||
`Parallel{3,0}`, two different values naming one relation that no dedup by
|
||||
value can see. Endpoint coincidence is the exception and is not restricted
|
||||
that way, because a point id has no ordering relation to a curve id.
|
||||
Equal-radius is deliberately NOT proposed: `SketchConstraint` has no such
|
||||
kind, and the solver's `ArcRadiiEqual` is internal to `add_arc`. Ordering
|
||||
is by rule then ascending entity id, and is asserted under entity
|
||||
permutation, because inferred constraints reach saved documents
|
||||
(invariant #1).
|
||||
|
||||
The rules are a LIBRARY, not a policy: the app's commit path additionally
|
||||
refuses to propose what the sketch states verbatim, refuses to relate a
|
||||
primitive's curve to another curve of the same primitive, and drops any
|
||||
proposal whose trial solve makes the sketch `Redundant`.
|
||||
|
||||
**And the CLICK SNAP subsumes two of the rules.** `DRAW_SNAP_MM` is 2 mm
|
||||
and the inference distance tolerance is 0.5 mm, so a click near enough to
|
||||
infer `Coincident` or `Concentric` has already reused the existing point
|
||||
and the relation holds by IDENTITY — there is nothing left to constrain.
|
||||
Both rules stay reachable through a drag or a solve, and the hover glyph is
|
||||
unaffected; what changes is what a drawing gesture can be said to
|
||||
demonstrate. Two of M3 lane A's own tests were asserting those rules
|
||||
through a gesture that cannot exercise them, and were green on a constraint
|
||||
that made the sketch `Redundant`. Whether the two tolerances should be
|
||||
related at all is an open question, recorded in FUSION_LOG rather than
|
||||
answered here.
|
||||
|
||||
## 6. Performance budget
|
||||
|
||||
Gate: **< 5 ms** for a solve at ≥200 constraints, release build, on the
|
||||
|
||||
Reference in New Issue
Block a user