Commit Graph
1815 Commits
Author SHA1 Message Date
aj 1b323e2380 docs(posts): describe CI Fiber M50 as Table In, the pallet swap
The pallet-change setting and post doc said M50 moves the cut sheet out,
borrowed from the CL-series manual. Cincinnati's CNC Codes Handbook calls
M50 "Table In" and M51 "Table Out". On the CI Fiber shuttle, Table In brings
the waiting pallet into the laser, which sends the cut one out, so M50 is
still the swap. Say that, note that it expects the waiting pallet to be
loaded, and note that newer Cincinnati samples end without a pallet code.
Default (M50) and posted output are unchanged.
2026-10-20 10:04:59 -04:00
aj 2d74d09023 chore(posts): stop naming the CI Fiber customer sample part
The Cincinnati sample used by the CI Fiber tests is a customer production
part. Its geometry and NC were never tracked, but comments named its part
number and fixture file names and quoted its date and a pierce coordinate.
Replace them with generic wording and placeholder values; the fixture stays
outside the repository, configured only in the gitignored test-config.json.
Comment-only change.
2026-10-20 08:01:18 -04:00
aj cc2b3d1b81 test(posts): post the CI Fiber sample's own lead-ins and match it line for line
The sample regression fixture now carries each part's pierce, lead-in and
cut moves from the Cincinnati machine program as its saved cutting program.
A new test posts those saved programs without reassigning lead-ins and
requires the program body to equal the sample exactly: L2/L4 macro, G41/G42
side, lead-ins and every cut move (21,911 lines).

Mutation checks: dropping the largest-contour perimeter rule from the kerf
fix fails it at the first perimeter (L4 posted as L2), and forcing G41 fails
it at the first perimeter's G42. The existing tests still replace the saved
programs with OpenNest's own lead-ins first; their comment now says so
instead of describing the sample's leads wrongly.
2026-10-20 07:36:01 -04:00
ajandClaude Opus 5.5 63233db108 fix(posts): put the CI Fiber kerf on the scrap side for either winding
The CI Fiber post selected G42 for every perimeter. Cincinnati's CNC Codes
Handbook defines G42 as "product remains on the left", and imported
perimeters run clockwise with the part on the right, so the controller
offset every outside edge into the part: parts came out a kerf undersize.
Cincinnati's LaserNST samples only use G42 because they cut perimeters
counter-clockwise.

Winding is normalized only at DXF import, so the post can't assume a
direction either. It now takes the largest contour as the perimeter (as
ShapeProfile does) and picks G41 or G42 from each contour's actual winding.
That also stops a reversed drawing from swapping the L2/L4 lead-in macros.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:08:11 -04:00
ajandClaude Opus 5.5 abfc1a714a feat(posts): trigger the Cincinnati safety head raise by rapid length
The safety raise (M47 P<SafetyHeadraiseDistance>) used to fire only when
the next part had a different drawing name, which has nothing to do with
crash risk: a long rapid between copies of the same part got a plain M47,
while a short hop between neighbouring different drawings got the full
raise. Sheets are rarely flat (5/8" plate can be ~1.5" out of flat within
supplier tolerance), and longer rapids cross more of that bow.

