Commit Graph
105 Commits
Author SHA1 Message Date
ajandClaude Opus 5.5 f9b2713420 feat(common-line): cut each shared line once through Plan Cutting and the CI Fiber post
N26-295's PT42 pairs saved spacing in slice 1 but every shared edge was
still cut twice, costing a pass per edge and risking a freed part
tipping under the head on the second pass.

Plan Cutting now cuts a plate's common lines once unless the plate is set
to cut them twice. Each group is cut member by member, owner before
partner (a captured dependency that search and replay enforce, so a kept
order cutting the partner first is a constraint conflict): the member's
holes, then the shared cuts it owns as open CommonLine centerline cuts
entered through the notch on the span's axis, then its remainder pieces,
each ramped in from the kerf the shared cut opened. Capture marks the
shared spans as tabs on the owned clean copy, so replay's contour
accounting proves each perimeter is cut exactly once; a lead that fits
at neither end refuses as UnsupportedGeometry naming the span, never
shortened. Material still comes from the drawing, so utilization,
quantity and overlap results do not change. Members are never
support-tabbed; locked or excluded members and broken groups refuse.

The CI Fiber post writes shared cuts in the cut-off form with a lead-in
and no G41/G42, and remainders in the contour form on their perimeter's
compensation side, named by a remainder comment. Cincinnati CL (whose
PreApplied mode offsets nothing) and Gravograph refuse such nests, as do
the desktop and console for any post without ICommonLinePostProcessor;
nothing falls back to a silent double cut. Plate > Arrange > Cut Common
Lines Twice keeps slice 1's behavior, persists with the plate and makes
an open plan stale.

Pre-post review now checks each span is cut once, on its centerline, by
the member cut first, and the rapid check treats a finished member's
remainders as an obstacle. Compensation start in void and cancel in
kerf are unconfirmed on the CI FIBER 4020; release waits on a 3/16
stainless coupon trial.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 16:51:42 -05:00
ajandClaude Opus 5.5 6de23fb831 feat(tabs): replace "Tab every part" with tabbing parts by size
Nobody tabs every part, but tabbing by size is useful even on a plate
that has a support grid. Cutting Settings > Tabs now offers "Only tab
parts the support grid can't hold level" or "Tab parts by size"
(CuttingParameters.TabBySize), which ignores the bed and tabs each part
whose minimum-area bounding rectangle's narrow side is in the range.
The support grid choice still falls back to that range on plates with
no bed, as before.

The range fields become TabSizeMinWidth/TabSizeMaxWidth; their JSON
keys stay noBedTabMinWidth/noBedTabMaxWidth so saved settings and nests
read unchanged. TabsEnabled stays as the per-contour flag Plan Cutting,
Place Lead-in and drawing pins set on the parts they tab.

Saved user settings with "Tab every part" read as tabs by size from 0
to 9999, which tabs the same parts. Only the user's settings migrate;
a plate's recorded parameters and pins replay as planned.

Plan Cutting, Place Lead-in and the pre-post review all go through
SupportTabSettings, so they agree on which parts need a tab. A
size-tabbed part is held by any clear tab, so it is never a rapid
obstacle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 07:46:24 -05:00
ajandClaude Opus 5.5 6c4ebe49b3 fix(planning): cut the remnant cut-offs last
The last strip line stops at the remnant's full-length horizontal
separator, so it never counted as separating the sheet and the planner
cut it wherever the route passed it, often first (N26-264). That frees
the X-tail remnant early and loses the mass that absorbs heat while the
parts are cut.

A continuous line from a sheet edge or separator to another now counts
as a separator too (CutOff.Separators, found in rounds), so Plan Cutting
and Part Sequencing cut it after every part, just before the separator
it stops on. The problem-nest harness now adds scrap cut-offs with
KeepHorizontalRemnant, as both desktop entry points do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 12:50:33 -05:00
ajandClaude Opus 5.5 322a66c339 fix(planning): take back a pair swap that leaves the search stuck
The "cut those two the other way round" rule is a guess. On an interlocked
holed-parts plate it swapped a pair whose swapped order then blocked on that
same pair; no further rule could be learned, the full search ran the strict
budget out, and Plan Cutting fell back to the safest route (0 strict
expansions), failing ContourRecoveryFileTests' interlocked rows since
16bd9256.

When a round teaches nothing and a swap was learned, the newest swap is now
taken back, never re-learned, and the attempt that taught it learns the plain
"cut this part before those" rule instead, backing up from that attempt as
any learned rule does. The swap is chosen apart from the plain rules, so a
"departed part first" rule with the same pair is never taken for a swap.

Both interlocked rows plan Ready within budget again. The problem-nest corpus
keeps every status and expansion count; a 4000-layout random sweep of 3-5
locked-lead rectangles keeps every status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 08:39:52 -05:00
ajandClaude Opus 5.5 6ee81a3501 fix(cutting): keep rapids off cut parts no single tab can steady
A support-tabbed part that no single tab can hold level may tip once cut,
yet its tabbed outside was crossable like any retained part, so Plan
Cutting could rapid back across a row of long strips. Its outside is now a
rapid obstacle, closed across its tab gap, in the search, replay, cut-off
insertion and the safest route.

Its fallback entries are ranked toward the next cut rather than steadiest
first, so a long strip can be left toward the next part, and the "cut those
two the other way round" rule applies only when the approach crosses no
other part.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 22:07:28 -05:00
ajandClaude Opus 5.5 a0d6c7212b fix(cutting): raise the head for rapids into hole sub-programs
Round holes are cut as sub-programs, which are never marked because they
may be shared, so the safest-route fallback could not raise the head for
the rapid into a hole: on interlocked layouts every such crossing stayed
a finding and the plan stayed unverified. A HEAD RAISE marker may now sit
directly before a sub-program call, raising the call's arrival rapid.

