Commit Graph
2239 Commits
Author SHA1 Message Date
ajandClaude Opus 5.5 b026bd19d2 feat(common-line): place parts on common lines automatically at a chosen level
Slice 3 of common-line cutting. On costly plate (N26-295: 3/16 RA310S at about
$2,500 a sheet) pairing parts one kerf apart fits the part the spacing cannot:
the last plate's 38 parts fit on one 48x120 with Auto Nest only with pairs.

- Drawing Properties gains "Allow common line" (Drawing.AllowCommonLine, off by
  default because customer edge-quality needs vary). The nest's CommonLineUsage
  (Off / When it adds parts / Whenever available) is set in Auto Nest and seeded
  from Tools > Nest Defaults; both persist (nest.json, defaults.json).
- NestPipeline runs the ordinary solve, then, with a level on, trials where
  eligible parts are offered as kerf-gap pair compounds. Placed pairs expand into
  parts plus explicit NestJobCommonLine groups, are validated again, and
  CommonLineRanking keeps a trial only by the level: count first, then sheets;
  "when it adds parts" keeps the plain layout on a tie, "whenever" also takes a
  shorter cut or less material, never at the cost of a part. Engines, FillScore
  and their comparers are unchanged; Off asks the engine exactly what it did.
- NestLayoutCheck exempts members only through a sheet's explicit group list and
  only when the job allows common lines; materializing and committing create
  Plate.CommonLines.
- Server nesting writes common-line jobs as version 3 and replays the recorded
  trial answers, so the desktop binds the same groups.
- Fill Area honors the level through a PlateFillService overload.
- The benchmark gains --common-lines <level> --kerf <k>.

Benchmark (synthetic nests + N26-295, --parallel 1): with no flag and with
--common-lines off every engine matches the base commit; with a level on no
layout becomes invalid and three runs save a sheet at equal nested area.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 19:38:00 -05:00
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
aj b630b50b7b fix(ui): label the server jobs button Stop Job
The job it acts on is shown as Stopping and then Stopped, and the rest of the
app talks about stopping server jobs, so the button now says Stop Job too.
2026-11-05 15:00:15 -05:00
ajandClaude Opus 5.5 1d87d212de feat(common-line): place parts one kerf apart to share an edge
Expensive alloy jobs (N26-295, 310 stainless) could not fit their last
PT42 at full part spacing; the plate was squeezed to 0.2 spacing with a
part 0.14 from the edge. Parts whose straight edges face each other one
kerf apart are cut on the same centerline, saving the spacing along each
shared edge.

Plate.CommonLines holds groups of parts and the kerf they were joined
at. Shared spans are derived from the placed clean perimeters, never
stored, so a moved member breaks its group instead of leaving a stale
span. Plate > Arrange > Join Common Line slides the selected parts
together at the plate's kerf; Remove Common Line ungroups them. The
plate draws shared spans as a dashed centerline.

Both spacing checks hold group members to the kerf instead of the part
spacing, and a new pre-post Common lines check reports broken groups, a
changed kerf, and leads that run into a partner. Groups persist as part
positions in an optional commonLines array that older readers ignore.

This first slice still cuts every shared edge twice; single-pass cutting
through Plan Cutting and the posts comes next.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 14:16:13 -05:00
ajandClaude Opus 5.5 924763493d feat(report): place part IDs wherever they fit best, holes included
Ring-shaped parts (a plate with a large center hole) were left unlabeled:
the material at their pole is too narrow for the ID, and the label was
never tried anywhere else. Group IDs were likewise only ever placed beside
the dotted outline, so a cramped cluster lost its ID or straddled the
sheet edge.