Add SafetyHeadraiseRapidDistance (program units, default 12"): any rapid to
the next pierce longer than it takes the safety raise, regardless of
drawing. Unknown travel never does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 07:08:10 -04:00
aj efa4844049 test(benchmark): prove parallelism reach with a rendezvous, not overlapping sleeps
Run_NeverExceedsMaxParallelism_ButReachesIt asserted two 200 ms solves
overlapped, which depends on the thread pool adding a second worker in
time; hosted Windows release run 39400265218 saw only one. Each fake solve
now waits (up to 10 s) until two solves have entered, so a parallel runner
always reaches the limit and a serial one fails once after the timeout.
Forcing MaxDegreeOfParallelism = 1 fails it (Expected 2, Actual 1).

Project Memory b534b51c.
2026-10-20 06:02:16 -04:00
aj bf240ab6df docs(console): describe --plan-cutting with --no-fill and unverified acceptance v0.5.0 2026-10-20 05:26:35 -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
aj 1ab39c3cd0 docs: correct cut planning effort scope and problem-nest storage steps
Console --plan-cutting and MCP plan_cutting run the planner at the default
effort; only the desktop exposes the setting. Adding a corpus nest must keep
the corpus server selected until the save, and the command is Nest > Edit.
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 a10e204268 fix(ui): lock plate edits while a fill is still running
Stopping a fill only requests cancellation; its worker keeps reading
Plate.Parts until it returns. The progress window is modeless, so a
click or key on the plate view in that window (clone placement, Delete,
arrow nudges, drops) changed the part list mid-enumeration and threw
"Collection was modified" in PlateFillService.TryAddClear.

PlateView now refuses editing input while IsFillInProgress, the same
way it does during an inspection. Panning and zooming stay live.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:54:28 -04:00
ajandClaude Opus 5.5 67daeafc98 test(planning): add opt-in problem-nest regression corpus check
Plans every nest on a dedicated OpenNest server (OPENNEST_PROBLEM_NESTS_SERVER)
plate by plate, with a per-plate time limit, and fails when a plate ranks
below the "planning: 1=... 2=..." baseline in the nest's comments. Customer
nests and baselines stay on the server, never in the repository. Refuses a
server holding more than 200 nests, so a production archive is not planned
by mistake.

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 94898225e8 perf(planning): skip lead checks against material no native query can reach
A lead check scanned every other part's material with native contact
queries. On the 5,742-washer plate that was about 80% of planning and
it never finished inside 120 s.

The earlier extent filter (reverted in ea1270e1) used a fixed 0.001 gap,
which native line/circle rounding can exceed for long leads beside small
circles. This skip adds 1e-6 times the span of both extents. The
discriminant's rounding is bounded by about 1e-7 times that span, and
about 2e-9 is seen. So a skipped material has no native contact, and the
900000-long lead beside a small circle is still checked. Each skipped
scan is charged to the native query budget as if it ran. Ray parity is
still asked natively unless the lead's midpoint is outside the
material's Y range. The pierce zone skips only material farther than its
radius by the same gap.

A randomized test checks that skipped material never has a native
contact. It fails with the span allowance at zero and passes with it as
low as 1e-8. Plate 1 of the washer nest now plans Ready in about 54 s.

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
ajandClaude Opus 5.5 13d75854c3 fix(console): give the DXF-only plate a quantity of 1
LoadOrCreateNest built the DXF-only plate with `new Plate`, leaving
Quantity at 0, so results reported "Parts placed: 0" and 0% weighted
utilization, and drawings' nested quantities stayed at zero. Build it
through Nest.CreatePlate as the desktop does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 18:48:51 -04:00
aj 61ad85768d test(api): drop property-echo tests and pin AllowRotation behaviourally
Remove three tests that only read back values they had just set. Fold the
quantity-weighted utilization check into the mixed-sheet test, and replace
the locked-rotation constraint read-back with a run where a bar fits only
rotated: placed when rotation is allowed, unplaced when it is not.
2026-10-19 13:15:37 -04:00
aj 274651b810 feat(desktop): add Nest > Clear Nest
Clear Nest removes every plate after the first and empties the remaining
plate (parts, cut-offs, repeat quantity), keeping nest metadata and the
first plate's configuration. It asks first, defaulting to No, and refuses
while nesting, a fill, a busy plate action or a database save is running.
The menu item is enabled only when there is something to clear.
2026-10-19 13:12:25 -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
aj b9092a5142 fix(scripts): point Deploy-OpenNest at Tools > Options 2026-10-19 12:11:13 -04:00
aj 98a046a112 docs: correct user-facing docs for the next release
Remove a private part reference from the lead-in notes, fix the Options and
New menu paths, say that release ZIPs never auto-update, describe current
Cincinnati CL ordering, clamp validation coverage and empty-plate saving,
list every built-in engine, and drop internal decision labels.
2026-10-19 12:11:13 -04:00
aj b97f67af41 ci(release): smoke-check the Circles and FlatBar engines in the package 2026-10-19 12:07:46 -04:00
ajandClaude Opus 5.5 5620c9b842 fix(ui): validate Nest Info and Edit Plate on the UI thread
Both dialogs revalidated with a System.Timers.Timer whose SynchronizingObject
was the form. Before the dialog has a handle, InvokeRequired is false, so the
Elapsed handler ran EnableCheck on a pool thread. When the UI thread was busy
(for example with the cut simulator open), the timer fired before ShowDialog
and touched applyButton while the UI thread was creating it, throwing a
cross-thread InvalidOperationException. Use a WinForms timer, which always
ticks on the UI thread, and stop starting it from the constructor, which
already calls EnableCheck directly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 12:05:14 -04:00
ajandClaude Opus 5.5 be8d1443e3 feat(ui): replace status bar plate labels with nest material
The status bar's "Plate N of M" counted the trailing empty plate, and its
plate number and size repeated what the plate view header already shows.
Drop Plate, Size and Qty from the status bar. Show the plate quantity in the
header as "×N" when it is above one, and keep Util in the status bar so it
stays visible while the Drawings tab is open.

Add a Material label (name and thickness) that opens Nest Info when
clicked. Nest Info remains the only place to edit material, and the label
refreshes after the dialog closes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:53:46 -04:00
ajandClaude Opus 5.5 3d1270a860 fix(ui): scale part label search precision to material width
The plate view searched for each part's label point with PolyLabel's fixed
0.5" precision, a third of a 1.5" part, so the search stopped on the first
interior cell and put labels near edges instead of in the thickest spot.
Precision is now 5% of the part's mean material width (2 x net area over
total outline length), so small, slender or heavily cut-out parts refine
further while large solid ones stay cheap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:50:41 -04:00
ajandClaude Opus 5.5 add94dff6c fix(data): leave the trailing empty plate out of nest record plate counts
The editor keeps an empty plate at the end of a nest as its new-plate slot.
Counting it made database records report one plate too many, so the record
now uses the same displayed-plate count as the UI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:09:57 -04:00
ajandClaude Opus 5.5 e82f26b976 feat(ui): rename nests from Nest Info in Database mode
The nest name box was always read-only, so a nest could only be renamed
by Save As, which leaves the old copy behind. In Database mode Nest Info
now edits the name (uploaded with the next Save), as does the saved-nest
browser's Nest Information (saved immediately). File mode keeps it
read-only because the file name is the nest name. Renaming to a name
another active nest already has asks first, and declining reopens the
dialog with the edits kept; a duplicate accepted there is not asked about
again by the nest's first Save.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:09:08 -04:00
ajandClaude Opus 5.5 c7df3f5e23 feat(storage): ask before a first save reuses another nest's name
Nests named offline from the per-PC counter can collide with names already
on the server. Renaming them silently is not an option because the name may
already be on posted CNC programs and labels, so the first Save of a nest to
a server now checks for an active nest with exactly the same name and, only
then, offers a freshly allocated name in an editable dialog (Cancel saves
nothing). A failed or slow check keeps the current name, as before. Save As
and pending-upload reconciliation are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:09:08 -04:00
ajandClaude Opus 5.5 3bc71a7e87 feat(server): allocate nest names from one yearly server sequence
File > New restarted its counter every day while names only carry the
year, so the first nest of each day was always N26-223, and each PC kept
its own counter. In Database mode the nest server now hands out the
year's next number (POST /api/nest-names/next, nest_sequences table,
schema v6), staying above every stored generated name so offline or
pre-existing names are never reissued. The per-PC counter remains the
fallback when the server is unreachable or older, resets per year, and
is raised past each server allocation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:09:07 -04:00
ajandClaude Opus 5.5 d35178c3b5 feat(clamps): edit clamps on the plate view, on any sheet edge
Clamps could only sit on the origin-side edge and be edited as a list in
Nest > Clamps. Setting them up against a real sheet is easier by dragging
them where they are, so Plate > Edit Clamps adds an edit mode: drag a clamp
along its edge or onto another edge, click near an edge to add one, click a
clamp's locating dimension to type its distance from the origin, Delete to
remove. Dimensions measure to the clamp center or its near edge
(remembered per user). Edits replace the nest's rail so every sheet follows,
like the dialog.