- Motion reader: a marked call raises its first rapid; each sub-program
  motion records the part's own call that runs it.
- RaisedRapids marks the call when the crossing rapid is its arrival.
- Cincinnati CL keeps the marker with its hole call and writes M47 before
  it; part sub-program dedupe now tells marked programs apart.
- CI Fiber raises before the hole's first G0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 16:54:59 -05:00
ajandClaude Fable 5.1 84a0fedac0 fix(cutting): sweep a part's holes even after its searched entries run out
Contour recovery tries each outside entry's hole-tour search first for a
part with at most 16 holes, and the reading-order sweeps after them; once
the searched entries had spent the recovery allowance it jumped straight
to the widened tries and never swept. A frame cut from inside its own
cutout, after the strips nested there, is often routed only by a sweep,
which leaves the cutout on its far side toward the outside entry beyond
it, so such plates fell back to the safest route with head raises or to
no plan at all. The sweeps now still get their few expansions per hole,
bounded by the whole budget. On the production corpus six plates went
from a safest-route or head-raise fallback to a strict plan, five kept
fewer raises, one blocked plate gained a safest route, and none got
worse; the problem-nest corpus is unchanged in every outcome and share.
No synthetic plate reproduced the exhausted allowance yet, so the corpus
guards this change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-11-02 14:31:45 -05:00
ajandClaude Opus 5.5 b2cc796e4a fix(cutting): let a part no tab can steady leave from another entry
A support-tabbed part that no single tab can hold level was limited to its
one steadiest entry. Two strips stacked in a frame's cutout then blocked
the plate: from the upper strip's only entry, every route to the lower one
crossed holes already cut. Its other entries clear of inside corners now
follow the steadiest, in the search and in contour recovery; the part is
still tabbed and still warned about. Parts a tab can hold keep their
steadying entries.

The unverified headline also named fixed lead-ins when the only warning
was a part that may tip; it now says what needs review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 09:34:00 -05:00
aj 4e92d0e8f3 fix(planning): route a cut-off from its start to its far end
A cut-off always runs away from its fixed edge: the origin side, the only
edge guaranteed to be a real sheet edge. The part order is proposed as a
traveling-salesman path over one point per placement, and a cut-off's
point was the middle of its line. The route did not know the tool must
arrive at the line's start and leaves at its far end, so the parts
before a sheet-splitting line finished level with its middle, and the
rapid down to its start crossed parts already cut.

Each placement now has an entry and an exit point; they differ only for
cut-offs (start and departure). Nearest neighbor and Or-opt go on from
each part's exit, and 2-opt costs a reversed run along its own directed
legs; with no cut-off on the plate the exits are not passed and the
symmetric route is unchanged. The part cut before a cut-off faces its
start.

Cut-off direction is not chosen here: the order reads each cut-off's start
and end from its program as given, and the joint search may still reverse a
head-locked far-edge segment.
2026-11-01 16:51:09 -05:00
aj 277719a1d6 fix(planning): re-plan the last kept part when a learned rule changes what follows it
When a blocked approach teaches an order rule, the search backs up to the
earliest part that approach crossed, keeps the parts before it and
re-plans the rest. The last kept part was planned facing the part that
followed it in the old order. If the new order puts another part after
it, its entry and exit still face the old one, so the plan ends with a
stale exit that a kept-order re-plan of the same order would fix.

Now that part is planned again, in the same place, facing its new
successor; when its successor is unchanged nothing is re-planned.

The locked-among-regenerated fixture's plan changes: rapid 67.60 ->
60.22, expansions 528 -> 268 (digest updated). Learning "cut the
cutoff first" now takes 40 expansions rather than 22, because B is
planned again to face the cutoff; retrying every entry of B took 60.
2026-11-01 16:51:09 -05:00
ajandClaude Opus 5.5 e231e44f72 refactor(geometry): share box containment, union, rotation and cutout range checks
Private copies of tolerant box containment, box union, vector rotation and
the cutout proposals' coordinate-range check now use one helper each:
BoundingBox.IsWithin and BoundingBox.Union, Vector.Rotate, and
CutoutCoordinates.WithinRange. Tests pin the helpers bit-for-bit against
frozen copies of the removed bodies. No behavior change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 09:25:27 -05:00
ajandClaude Opus 5.5 4d55e11318 style: use one spelling across the codebase
The repo mixed variants such as center/centre and color/colour, so a
name could be spelled either way and searches missed half the hits.
Standardize on the US spelling, matching .NET's own APIs (Color, Center).

Wire values owned by other systems keep their spelling: the material
ledger's "Cancelled" hold status and GitHub's "cancelled" job status.

No behavior change beyond the spelling of a few status messages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 16:11:30 -04:00
ajandClaude Opus 5.5 4028dafb26 feat(cutoffs): trim a middle piece into a gap in the line
Trim refused the piece between two crossing cut-offs because a cut-off had
one start and one end, so a line could not be stopped short around a pocket
of parts without deleting it and drawing two. A cut-off now carries Gaps,
stretches between its limits left uncut: segment generation excludes them
like parts, so the line splits into segments that each take their own place
in the cut sequence. Trimming a middle piece adds a gap from one crossing
centre to the other (merged with any it touches), Extend near a gap's edge
closes it, and Swap Through-Cut refuses a junction a gap touches rather
than guess which side of the gap should run through.