A part whose pole spot is too tight now takes the roomiest clear spot
within its own extents, such as its empty hole. A group ID takes the
roomiest spot inside its outline or beside it; with none clear it may
cover the group's own parts near the center, since operators read part
detail from the parts list. No ID sits across the sheet outline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 13:01:39 -05:00
ajandClaude Opus 5.5 46adbfd6f6 fix(ui): refresh the drawing list on the UI thread, never from the timer thread
EditNestForm's debounce timer is a System.Timers.Timer whose Elapsed ran
on a pool thread, checked drawingListBox1.IsHandleCreated, then called
drawingListBox1.Invoke. Invoke reads Handle, so a handle destroyed
between the check and the call was re-created on the pool thread (the
cross-thread check is off outside the debugger) while the UI thread was
disposing the window, which threw "Dispose() cannot be called while
doing CreateHandle()". The timer starts enabled at 50 ms, so short
WinForms tests such as LedgerCodeRecheckTests.NoLedgerOrNoCodes_ChecksNothing
hit it intermittently on CI.

Elapsed now posts to the window's UI synchronization context and the
refresh checks IsDisposed there; the timer is disposed with the form.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 12:55:14 -05:00
ajandClaude Opus 5.5 fbe82d198a fix(report): keep IDs on neighboring part groups one spacing apart
Each dotted group outline was padded 1 pt beyond its parts. At overview scale
a 0.25 in part spacing is only ~1.3 pt, so the outlines of two adjacent
clusters (e.g. the six small bars and the two holed plates on N26-27Y plate 1)
overlapped, and the later group - with its ID - was silently dropped.

Pad outlines by under half the part spacing instead, so neighboring clusters
both get their outline and ID.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 12:49:02 -05:00
ajandClaude Opus 5.5 a994bae76f feat(open): list materials for several saved nests
The Database-mode Open dialog now allows multi-row selection and a Get
Materials command (button and context menu) that downloads the chosen
nests, or every nest the current search matches across all pages, and
lists the sheets they use by material, grade, thickness and size with
the quantity and the nests using each. Needed to order stock for a whole
job's worth of nests at once instead of opening them one by one.

Material, grade and thickness come from each nest's server record;
sizes and duplicates from its plates, skipping plates with no parts.
Copy All and Save CSV export the list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 09:57:43 -05:00
ajandClaude Opus 5.5 f9abab0c6d feat(verify): warn when parts leave the plate or its edge spacing
Validate Nest and the pre-post review checked overlaps and part-to-part
spacing but never the sheet itself, so a part dragged past the plate edge,
a lead-in piercing off the sheet, or a part inside the edge spacing could
post without a warning. Only Auto Nest's own layout check held parts to
the work area.

PlateEdgeReview adds two finding kinds:
- OffPlate: any cut, lead or scribe motion past the sheet, or clean
  material outside an outlined sheet or over one of its obstacles.
- EdgeSpacing: clean material (leads excluded) outside the work area, or
  closer than the largest edge spacing to an outline or obstacle - the
  bound Auto Nest's layout check applies, with SpacingSlack, so layouts it
  accepted stay clear.

Cut-off parts are exempt. Routing-replay test fixtures sit at the sheet
origin with leads hanging off it; their route assertions now ignore the
sheet-bound kinds, and the post-contract fixture moves onto the sheet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 08:59:23 -05:00
ajandClaude Opus 5.5 3cd7729d38 feat(cutting): keep cutting settings per machine material and thickness
Tabs suit thin plate, but on anything thicker than 0.25 in the parts
are too hard to break out of the sheet, and the Cutting Parameters
dialog was one global set for every job. Its settings now live on the
nest's machine thickness: leads on the existing Outside/Inside Cuts
tabs, and lead-in angle rounding, tabs and pierce on a new Tabs &
Pierce tab (ThicknessConfig.Cutting). In Database mode every
workstation gets the same settings through the shared machine.