Rail clamps now carry a ClampEdge (origin side, far side, origin end, far
end), positioned from the origin along that edge. Origin-side clamps keep
their ids and files; other edges persist in optional per-edge arrays in
.nest files and clamps.json, omitted when empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:09:04 -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 9bf7760c1d fix(ui): keep the cut simulator's torch in place when rates change
Changing a rate, the pierce time or the machine rebuilt the timeline and
kept the playhead's old time. That time pointed at a different move on
the retimed timeline, so the torch jumped around while settings were
adjusted. When the new timeline has the same moves, Load now finds the
same move and how far through it the torch was (CutSimulation.TimeAt
inverts FractionAt, acceleration included).

The in-progress rapid was drawn whole with a dashed pen. GDI+ cost grows
with dash count: zoomed in, one paint of a long rapid can take seconds
to minutes. It is now clipped to the visible area, as finished rapids
already were.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 08:00:47 -04:00
ajandClaude Opus 5.5 50cb34305c feat(ui): fixed-size cut simulator with a larger play button
The window used to grow to fit long drawing names, then never shrank.
Now it keeps one size. The status shows Time, Part, Drawing and Motion
on separate rows, and drawing names get two full-width lines (longer
ones are trimmed and appear in full on hover). Play is the largest
transport button because it is the main control. The track bar is
shorter, and playback now defaults to 5x.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 07:32:27 -04:00
ajandClaude Opus 5.5 2b3f8e7b52 fix(posts): Cincinnati CL sub-program frames, head raises and dead settings
Part sub-program calls restored the sheet frame with G92 at the part
corner while the tool sat at the sub-program's last endpoint, shifting
every later part. The call now raises the head, rapids back to local 0,0
and restores there. Parts share a sub-program only when their posted
toolpaths match, so per-part lead-ins are kept.