Every reader of the limits treats a gap as uncut, so nothing waits for,
warns about or credits a cut that never happens: segment spans stop at a
gap, the cutting dependencies skip a part inside one, the clamp check
ignores a clamp inside one, the cutting-state and overlap stamps go stale
when gaps change, and a gapped line is never full span for the expected
remnant or automatic cut-offs. Gaps persist as an optional gaps array;
older versions ignore it and would cut straight through.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 12:59:46 -04:00
ajandClaude Opus 5.5 47f9593a41 fix(planning): pierce arc text where a fitting lead-in cannot route
A plate of tags with arc-outline digits found no plan, although each
cutout had a clear entry. Eroded pierces were offered only when no
configured lead fit, so a letter with one fitting lead on the wrong
side stayed stuck with it, and an uncertain lead check skipped erosion
altogether. Recovery also spent its allowance on the outside entries
and accepted the first it reached, leaving a part on a side the next
rapid had to cross it from.

Count uncertain leads as no fit. Give recovery a last, separately
funded try that adds eroded pierces for the outside entries ranked
ahead of the first reached, and hold back routes that end facing away
from the next cut until then. Drop a lead that touches only in the
whole emission, where rounding moves it, rather than rebuilding the
same chain. Plans reached from their best entry keep their entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 12:38:32 -04:00
ajandClaude Fable 5.1 07a9739774 perf(cutting): plan plates faster with bounded fallbacks and prefiltered checks
Plan Cutting spent most of its time on work that never changed the outcome:
many-holed parts paid quadratic shape-pair and ring-containment costs before
any search, every plate was captured twice, and failing plates burned their
whole budget in exhaustive fallback passes that never found a plan on 127
production plates.

- OverlapMaterial: skip native shape pairs whose bounds are clear by more
  than the query allowance; gate polygon touch and winding tests on vertex
  bounds.
- LeadMaterialSnapshot: gate ring enclosure tests on ring extents when
  finding the perimeter and rejecting nested cutouts.
- CuttingPlanBatch: capture each plate once; the kept-order retry derives
  from the same capture through CuttingPlanSnapshot.WithPreservedOrder.
- JointCuttingPlanSearch: end the kept-order full pass and the sequence-free
  recovery and full passes after FallbackStalls (2) stalls' worth of
  expansions when programs are regenerated; plates with only fixed programs
  keep the exhaustive search so a refusal stays genuine.