The dialog and the Place Lead-in panel say what they edit, and save
back to that thickness (MachineCuttingDefaults.WriteTo, converted to
the machine's units). A thickness with no Tabs & Pierce of its own, or
a nest the machine has no thickness for, keeps this PC's settings as
before. If the machine can't be saved (server offline, a conflict),
the edit is kept on this PC for that job and the user is told.
Machine Configuration can copy one thickness's Tabs & Pierce to
thinner or thicker ones, so the 0.25 in rule takes a few clicks.

An older desktop saving a shared machine would silently erase these
settings, since it doesn't know them. Machine configuration classes
now keep unknown fields, and the server refuses a machine save that
leaves out a field the stored machine has a value for, telling the
user to update OpenNest.

The Plan Cutting status line now reports tabs from SupportTabs; since
"Tab every part" was retired it always said off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 08:24:39 -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 ae14458444 fix(ui): open View in CAD through the shell instead of crashing
.NET 8 defaults Process.Start to UseShellExecute=false, so handing it the
temp DXF tried to run the file as an executable and threw an unhandled
Win32Exception that took the app down. Open it through the shell so the
.dxf association is used, report write/launch failures in a message box,
and replace characters a file name cannot hold in the nest name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 07:21:33 -05:00
ajandClaude Opus 5.5 0e4f4f5109 fix(cutoffs): move a clamp-blocked tail separator past the clamp
A tail separator that landed on a front-edge clamp was skipped outright, so
a plate lost its whole remnant (19.5 in on a 48 x 120 sheet with the part
ending at a rail clamp) over a 1.5-in clamp. The separator now steps to the
clamp's far edge plus its clearance, repeating for any clamp it then meets,
and reports ClampMovedTailSeparator. The kept tail is shorter by that
distance and must still meet the minimum tail length; a separator pushed off
the sheet still reports NoSafeTailSeparator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 07:15:24 -05:00
aj cf483c1a2e fix(ui): say Stopped for server jobs the operator stopped
Every server path into NestJobState.Cancelled requires cancelRequested (Cancel Job), and the running state already reads Stopping.
2026-11-04 23:03:59 -05:00
aj e8215004ab chore: tidy cut-off spelling in new text and a stale comment 2026-11-04 23:02:58 -05:00
aj e290254a18 fix(ui): give console and MCP users a hint they can follow on outlined sheets 2026-11-04 23:02:21 -05:00
aj f31cd1c797 fix(posts): name the post settings fields in head-raise and head-lock refusals 2026-11-04 23:01:58 -05:00
aj 014051c121 fix(ui): describe the update source the way updates are actually found 2026-11-04 22:59:41 -05:00
aj 1179210e46 docs: correct outline, schema and internal-label wording 2026-11-04 22:58:23 -05:00
ajandClaude Opus 5.5 dc559a6c66 test(release): smoke the Lattice engine by its current name
The release smoke instantiated the multi-phase fill engine through its
old Fill alias, so it never proved the current name. It now creates
Lattice and checks that Fill still resolves to Lattice, as it does for
the Opus55NestingEngine rename.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 22:56:38 -05:00
ajandClaude Opus 5.5 4f272176b3 docs: use the Lattice engine name throughout
The multi-phase fill engine and strategy is named Lattice; the docs still
called it Fill in several places. Generic fill passes stay lowercase and
the renamed-engines alias table is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 22:55:51 -05:00
ajandClaude Opus 5.5 227a561d59 fix(ui): call the default fill strategy Lattice in console help and MCP descriptions
The multi-phase fill strategy has been named Lattice since the engine
rename, but the console's --engine help and the MCP tool descriptions
still offered it as Fill. Fill keeps working as an alias.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 22:54:51 -05:00
ajandClaude Opus 5.5 0547af2ff6 fix(nudge): always move the full calculated step
Interlocked rows, such as staggered triangles, cannot slide straight past
their neighbors, so capping the step with a push left them unable to
pattern down. The calculated step now moves the full distance like a fixed
nudge, even off the plate or onto a part; the layout check reports either.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 22:42:53 -05:00
ajandClaude Opus 5.5 d98bee87ec feat(nudge): step the selection by a calculated distance
Set Offset Increment gains a "Calculated distance" option. With it on, the
arrow keys move the selection by its own size plus the part spacing,
measured on its geometry like a fill's copy distance, so it lands tight
without a push back. The move stops early at an edge, clamp or part, and a
clone preview steps clear of the copy just placed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 22:21:56 -05:00
ajandClaude Opus 5.5 b5bc03bea1 refactor(circle-fill): merge FillEndOdd and FillEndEven into StaggeredFill
The two stripe layouts differ only in how far odd stripes shift, so they are
now one StaggeredFill with StaggerMode.HalfPitch (was FillEndOdd: half-pitch
shift, odd stripes one disc fewer) and StaggerMode.SlackShift (was
FillEndEven: shift by the stripe's leftover, every stripe full). The unused
FillEngine base and its throwing Fill(item, maxCount) go away. Layouts and
orientation tie-breaks are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 22:02:03 -05:00
ajandClaude Opus 5.5 dffb06a9e3 feat(circle-fill): end staggered rows with straight rows when that fits more
The Circle fill strategy's stripe layouts (FillEndOdd, FillEndEven) now try
switching from staggered to straight stripes, a diameter apart over the last
staggered stripe, at every stripe, all staggered and all straight included,
and keep the switch that places the most; a tie stays staggered. A 9" circle
on a 60x120 sheet at 0.2 spacing now fills 89 (five staggered rows, two
straight) instead of 88.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 22:02:03 -05:00
ajandClaude Opus 5.5 8700ae187a feat(expand-spacing): keep rows that share a pitch but stack unevenly
A single-drawing selection that fits no one lattice, such as staggered rows
topped by straight ones, now counts as a pattern when its rows share one
pitch along X (or Y). Each row stretches rigidly instead of the selection
falling back to the slow pair search.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 21:44:12 -05:00
ajandClaude Opus 5.5 7f718f222c feat(expand-spacing): stretch repeating patterns instead of pushing pairs apart
A selection that repeats on a lattice (a fill) now has its lattice scaled
along X, then Y, as far as the work area and clearance floors allow, so the
pattern survives. Multi-part motifs stay rigid, no selected gap closes below
the smallest entry gap, and parts never pass through fixed material. Other
selections keep the pair search.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 21:12:22 -05:00
ajandClaude Opus 5.5 440fe767f1 fix(ui): keep the drawing library dialogs above the main window
The library dialogs were owned by the nest tab (an MDI child) or by the
library view, both child windows. Windows only keeps a dialog above its
owner, so the main window could cover them. Own them by the top-level
window instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 20:47:59 -05:00
ajandClaude Opus 5.5 4dae54c629 feat(plates): resize plate to fit parts at any size
Resize to Fit snapped layouts larger than 48x48 to a hardcoded list of
inch mill sheets, so a plate already on a full sheet could not shrink to
its parts, and the cutoff ignored nest units and the machine's stock
sizes. It now rounds the parts' extent up to the auto-size plate factor
at every size through Plate.AutoSize.

Removes Plate.SnapToStandardSize and PlateSizes.Recommend with its
options; the sheet list and label lookup stay for Machine Config.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 20:45:33 -05:00
ajandClaude Opus 5.5 7ea21f3afe fix(reporting): weigh parts with the machine catalog's material density
Nest reports showed "-" for every part weight on N26-295 because the nest and
its drawings store Stainless Steel 310 with density 0: materials are picked by
name and grade, and nothing copies a density onto them. The densities live in
the machine material defaults, and for this nest not even on its own machine
(CL-980 lists only 304; 310 is on CI FIBER 4020).

The desktop now resolves a catalog density before capturing the report: the
nest machine's exact name and grade, any machine's exact name and grade, then
the same material name. A density stored on the nest still wins, and the
drawing's own material stays the last fallback.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 13:51:23 -05:00
ajandClaude Opus 5.5 90a1a087f0 feat(plates): reorder plates by drag and drop in the Plates list
Operators want plates of the same size grouped together so material
doesn't need sorting when it arrives; there was no way to change plate
order. Rows can now be dragged to a new position (with a drop line and
edge auto-scroll), or moved with Alt+Up/Alt+Down. Each move is one
undoable "Move Plate" step and only reorders: quantities are untouched.

The trailing empty new-plate sentinel stays last. An empty plate moved
to the end becomes the sentinel, as the sentinel rule already does on
reload, so the order shown is the order saved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 13:41:23 -05:00
ajandClaude Opus 5.5 890cbc486b feat(status-bar): show the material grade in the material label
The status bar showed only the material name and thickness, so nests
of the same material in different grades looked identical there. The
grade now follows the name, e.g. "Material: Steel A36 · 0.25 in".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 13:35:31 -05:00
ajandClaude Opus 5.5 698b91d256 feat(reporting): show job parts as cards with size and weight
The summary's parts table squeezed each thumbnail into a 62 pt column and
had no room for the size and weight the shop asks for. Each drawing is now
a card, four to a row: ID, a larger thumbnail, name, bounding-box size,
weight each and for all nested copies, required/nested counts and plates.
A shortage or extra is a badge beside the ID (SHORT in red) so it stays
easy to spot without a column to scan.

Weight is net area x nest thickness x material density, read as lb/in^3
like the machine material defaults; millimeter jobs report kilograms. A
nest without thickness or density shows "-" and a note saying what is
missing, never a zero weight.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 10:24:30 -05:00
ajandClaude Opus 5.5 9d4d024d60 feat(reporting): view nest reports in a window to save or print
Export Nest Report only wrote a file, so checking or printing a report meant
finding it and opening another program. View Nest Report renders the same
snapshot to a private temp folder and opens it in a WebView2 viewer with
Save As and Print; closing the window deletes the temp copy. Export and View
share the capture and write guards.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 10:02:42 -05:00
aj 54cea0c325 Merge branch 'fix/report-group-ids' 2026-11-04 09:38:39 -05:00
ajandClaude Opus 5.5 c60694b947 fix(reporting): label groups of small parts nested in a larger part's notch
Group outlines and their shared ID were rejected whenever they touched
another part's bounding box. A large irregular part's box can cover most
of the sheet, so small repeated parts sitting in its notch or cutout
(e.g. test squares) were left with no ID at all. Test clearance against
real contours instead, as individual labels already do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 09:38:30 -05:00
ajandClaude Opus 5.5 032854895d fix(reporting): fill parts whose arc ends carry post roundoff
The nest report joined contour segments only within 1e-12, but converted
arcs rebuild their end from the start radius and end angle. Rounded or
incremental programs (end radius a few 1e-7 off the start radius, which
the report's own validator accepts up to Tolerance.Epsilon) left every
arc a hair short of the next move, so outlines split into open pieces
and N26-27K's parts printed unshaded as if they had tab gaps.

Join within Tolerance.Epsilon instead, still far below ShapeBuilder's
welding tolerance and real tab gaps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 03:09:15 -05:00
aj be5fef6875 fix(release): enforce one finish per commit and keep real unplaced reasons
Delta review fixes:

- ReleaseRenest throws when a commit does not call finish, or calls it
  twice: either would leave ledger plates uncoded or count a sheet twice
  for later nests of the run. The ledger sheet count is the codes given.
- A stage whose layout is not kept now lists the copies its layout
  missed with their own reasons (a part no sheet fits stays "does not
  fit"); only the copies it placed are "the proposal cannot be kept".
- A valid ledger layout that places nothing says "Auto Nest placed
  nothing on it" rather than claiming no part fits.
- ReleaseLedgerOffer rejects null rows; docs list every ledger note.
2026-11-03 18:03:24 -05:00
aj 9efeb4e5b6 test(release): check the ledger step's own undo state keeps its code 2026-11-03 17:55:16 -05:00
aj 3e35821ab1 docs(release): note bundle sharing, merge drafts and every ledger note 2026-11-03 17:53:26 -05:00
aj c5b6e680cb fix(release): keep ledger codes in the undo step and share bundles per sheet
Review fixes for ledger-first Make Nests:

- The release renest (offer, staged run, codes, note) moves into
  OpenNest.Desktop.ReleaseRenest, shared by the headless panel, the
  live main window and the tests. Codes are given inside each commit, so
  the live tab's Auto Nest undo step records them; before, undo and redo
  dropped every ledger code.
- A bundle repeats one code per sheet: a later nest of the run lost the
  whole bundle once an earlier nest took one sheet. Taken sheets are now
  counted per code (LedgerCodeFilter.ExcludeCopies).
- A stage whose layout is not kept lists every copy it asked for as not
  placed (the proposal cannot be kept), and a rejected ledger layout
  says "MaterialLedger not used: Auto Nest could not keep a layout on
  its stock" instead of a bare "No MaterialLedger stock used".
- "no free stock" is said only when the ledger had none; otherwise the
  note counts what was left out (on other nests, taken by earlier nests
  of this release, too small, unknown shape).
- The ledger is not read for a nest with nothing to nest, the live read
  runs under the tab's stop token, a reason's own full stop is not
  doubled, and the sheet count is the codes given.
2026-11-03 17:53:26 -05:00
aj 31ee77914f docs(release): describe ledger-first nesting in Make Nests 2026-11-03 17:38:07 -05:00
aj 3b5cf92af2 feat(desktop): Make Nests nests each group on its MaterialLedger stock
With Nest after release ticked, one ReleaseLedgerStock is shared by the
whole run and passed to the renest step, headless or live in the main
window. The live tab runs one Auto Nest per stage (ledger stock, then
the Nest Defaults sheet), records the ledger locations for the plate
tooltips, and the group's note says how many sheets came from the
ledger or why it was not used.
2026-11-03 17:38:07 -05:00
aj 2939fe0802 feat(release): nest released groups on MaterialLedger stock first
NestRenest gains a staged run: a nest is nested on finite first stock
alone, then whatever is left on its plate defaults and plate-size
options. Each stage keeps only a valid layout, and the result lists the
stock id each committed plate was solved on.

ReleaseLedgerStock is the ledger stock of one Make Nests run: each nest
is offered the free sheets and drops Auto Nest's ledger load would tick
for its material, grade and thickness (substitutes included), minus
codes on other open server nests (read once per run) and codes earlier
nests of the same run took, which are not on the server until the
release uploads them. Committed ledger plates get their codes as Auto
Nest gives them. An unusable ledger nests on the plate defaults and the
note says why the ledger was not used.
2026-11-03 17:38:07 -05:00
aj 072e96c08e fix(ci): expect the role-aware image healthcheck in the server smoke
The image HEALTHCHECK became /app/healthcheck.sh when the worker role was
added (54ad7ee8), but the container smoke still required the old inline curl
probe, so every Server image validation since then failed before publishing.
Expect the script form and describe it in the storage docs.
2026-11-03 16:19:28 -05:00
ajandClaude Opus 5.5 53d46303cd fix(planning): raise the head out of a cutout's slug after its lead-out
A cutout's lead-out ends in its slug, so the rapid after it always crossed
the cutout just cut and the strict search refused every plan with cutout
lead-outs. The slug is free and may drop or tip, so emission now marks that
rapid to raise the head, and the rapid check accepts a raised rapid that
starts at the lead-out's end and leaves its cutout exactly once. Cutouts
without a lead-out, or with an overcut, still leave from the cut head down.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 13:45:12 -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 5de628760f feat(ui): fill a blank Nest Info Made By with the current user
A blank Made By now starts from the name the user last typed there, or
their Windows user name when they never typed one. Changing the box on OK
remembers the new name in user settings; clearing it falls back to the
Windows name again. A nest's own author is shown unchanged and is not
remembered unless the user edits it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 12:23:24 -05:00
ajandClaude Opus 5.5 d7fe7fe33c feat(ui): mark unsaved nests and ask before closing them
A nest window gave no sign that its nest had changed since the last
save, and closing it (or the app) discarded the edits silently. The
undo history already tracks a save point, so the title now ends in
" *" while the nest is off it (or holds an edit no scope recorded),
and closing asks to save, discard or cancel. Yes saves through the
storage in use; a database save cancels the close and closes the
window once the upload succeeds.

Saves now commit any unrecorded edit first so the save point covers
what was written. The window's cleanup moves from OnClosing to
OnFormClosed: another window can still cancel closing the app, and a
nest window must not lose its plate manager when that happens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 12:09:50 -05:00