Suppressed moves are left uncut: the cut resumes with a rapid past them.

Head raises go before the rapid that leaves a feature, one per rapid:
the safety raise now precedes the rapid to a new part instead of
following its first feature, and sub-program mode no longer posts M47
then M47 P2000. M47Mode.Auto posts M47 before rapids longer than
M47OverrideDistanceThreshold and /M47 otherwise. ExteriorM47 applies to
the contour spanning the part's cut extents.

The sheet GOTO targets FeatureLineNumberStart and is omitted without line
numbers. PrepareForNest pre-selects only the gas- and thickness-matching
library. Part programs are read through absolute copies, never switched
to absolute in place.

Removes the unimplemented UseSheetSubprograms, CoordModeBetweenParts and
ProcessParameterMode (G89Mode); old configs still load.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:56:28 -04:00
ajandClaude Opus 5.5 5dc13a03ae feat(diagnostics): warn when parts are closer than the part spacing
Validate Nest, the posting review and console --post now report a
"Part spacing" finding for pairs of parts that do not overlap but sit
closer than the plate's part spacing. Before, only Auto Nest's
Keep/Discard review checked spacing, so hand-edited layouts could be
validated and posted with parts too close together.

Candidates are found with Auto Nest's own outline test, moved into Core
as SpacingOutline (NestLayoutCheck and NestTolerances now use it; Engine
tests unchanged). Because that outline circumscribes arcs by more than
the spacing slack, each candidate is confirmed on native contours
flattened 20x finer than the slack, so arcs placed exactly at the
spacing by interactive fills stay clear. The finding reports the
measured gap and marks the middle of the closest approach. Overlapping
pairs, cut-offs, zero spacing, the plate edge and clamps are not
reported as spacing findings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:56:27 -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 4676c97c2c fix(tests): skip cut-time PDF test when pdftotext is missing
The GitHub Linux runner has no poppler-utils, so ReportPdf throws
SkipException; as a plain [Fact] the test failed instead of skipping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:51:46 -04:00
ajandClaude Opus 5.5 5dff83cfb8 fix(server): reject duplicate nest ids, invalid metadata and bare --database
- POST /api/nests with an existing id (active or deleted) now returns 409 with
  the current record instead of a 500 from the UNIQUE constraint.