On 127 archive plates (lead-ins cleared, 35" scrap cut-offs) total time fell
from 164 s to 102 s with identical outcomes; the problem-nest corpus gives
the same status and expansion count on every plate.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-29 09:35:33 -04:00
ajandClaude Opus 5.5 c6b6678a2f feat(planning): raise the head over cut parts as the last resort
When no search finds a route that keeps every rapid off parts already
cut, Plan Cutting used to offer only an unverified safest route needing
explicit acceptance. Cincinnati's own software instead raises the head
for such a rapid. Now the safest-route fallback marks each planner-chosen
rapid that still crosses cut parts with a HEAD RAISE comment, and the
plan is Ready with every raise listed. The strict search never marks a
rapid, and the batch prefers fewer broken checks, then fewer raises,
then less travel, so a plate that can be cut head-down never gets one.

The reader flags marked rapids and the checker sets their crossings
apart, in replay and pre-post verification alike. The Cincinnati CL
post writes M47 before a marked rapid whatever the M47 mode (the
distance-based safety raise is unchanged); the CI Fiber post writes a
new Head raise block and refuses marked nests while it is blank, since
its raise code is unconfirmed. Rapids into locked programs, cut-offs
and hole sub-programs are never marked and keep their findings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 13:37:33 -04:00
ajandClaude Opus 5.5 16bd92567c fix(planning): swap the pair a blocked approach doubled back across
When a part could not be reached without crossing parts already cut, the
free search always learned "cut the blocked part before them". When the
crossed part was the one cut just before the part the tool left from, the
tool had gone on past it and come back: the cheap repair is to cut those
two the other way round. Without it, N26-23S learned a chain of wrong
rules (8 before 4 and 5, 3 before 1, ...) that excluded every valid order
and ran the full search out of budget, although swapping parts 5 and 6
gives a valid plan. It now plans ready in 786 expansions.

The problem-nest corpus keeps every outcome; three P260417-17 plates stay
Ready with more expansions (5341 -> 8937 the largest).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 12:14:10 -04:00
ajandClaude Opus 5.5 f4317bc52f fix(planning): learn to reach a sheet separator from beyond the parts in its way
A sheet separator is cut after everything, so when the approach to its
pierce crossed parts already cut, the usual "cut it before them" rule
contradicted that and the search learned nothing. It fell back to the
full search, which spent the budget or found a route that climbed the
column and jumped back down past the cut parts (N26-23M).

When every "cut the blocked part first" rule would contradict a required
order, learn the other way round: cut the part the approach left from
before the parts it crossed, so the tool arrives from beyond them. A
separator blocked this way now ends the attempt at once, like any
cutoff whose rule can be learned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 14:36:26 -04:00
ajandClaude Opus 5.5 0ede9443de fix(cutting): route a part's holes from the end of the segment cut before it
On P230323-02 plate 7 the frame part cut after a cut-off segment took its
upper small hole first, so the rapid up from the segment's end at the
bottom of the sheet crossed the rapid from the lower hole to the window.
The free search plans parts as if segments were absent, so the part's hole
route was ranked from where the tool was before the segment (the previous
part's end, top right), not from where it really is.

After CutOffInsertion places the segments, each holed part cut straight
after one now keeps its outside entry and order but takes the hole route
and preferred hole entries planned from the segment's end, when that
chain has an entry for every hole and passes the checks. The search's
look-through of segments keeps ranking outside entries from the
pre-segment point (so routes stay as planned without the lines) but plans
hole routes from the real position, so a kept-order replan of an applied
plan picks the same holes. Plates without cut-offs are unaffected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 13:42:29 -04:00
ajandClaude Opus 5.5 58b8467c39 fix(ui): keep Draw Support visible while inspecting a cutting plan
The support overlay was drawn inside the live-plate-only paint block, and
the Plan Cutting preview plate never copied the support bed, so opening
the cut planner hid the grid points and each part's support marks. The
overlay now follows the displayed plate, the preview carries the bed, and
tab-point clearance falls back to the live plate's tab size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 13:25:09 -04:00
ajandClaude Opus 5.5 69a83b3ad9 feat(support): let a tab alone hold short parts the bed can't
Small parts such as 1.5" test squares on a 2" laser grid rest on at most
one grid point, so no single support tab can bring their center of
gravity inside the contacts and Plan Cutting warned "no single tab can
steady it" on every one. In practice a part that short stays in the
sheet on its tab, so the bed's contacts don't matter.

Cutting Settings > Tabs gets "Tab alone holds parts up to N long"
(CuttingParameters.TabHeldMaxLength, 0 = off, the default). On a plate
with a bed, a part the bed can't hold level whose length (long side of
its minimum-area bounding rectangle) is within the limit is still
tabbed, but any tab clear of inside corners steadies it, so Plan
Cutting, hand-placed lead-ins and the pre-post review warn only when it
has no tab at all. The setting persists with the cutting parameters and
is part of the plan state fingerprint.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 13:20:03 -04:00
ajandClaude Opus 5.5 6a9b81326e feat(planning): cut text-like cutouts in reading order
Serial-number tags with 27 stencil-text cutouts never planned: contour
recovery stopped at 16 holes, a lone part never got recovery, and the
remaining search kept leaving letters on the wrong side so rapids ran
back across letters already cut. Recovery now handles up to 30 holes,
runs for lone holed parts, and first sweeps the holes in reading order:
by their far side along the way they spread, each left from its far side
(stencil pieces face the next piece), ending at an outside entry beyond
every hole, with a few expansions per hole. Parts within the old 16-hole
reach keep the search first, so their plans are unchanged.

The eroded pierce now steps down through shallower levels so each entry
gets a pierce on its own stroke's centre line, and leads to the entry the
planner aimed at (falling back to the nearest wall), which the sweep needs
to leave a letter from the right place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 11:36:54 -04:00
ajandClaude Opus 5.5 37cdc52f0d feat(cutting): pierce cutouts too small for their lead-in by erosion
Small text and narrow slots often have no entry where the configured
lead-in fits, so Plan Cutting refused them. When every entry of a cutout
fails, the planner now erodes the cutout inward (to the pierce clearance,
or nine tenths of its inscribed radius when smaller), pierces at the
eroded point nearest each ranked entry and leads straight to the closest
wall, with no lead-out. Letter strokes pierce on their centre lines; a
tapering feature pierces at its widest spot. The lead validator still
checks every candidate, and cutouts whose lead fits are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 10:36:03 -04:00
ajandClaude Opus 5.5 479883e7ac feat(cutting): tab parts by width when the plate has no support bed
With support tabs on and no support bed, nothing was tabbed and nothing
said so. A new no-bed width range (NoBedTabMinWidth..NoBedTabMaxWidth,
the short side of the part's minimum-area bounding rectangle) now picks
the parts to tab instead. SupportTabSettings.Analyze makes the choice
for Plan Cutting, hand-placed lead-ins and the pre-post review; without
a bed any tab clear of inside corners counts. With no bed and no range,
the plan notes that nothing was tabbed. Cutting Settings > Tabs gains
the range fields, and the values persist with the cutting parameters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 22:02:31 -04:00
ajandClaude Opus 5.5 993555dba6 feat(cutoffs): head-locked overcut at the far edge, reversible by Plan Cutting
Stock can arrive up to 1.5 in wider than nominal, so only the origin-side
edge is certain. A cut-off with a head-locked overcut cuts past the nominal
far edge with the head height locked, covering the oversize. With that lock,
Plan Cutting may start the far-edge segment at the far edge: overcut outward,
rapid back still locked, unlock, cut toward the origin. Without it the
direction stays fixed, as decided in Project Memory a20ea455.

- CutOff.HeadLockOvercut / FarEdgeFirst, persisted in .nest; HEAD HEIGHT
  LOCK/UNLOCK comment markers; far edge is quadrant-aware.
- Planner offers the reversed far-edge segment in the joint search, the
  safest route and segment insertion; Apply records the direction.
- Cincinnati CL and CI Fiber posts gain lock/unlock code settings and refuse
  head-locked cut-offs while either is empty.
- Automatic cut-off dialog setting (off by default, 1.5 in), kept between
  sessions and used for new cut-offs.

Lock codes and machine behaviour with the head locked are unconfirmed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 09:51:59 -04:00
ajandClaude Opus 5.5 7ce5e73a82 refactor: share duplicated paging, HTTP and helper code
Roslyn duplicate scans found the same code copied across layers:
- Data: the three browse sessions share BrowseSession<TPage, TSort>;
  the remote clients share NestServerHttp (JSON options, If-Match,
  error text).
- WinForms: five paged lists share BrowsePager for loading text,
  navigation, sort glyphs and failure messages. The Add Drawings to
  Release, Drawing Library and set browser dialogs now dispose their
  browse sessions.
- Server: NestQueryRequest reuses DrawingLibraryRequest's helpers;
  revision history queries share count and paging binds.
- Engine: RemnantPlateNester delegates to DefaultPlateNester;
  CuttingPlanService reuses JointCuttingPlanSearch.Map.
- Core: LineArc and CleanHole lead-ins share LineArcApproach with
  unchanged arithmetic order, so output is bit-identical.
- IO: Dxf.GetGeometry overloads share one reader; .nest JSON test
  helpers move to NestArchiveJson.

Also fixes the production compiler warnings (CS8632, CS8603, CS0108)
and moves a test off an obsolete forwarding API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 08:45:36 -04:00
aj 0785bb84c9 fix(planning): learn a door's hole order when a hop crosses its own cut holes
Rapids may not cross holes already cut. On an instrument panel, mounting
holes either side of a cutout become unreachable from each other once
the cutout is cut, so the holes must come first. The contour-by-contour
search backtracks chronologically through every entry combination of
the last holes before it changes their order, and ran out of budget.
Supplied-blank doors fell to an unverified safest route.

Three changes:
- Contour recovery, the part solver that memoizes failed states, now
  runs for display-perimeter parts too: their holes are the whole part,
  with no outside cut to finish on.
- A door alone on its sheet gets the recovery pass first. Any other
  lone part keeps the plain search, whose routes are shorter.
- Recovery learns, as whole-part ordering does: a hop onto a hole that
  crosses holes of the chain teaches "cut it before them" (skipping any
  rule that closes a cycle) and restarts the chain, with holes still
  waiting for a prerequisite ranked last. Rules only order candidates;
  no hole is skipped. Until a rule is learned the chain is unchanged.
2026-10-23 07:43:39 -04:00
ajandClaude Opus 5.5 07e7d7edcd perf(planning): plan parts with thousands of holes in seconds
A part with about 1,700 holes (P241017-01) never planned: material
capture paired every boundary with every other one and lead checks
scanned every boundary per lead, so both hit the 1M native query limit
and the plate fell back to an unverified best-effort plan.

- Material capture sweeps boundary extents along X and queries only
  pairs the lead checks' per-pair clearance cannot skip, in the full
  scan's order.
- Material with 64+ boundaries keeps a grid of boundary extents. Lead
  checks, contour-joint matching and replay's contour accounting query
  only nearby boundaries; ray parity reads only holes on the point's row.
- Only native queries that run are charged to the budget; skipped far
  material no longer costs its full boundary count.
- The search looks up chosen holes and route ranks instead of scanning.

With that the plate plans Ready, but in 189 s: every step re-emitted
and re-checked all holes already cut. On parts with 64+ contours a
middle hole step now checks only the contour it adds, continuing the
completed-contour state its prefix left (ReleasedContourState.Continue).
It falls back to the full prefix whenever it cannot continue exactly,
and the last contour still checks the whole part from before it.
Isolated contour emission clones only the chosen contour.

P241017-01 now plans Ready in 5.4 s with an identical route, expansions
and rapid travel. Core and engine suites pass; the problem-nest corpus
matches the unchanged commit's outcomes and expansions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 06:01:43 -04:00
aj 73e54fbd67 fix(planning): refuse misplaced display perimeters by name
Review found three blanks that slipped past or failed silently. Enclosure
was checked against the outline's bounding box, so a cutout in the notch of
an L-shaped blank reached an unverified plan that warning acceptance could
apply; every cut point is now tested inside the outline itself, and the
material capture names the display perimeter when no ring encloses the
rest. A blank whose only cutouts are tabbed left the search with nothing
to choose and ended without a finding; it is now refused with its reason,
as is a blank with nothing to cut, which used to get only the generic
noncutting message. None of these offers even an unverified plan.

Clean-bounds containment, seam overcut trimming and incremental closure
drift now treat the display perimeter like the other material boundaries.
2026-10-22 19:56:14 -04:00
aj 6e3705eb89 feat(planning): cut holes inside a display perimeter that is never cut
Some jobs cut only cutouts into a supplied blank, such as instrument holes
in a purchased door that is the whole sheet. Its outline has to be known
to the planner (the blank is material that leads, rapids and cut-offs must
respect) but must never be pierced, led or cut.

A new DisplayPerimeter layer marks that outline. It is material, so
nesting, containment, lead clearance and automatic cut-offs all see the
blank; a door that fills its sheet leaves cut-offs nothing to cut. Cutting
preparation keeps it out of the contours entirely: with no cut perimeter
every contour is a hole with internal leads, and the search, best-effort
and safest-route paths stop offering a perimeter. Replay refuses any run
along the display perimeter and completes once every other ring is cut.

A display perimeter must be one whole closed contour enclosing every other
contour; a mixed ring, one inside another contour, or a second one is
refused with that reason. Saving, drawing and posting it are still to do.
2026-10-22 19:32:22 -04:00
ajandClaude Fable 5.1 8f27eac2ca feat(cutting): plan each scrap cut-off segment where the route passes it
Plates with staged automatic scrap cut-offs could not be planned: P260810-01
plate 1 ran out of budget even at 10x effort, while the same plate plans
Ready in 3.6k expansions without the lines. A cut-off was one fixed program
cut whole before every part its line passes through, which dragged the tour
to the middle of the sheet and left the head at the far edge of the line;
and cutting every line first (the rejected alternative) weakens the sheet
and breaks the containment operators rely on when they fast-forward a
changed program.

A cut-off stays one definition, but Plate.RegenerateCutOffs now makes one
part per trimmed segment, each with its own place in the cut sequence.
CutOffSegments gives each segment the span of the nominal line it stands
for (end of the segment before it to start of the one after), and the
dependency rules of the planner and Part Sequencing use that span, so a
segment precedes only the parts beside it. The free-order search plans the
parts as if the segments were not there, so adding lines no longer changes
a plate's route, then CutOffInsertion slides each segment into the latest
gap before its first part where the rapid into its pierce and the rapid
from its end cross nothing cut before; only when one fits nowhere is the
plate searched with the segments among the parts. The search looks through
segments wherever they sit (entries face the next part, hole routes rank
from the pre-segment position, rapids are still checked from the segment's
end), so an applied plan replanned with the order kept replays Ready.
Segments saved out of consecutive order are recorded per segment in the
.nest file (`segments`); older readers load them consecutively.

P260810-01 plate 1 now plans Ready in 3639 expansions with every check
passing; rapid travel 1836 against 1547 without the lines. Plates without
cut-offs keep their PlanningCharacterizationTests digests, and the
problem-nest corpus has no plate below its baseline.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-22 11:38:38 -04:00
ajandClaude Opus 5.5 ff46de69df feat(planning): offer the safest route when the strict search runs out
Cut planning should rank routes safest first, then fastest, but a plate whose
strict search hit its expansion budget was simply refused ("no plan found
within the search limit"), even when a route with a few reviewable rapid
crossings existed. Scrap cut-offs make this common: their trimmed segments
can wall off a column of parts, and rapids are straight.

When both the free-order and current-order searches stop at the limit, the
batch now walks a greedy safest route from each input, replays it with fresh
checks, and keeps the one with fewer violations (material first, then rapid
crossings, then the rest), then less rapid travel. A route that passes every
check is an ordinary Ready plan; otherwise it is an unverified BestEffort
that lists every violation and applies only with explicit acceptance. Routes
with any motion into material are never offered, so the strict refusal and
its lead-in advice stand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 11:37:17 -04:00
ajandClaude Opus 5.5 8c7dc41ce8 feat(planning): warn about tipping parts and retire legacy lead-in assignment
Plan Cutting is now the only automatic lead-in assignment, and parts the
support grid cannot hold level are reported wherever they lack a
steadying tab.

- Remove Assign Lead-ins (plate and nest), LeadInAssigner, the lead-in
  tool's Auto-Assign button and the Auto Tab size range; old settings
  with autoTab sizes still load
- Manual Place Lead-in tabs the clicked entry when support tabs are on
  and the grid cannot hold the part (SupportTabSettings)
- New PartSupport finding: Plan Cutting replay and best-effort plans
  warn when a drawing pin, a lead-in that does not fit or no single tab
  leaves a part unsteady; the pre-post review checks each placed
  program's outside tab gap. These warnings replace the advisory
  weak-tab notes; only the inside-corner tab note stays advisory, and
  never for a pin
- Pinned perimeters keep their pin but carry the support analysis
- Draw grid points as pixel-snapped squares without anti-aliasing
- Post fixtures build lead-ins through a test-only TestLeadIns helper
- Docs: support tabs, pre-post verification and planner notes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 23:54:40 -04:00
ajandClaude Opus 5.5 f51e5aefdd feat(planning): keep support tabs out of inside corners and report weak tabs
The best tab point used to land in inside corners: equally good points
run along a straight edge, vertices were tried first and the first tie
won. Operators cannot grind a nub flush there.

- SupportAnalyzer finds inside corners (inward-turning vertex runs of at
  least 30 degrees, so chorded fillets count) and keeps tab points a
  clearance from them; of equally good points it picks the one farthest
  from an inside corner. Plan Cutting and the overlay use twice the tab
  size; AcceptsTabAt rejects closer points
- When no steadying entry has a lead-in that fits, the search falls back
  to entries clear of inside corners, then to every entry, each ordered
  by how well the tab steadies the part, keeping only the steadiest that
  fit
- Replay notes parts whose planned tab cannot hold them level or sits in
  an inside corner; the notes are advisory and leave a Ready plan Ready
- Console/MCP plate summaries print a ready plan's notes
- docs/support-tabs.md and cutting-planner notes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 18:18:16 -04:00
ajandClaude Opus 5.5 a7c0747e11 feat(planning): tab parts the laser support grid cannot hold level
Model the machine's support bed as a grid of contact points measured
from the plate origin, and check each part's center of gravity against
the convex hull of the grid points under its material. The bed is
extensible so straight and CAD-imported curved slats can follow.

- Core: SupportBed/SupportGrid, SupportMaterial and SupportAnalyzer
  (margin with registration tolerance, best single tab point)
- Nest-wide support bed that every plate follows, saved in
  plateDefaults.supportBed; machine defaults in support-grid.json
- CuttingParameters.SupportTabs: Plan Cutting tabs only unsupported
  parts and limits their perimeter entries to points where the tab
  steadies the part, falling back to any fitting entry
- Desktop: Nest > Support Grid..., View > Draw Support overlay and a
  "Tab parts the support grid cannot hold level" tab option
- docs/support-tabs.md, nest file format and planner notes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 16:55:24 -04:00
aj 3d4ac5ddf7 fix(planning): drop the desktop-only effort advice from console and MCP findings
CuttingPlanProposal.Describe is shown only by the console and MCP, which have
no Tools > Options; the desktop panel keeps its own effort hint.
2026-10-20 05:26:35 -04:00
ajandClaude Opus 5.5 56eaf4829a feat(planning): add a Cut planning effort setting that scales the search budget
Tools > Options > Cut planning effort (default 1.0, 0.5-10) multiplies the
desktop cut planner's per-plate expansion budget for both the free-order
search and the current-order retry. The budget counts expansions, not time,
so the setting is how faster hardware can be spent on hard plates.

The panel reads the setting on the UI thread and passes it to
CuttingPlanBatch.Capture; the worker never reads settings. The 1,000-
expansion first pass stays fixed: it is a cheap probe for easy plates, so a
higher effort only adds work where the full search runs. A plate refused
at the search limit now says the effort can be raised, without promising a
plan. The default keeps today's budgets and characterization digests.

Console, MCP and API do not run the cut planner, so they get no option.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:54:28 -04:00
ajandClaude Opus 5.5 391a27b2f9 feat(console,mcp): add cut planning to the headless front ends
Console --plan-cutting and MCP plan_cutting/apply_cutting_plan run the
desktop's CuttingPlanBatch: capture, plan, then an all-or-nothing apply.
Settings come from an explicit JSON file or the plates' identical saved
settings, never defaults. Unverified plans need per-call acceptance,
which is not posting consent. Console --no-fill plans a loaded nest as
is; a blocked plan exits 2 and saves nothing. Scrap cut-offs stay
desktop-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:54:28 -04:00
ajandClaude Opus 5.5 cf32d1cab5 fix(cutting): scale the reorder stall with the blocked part, not the plate's largest
An attempt along a part order stopped backtracking after 8 x entries x
contours expansions without progress, with contours taken as the most of
any part on the plate. One many-holed part therefore let every blocked
part, even a two-contour tab, replay its predecessors' entries for the
whole of that allowance; a plate whose rounds each stalled that long
ran out of budget before the recovery pass that would have finished it.

Along an order the stall now uses the larger contour count of the blocked
part and of the part cut just before it, whose departure a retry changes,
capped by the old limit. The sequence-free recovery pass keeps the plate
maximum. Planning characterization digests are unchanged.

The optional private-fixture test now also runs RecoveryCuttingNestPath
with default lead-ins, and requires that file's plates to plan within
60% of their budget.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:54:28 -04:00
ajandClaude Opus 5.5 04a6e0eb50 fix(engine): let contour recovery plan scribed and boxed-in holed parts
The cut planner's directed-contour recovery pass gave up on plates the
full search could solve, so they ended "no plan found within the search
limit":

- Each hole was checked as an isolated probe that repeats the part's
  scribes, so every hole-to-hole hop was checked as a detour through
  the scribe start. Scribes and other open cuts are now checked once
  from the arrival, and each hole as a direct hop from the one before.
- Hole entries were ranked only by pierce distance, so the departure
  often ran back across the hole just cut. The nearest hole is still
  tried first, but its entries that leave toward the holes still to
  cut come first.
- The first-ranked outside entry could spend the whole recovery
  allowance. Each outside entry now gets a share of what is left.

The optional private-fixture test now takes its config key, adding
RecoveryCuttingNestPath; it fails on the old search and passes now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:54:27 -04:00
ajandClaude Opus 5.5 a0713289fa feat(planning): tour large aligned grids as a serpentine
A plate of at least 200 parts with no cutoffs or prerequisites, whose
part centres bin into rows and columns within a quarter of the smallest
part extent, is toured line by line in alternating directions. Each row
and column gap must be wider than that tolerance, each cell may hold
only one part, and at least a quarter of the cells must be filled
(interleaved rows fill half). The route runs along whichever axis, from
whichever corner, is shortest from the start point.

This replaces the travelling-salesman 2-opt/Or-opt passes, which took
about 8 s on 5,742 parts. It is still only a proposal: the joint search
checks every rapid and lead, and replans after a learned rule use the
general order. Smaller plates, and the characterization fixtures, keep
their order unchanged.

The washer nest's plate 1 now plans Ready in about 44 s (was 54 s), with
86k expansions against 91k.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:16:03 -04:00
ajandClaude Opus 5.5 40e4e559dd fix(planning): rank hole entries by a clear way out to the next pierce
With no lead-out the tool leaves a hole where it entered it. A tiny corner
arc's midpoint lies on both facing sides of its hole, so the ranker scored it
as an ideal two-side corner, but the tool leaves it along its 45-degree
tangent: a shallow rapid to a nearby next hole re-entered the corner and
crossed the hole just cut. Every outside endpoint's preferred hole chain
then failed the same way, and the reorder search spent its budget on full
backtracking. A 31-part plate of such parts needed 31,959 expansions
against a default budget of 20,000.

Hole entries whose straight rapid to the next pierce clears the hole itself
now rank first, in the preferred chain and in the full search. This is a
stable reorder only: no entry is dropped, and every emitted rapid is still
checked. That plate now plans Ready on its first preferred pass, using 7,781
expansions; the budget is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:16:03 -04:00
ajandClaude Opus 5.5 b9c5240a43 fix(planning): close incremental rounding drift at contour seams
PEP-converted incremental programs round every move, so a long contour
can end 1-1.4e-6 off its start. Material capture refused it as open
("blocked: unsupported geometry"), and a gap right at the 1e-6 boundary
could pass material capture yet fail preparation.

On the planner's owned clean copy only, close incremental contours whose
gap exceeds 1e-8 but stays within what their rounded moves could
accumulate (capped at Tolerance.Epsilon); the next motion absorbs the
correction so nothing later moves. Absolute programs, larger gaps and
the drawing itself are untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:16:02 -04:00
aj 1ed66bbf20 fix(ui): point operator messages at commands that exist
Pinned-lead and locked-lead warnings named a Drawing Pins Off command and a
Clear Lead-ins command that the desktop does not have; name Plate > Remove
Lead-ins and spacing instead. Closing Plan Cutting no longer claims nothing
changed after lead-ins or cut-offs were cleared, the no-stock reason no
longer says the part is larger than every sheet when only the usable area at
the checked rotations is too small, and the console says whole-job engines.
2026-10-19 12:15:40 -04:00
ajandClaude Opus 5.5 a1458a355b fix(cutting): route best-effort holes instead of cutting them in source order
The best-effort fallback (used whenever a part has touching or uncertain
material boundaries, which sends the whole plate there) cut each part's holes
in raw source order with the nearest entry. On hole grids that order
doubles back, so the rapids between holes cross; any crossing means a
shorter uncrossed order exists. On A0228-01 plate 1 this cost ~300 in of
rapid travel and drew crossing rapids on PT08 in the simulator.

Tour the holes with CuttingHoleOrder (the nearest-neighbour + 2-opt/Or-opt
proposal the strict search already uses), as an open path from the arrival,
perimeter still last. Hole-centre selection is shared with the strict search.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:08:51 -04:00
ajandClaude Opus 5.5 baa5f8481a fix(cutting): plan cut-first parts before every other part
Classic sequencing honored Drawing.CutFirst, but the cutting planner built
its own order from the dependency graph and ignored it, so test coupons
interleaved with the rest of the plate. Each cut-first part is now a
prerequisite of every non-cutoff part, except a part nested in its cutout,
where containment wins so the graph stays acyclic. A kept order that cuts
a part before a coupon reports the cut-first conflict.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 08:45:47 -04:00
ajandClaude Opus 5.5 93cf8007bc feat(cutting): pierce perimeters in open scrap when no lead-in keeps the pierce zone
With a pierce diameter set, a perimeter none of whose configured lead-ins keeps its pierce
clear (a lead shorter than the zone radius, or neighbours closer than it) was only rejected.
Plan Cutting now looks for a pierce in the open scrap around the part instead.

- ScrapPierceSearch (Engine): the window four zone radii around the part, minus every nearby
  part's clean material grown by the zone radius and a margin (ClipperBridge, conservative
  flattening); the clear point nearest each ranked perimeter entry is a candidate. Other
  parts' cutouts count as scrap, the part's own holes do not. With no clear scrap, the
  PolyLabel pole of the free scrap is the best effort, and its shortfall is reported.
- ContourChoice.Pierce / PreparedContours.ScrapPierceEntry: the planner's choice carries the
  pierce; the emitter cuts a straight lead from it to the nearest perimeter point and still
  reads nothing but the contour and the choice.
- Every candidate passes the lead validator like any planner-chosen entry; pinned perimeters
  keep their pins and warn. Without a pierce diameter nothing changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:56:27 -04:00
ajandClaude Opus 5.5 6676f9f6f1 feat(cutting): keep lead-in pierces clear of material with an opt-in pierce diameter
Thick plate pierces leave a crater wider than the kerf. CuttingParameters.PierceDiameter
(Cutting Settings > Pierce Diameter, 0 = off) requires every lead-in pierce to keep half
of it from all part material: its own contour, its holes and every other part.

- LeadPathValidator checks the zone during Plan Cutting candidate checks and final
  replay; fixed emissions warn as usual. No-fit findings explain the zone.
- PierceZoneReview reports Pierce zone warnings before posting for leads from any source.
- Holes whose configured pierce is inside the zone move it toward the hole's PolyLabel
  pole (round holes: the centre), as close to the contour as the zone allows; a hole
  too small for the zone is pierced at its pole and the shortfall is still reported.
- Straight corner leads and round-hole clamping use the larger of PierceClearance and
  the zone radius. The manual lead-in preview shares the Core rules.
- Persisted through the DTO, owned copies and state fingerprint.

Perimeter fallback is not included; see docs/geometry/pierce-zone.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:56:27 -04:00
ajandClaude Opus 5.5 13ab8e02f8 fix(cutting): plan with staged scrap cut-offs within budget
Staged cut-offs were appended after every part, so a kept order (the
"Keep the current part order" option, or the fallback after a free
search runs out of budget) always conflicted with any cut-off crossing
a part. PlateSequencing.PlaceCutOffs moves each new cut-off to just
before the first part it crosses, separators last, without moving
anything else; the panel applies it after staging.

The free search also learned "cut the cut-off first" only after a full
stall, re-planning the many-holed parts before it. A cut-off is a fixed
program that never gets harder to cut earlier, so a crossing approach
into a non-separating cut-off now teaches that rule at once. On the
reported 35-part plate this drops the plan from 23,930 expansions (over
the 20,000 budget) to 15,605.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 22:14:28 -04:00
ajandClaude Opus 5.5 fb505ef0ff fix(cutting): plan outlines with a seam gap before an arc, and memoize lead checks
A converted outline whose seam closes within the admitted 1e-6 gap could
only be entered at its seam: entered anywhere else, the arc after the
seam started off its own circle and every emission was refused as an
inconsistent radius. The search then spent its whole budget on that
part and the plate never planned. Emission now bridges the gap with a
straight move and cuts the arc as drawn; the verifier already admits
that slack. An entry on the seam vertex is left as before.

Each prefix of a part re-checked its earlier contours' leads against
every other part's material. One search now remembers each verdict by
the lead curve's exact bits and the material's reference, charging the
same native query budget; replay never uses it. On the reported plate
the memo alone gives a byte-identical result in 57 s instead of 12 min 47 s;
with the seam fix the plate plans Ready in about 17 s.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 21:21:20 -04:00