- Uploaded nest metadata must have string text fields and a defined status;
  null fields and undefined statuses (e.g. 99) are 400 instead of a 500 or a
  stored invalid value.
- --database <path> is accepted alongside --database=<path>; a missing or
  repeated path fails startup instead of silently using OPENNEST_DB/default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:30:37 -04:00
ajandClaude Opus 5.5 3a7073d38c fix(posts): post Cincinnati CL holes where and as drawn, in sequence
Hole sub-programs are stored incremental but were written under G90 as
if absolute, producing invalid arcs. The registry now posts absolute
copies and leaves the nest's programs untouched.

Sheet-level hole calls omitted the part location from G52, so every
part's holes were cut near the sheet origin. Calls now shift to the
part location plus the hole offset.

Hole calls were matched to sub-programs by call id, which planned
emission numbers 1, 2, ... per drawing, so holes from different drawings
shared the first drawing's sub-program and diameter. Calls are now keyed
by program reference and deduplicated by posted toolpath.

A part opening with a hole call got a synthetic rapid that posted an
empty pierce on the part edge. The rapid is now only inserted before a
contour motion with no rapid ahead of it; the hole call carries the
part comment and safety head raise that feature used to hold.

The sheet writer re-sorted parts bottom-then-left with cut-offs last.
Plate order is the cut sequence, so parts now post in plate order.

Regression tests replay the posted G-code for off-origin parts of
several drawings and check each hole's center and radius.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 01:08:06 -04:00
ajandClaude Opus 5.5 00acaeaaf1 feat(engine): report best whole-job plans from Rectangles, Circles and Default
Desktop Auto Nest's "Best plan so far" strip now fills in for every built-in
whole-job engine except FlatBar, not only Irregular.

- Rectangles makes one sheet-by-sheet run, so it reports the finished job as
  its one plan, then replays its plate commits (token checked as before).
- Circles reports when a stock-preference run or a tail re-plan beats its
  best result so far.
- Default scores each candidate plan as it ranks results (valid, fewest
  unplaced, lowest cost, candidate order) and reports it only when it beats
  every plan already shown, so a later candidate never shows a worse plan.
  The chosen result is always the last plan reported.
- Shared ReportPlan/SameLayout helpers on CandidateProgress; Irregular uses
  them too. Reporting never changes the search.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:56:38 -04:00
ajandClaude Opus 5.5 cd2bea054b feat(desktop): show Auto Nest as a sheet strip with a Keep/Discard review
Auto Nest no longer draws parts on the plate view before they are kept:
its result is a set of sheets, possibly of several sizes, not parts on the
current plate. Ghost parts stay with interactive Fill and remnant tools.

- NestJobStage.PlanImproved carries an engine's best whole-job plan so far;
  Irregular reports one whenever a variant or the tail re-plan beats it.
- NestPipeline adds PlanSheets: the plan on detached drawings built from
  the job geometry (with the caller's names and colors), so previews never
  touch caller drawings or quantities.
- SheetStripControl draws every sheet side by side at one scale, repeats
  once with their count, captioned with size, parts and utilization.
- The progress window shows "Best plan so far"; a review window shows the
  final sheets, totals, cost summary and unplaced parts before commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:56:38 -04:00
aj a2fb945669 Revert "feat(engine): live sheet preview while Irregular packs"
This reverts commit 9f0e536eeed85e4417f285b94913e03f594400f7.
2026-10-18 23:56:38 -04:00
aj b11225135e Revert "feat(desktop): draw Auto Nest previews on the trial sheet"
This reverts commit bf42cdc63d5e475fa6921a3ddac06d7a39152bec.
2026-10-18 23:56:38 -04:00
ajandClaude Opus 5.5 d384e63068 feat(desktop): draw Auto Nest previews on the trial sheet
NestProgress gains PreviewSheet, a detached plate for the stock the preview
parts lie on; Irregular builds one per stock. PlateView draws it (size, edge
spacing, clamps) in place of the plate while the preview is shown and drops
it whenever the preview is cleared or the plate changes. Auto Nest zooms out
when a trial sheet falls outside what it has already shown.

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