Commit Graph
169 Commits
Author SHA1 Message Date
ajandClaude Opus 5.5 b703abe8dc feat(library): add a Drawing Library Grid that checks every drawing
File > Drawing Library Grid shows a page of library drawings side by
side. Check All Pages walks every page, downloading each drawing, timing
its label search without the paint's cell budget on a worker with a
10 s limit, then timing its paint, and lists drawings that fail, run
slow or would freeze a preview. It was added to confirm no other library
drawing hangs on load the way the twin-outline drawing did: a run over
all 40,757 drawings on the work server found no hangs or failures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 07:50:06 -05:00
ajandClaude Opus 5.5 d57678ecee Disable toolbar buttons that cannot be used
Plate commands need an open nest and no running job; Trim/Extend Cut-Off
needs a cut-off on the plate and Sequence by Path needs two parts. The
Plate menu's Trim/Extend item follows the same rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 16:33:36 -05:00
aj 5e2606f679 Add a Zoom To Area button to the plate header
The header gets a fourth zoom button that starts the existing Zoom Window
action, with a matching dashed-window icon also shown on View > Zoom To >
Area. It stays out of the inspection's live zoom controls: inspection owns
Escape, so a zoom window could not be cancelled there.
2026-11-01 14:07:48 -05:00
ajandClaude Opus 5.5 bbdd51fabc feat(cad-converter): show the source file's raw geometry as Original
Show Original drew nothing until Simplify ran, and then showed entities that
had already been through import cleanup. The importers now capture the
entities before any optimization and the overlay draws those from load, while
Simplify keeps starting from the cleaned entities.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 12:07:06 -05:00
ajandClaude Opus 5.5 c027793077 test(desktop): share form pumping and reflection helpers
Desktop test classes each kept identical PumpUntil, Show, Mouse, All,
PressKey, Raise, SetBackingField and Field helpers. They now import
FormTesting and TestReflection; the two Field variants that read a base
type's field or unwrap DrawingLibraryForm keep a one-line wrapper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 11:24:46 -05:00
ajandClaude Opus 5.5 e5d9e12df9 test(desktop): share the square and rectangle part programs
Ten desktop test classes drew the same squares and the same 4 x 2
rectangle in private helpers, in two equivalent styles. They now use
TestPrograms.Square, ClockwiseSquare and Rectangle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 10:53:24 -05:00
ajandClaude Opus 5.5 59d4c8d727 feat(machines): set spacing per thickness and save defaults from a nest
Plate > Set as Default and Nest > Edit's Defaults tab only changed the
open nest, so new nests never picked up the values. Set as Default now
also saves the new-nest defaults, and the Defaults tab gains an opt-in
"Use these defaults for new nests" check.

Machine thicknesses can now set part and edge spacing. A nest takes them
when its material, grade, thickness or machine changes and when a release
creates it; BOM import seeds its groups from them. Spacing edited in the
same dialog stays, and only an untouched trailing sheet follows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 19:39:48 -04:00
aj ad5f2a9041 feat(cad-converter): add a Hole Table window that counts and colors holes by size 2026-10-31 05:50:22 -04:00
aj 45ab837c8c feat(cad-converter): drag a dimension by its value
Pressing a dimension's value text now grabs it like its line does. The
label keeps its offset under the pointer, so a radius or diameter value,
which sits past its leader's end, no longer jumps when grabbed. Hit boxes
are measured the way painting draws them, at the control's DPI.
2026-10-31 05:40:26 -04:00
ajandClaude Opus 5.5 ca693285bb feat(cad): add radius and diameter dimensions
Holes and radii need sizes on the drawing as well as the overall extents. Select
circles or arcs, right-click and choose Add Radius Dimension or Add Diameter
Dimension. The value is measured live from the curve, found by its entity ID, so
it follows edits; only the leader angle and label offset are saved. A radius on
an arc stays on its sweep, and labels are kept clear of the curve and center.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 22:47:56 -04:00
ajandClaude Opus 5.5 abced0a7ec feat(cad): add overall dimensions to the CAD Converter
Shops need a part's overall size on the drawing while converting it. Width and
height are measured live from the geometry that will be cut, so they follow
filters, exclusions, simplifying, breakoffs and tabbed cutouts instead of going
stale. Only the placement is saved; dimensions never touch the program.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 22:34:31 -04:00
ajandClaude Opus 5.5 3a8994c8fe feat(io): import and export SVG drawings
Customers and design tools hand over SVGs, and getting them in meant a
trip through another CAD tool. CadImporter now reads them like any other
drawing, and plates, programs and converter entities can be written out.

An SVG's numbers are not drawing units, so import converts to the nest's
units and never guesses: only an absolute width or height counts as a
stated size, since px means 1/96 in to browsers but 1/72 in to
Illustrator. Without one the desktop asks, showing the size each choice
gives, and headless callers must pass the scale or the import fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 17:50:41 -04: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 667beb4334 fix(cutting): start planning from the user's settings
Edits in the Cutting Parameters dialog only reached user settings, while a
plate's stored parameters took priority, so a change was lost on any
planned plate unless Apply succeeded. User settings now win; a plate's own
are the fallback when none are saved or readable.

WinForms tests saved to the real user-settings.json, and with user settings
winning a test's lead-ins would feed real planning, so they now use a temp
file and skip the legacy settings carry-over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 14:06:11 -04:00
aj 7a7b671408 fix(tests): select the library row before Add/Edit in DrawingLibraryFormTests
The drawing library tests relied on DataGridView picking a current row by
itself when the page is populated. It only does that when the first row is
already laid out as displayed, which the hosted Windows runner does not
guarantee. Without a current row SelectedRecord() is null, Add/Edit return
silently, and the test fails later:

- run 41057280460: EditSettings_SavesCutFirstAsANewRevision_AndTheAddAppliesIt
  "Timed out waiting for the reloaded page."
- run 40312036013: MismatchWarning_IsShownBeforeTheAdd_AndCancelLeavesTheNestAlone
  expected 2 messages, got 0.

Make the first row current explicitly after each page load (and after the
edit reload that precedes an Add), and make Run() rethrow a faulted task so
a failed step reports its own error rather than a 15 s timeout.
2026-10-30 09:17:13 -04:00
ajandClaude Opus 5.5 4ca8b0debf fix(ui): call set quantities sets in the release panel
The release panel was the only place that counted a set in kits;
everywhere else in the drawing library calls them sets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 08:25:23 -04:00
ajandClaude Opus 5.5 bb21ffdf35 feat(machines): split machine leads into outside and inside cuts
Machine Configuration held one lead-in and lead-out per thickness and
applied it to every contour. Each thickness now has Outside Cuts and
Inside Cuts tabs; inside cuts follow the outside leads until "Same as
outside cuts" is cleared, and configurations without inside leads keep
applying one pair to both.

The lead type lists, per-type fields and preview from Cutting Settings
are now a reusable LeadsEditor control that both dialogs use. The
machine tabs hide what the configuration cannot hold: the arc sweep,
the clean-hole kerf (taken from the thickness) and Line + Line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 18:51:42 -04:00
ajandClaude Opus 5.5 c798be9b95 fix(undo): restore plates that hold only cut-offs
Undo regenerates each restored plate's cut-offs, which removes the
cut-off parts first. A plate holding nothing but cut-offs became empty
for a moment, so the new-plate sentinel dropped a trailing plate while
the restore was still enumerating the plates, throwing "Collection was
modified". Regenerate inside a PlateManager batch so the sentinel only
settles once every plate is done.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 09:17:51 -04:00
ajandClaude Fable 5.1 a0d063bb94 test(desktop): apply the Edit Plate dialog directly in the outline tests
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-28 22:21:50 -04:00
ajandClaude Fable 5.1 662d3daf8c feat(desktop): draw and edit a plate's sheet outline
The plate view fills the outline, hatches obstacles and draws the usable
area; Edit Plate imports an outline from a CAD file or clears it, with
the size read-only while the sheet has one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-28 22:16:36 -04:00
ajandClaude Opus 5.5 379e3fd433 fix(ui): preview the selected version in the database browser
Highlighting an earlier version on the Versions tab left the plates,
drawings and plate preview on the current version, so there was no way
to see what a historical version looked like without opening it. The
embedded history now reports its selection and the browser downloads
that version (debounced, cached per history view) and shows it, labelled
as historical; selecting the current version returns to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 07:30:45 -04:00
ajandClaude Opus 5.5 fcb61f3b3e feat(ui): choose Plan Cutting's plate scope in the panel
The panel gains a Current plate only / All plates selector, shown when the
two scopes differ. Changing it takes the unapplied scrap cut-offs off,
cancels any running plan and replans. The toolbar button opens with the
scope last chosen there (default all plates); the Plate and Nest menu items
keep their fixed scopes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 23:12:18 -04:00
ajandClaude Opus 5.5 8776eb4734 feat(ledger): keep MaterialLedger item codes from being double-booked
Auto Nest leaves out ledger item codes already on other open server nests,
and save and post re-check a nest's codes before going on.

- Server: GET /api/nests/stock-item-codes?exclude= lists the codes on
  non-deleted Draft, Quote and To Be Cut nests. Codes are stored in
  nest_stock_codes (schema v14) at every archive write; the upgrade reads
  each current archive once.
- Data: INestRepository.GetStockCodesInUseAsync, LedgerCodesInUse (5 s,
  failures become an unknown answer), the pure LedgerCodeFilter for ledger
  rows (reusable by release-time nesting) and LedgerCodeCheck for the
  re-check.
- Desktop: the Auto Nest ledger summary counts "(N on other nests)" or says
  other nests were not checked. Save, Save As and post open Ledger Stock
  Changed when codes are taken: proceed after a per-attempt
  acknowledgement, remove the codes (undoable), or cancel. A ledger that
  cannot be read skips the check with a status note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 22:43:08 -04:00
ajandClaude Opus 5.5 3618b335cb feat(ui): edit a machine's support bed in Machine Configuration
Add a Support Bed tab beside Clamps that edits the grid or slats new
nests assigned the machine receive. A machine without a bed shows the
legacy support-grid.json values; the first edit stores them on the
machine in its units.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 21:39:30 -04:00
aj 242a0d2a1b fix(ui): match operator messages to the commands that exist
- archived library drawings: say they can't be edited or released; no
  front end can restore a library drawing yet
- library filter hint names the Show all materials checkbox
- undo labels Support Bed and Automatic Scrap Cutoffs match their menus
- display-outline posting hints name both Plate > Plan Cutting... and
  --plan-cutting, since the console prints them too
- MaterialLedger options are saved per Windows user, not per machine
2026-10-27 09:47:03 -04:00
ajandClaude Opus 5.5 3e1df45c7f feat(machines): keep the clamp rail on each machine
Clamps are physical fixtures that differ between machines, but one global
clamps.json served every machine, so a plasma table and a fiber laser could
not have different rails.

- MachineConfig.Clamps holds each machine's rail in the machine's units,
  edited on a new Clamps tab in Tools > Machine Configuration.
- New and BOM import give a nest the rail of the machine they assign;
  Nest > Clamps loads and saves the nest's machine's clamps. Each nest keeps
  its own copy, so machine edits never move existing nests' clamps.
- At startup, while no machine has clamps, the legacy clamps.json (or the
  server's shared copy) is copied once into the default or only machine;
  with several machines and no default the user picks one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 09:32:56 -04:00
ajandClaude Opus 5.5 dcb0a5c519 feat(shapes): pick shapes from a thumbnail grid in the Shape Library
Replace the name list with a ListView of 96px thumbnails drawn by
Program.GetImage at each shape's preview defaults (or its first
configuration), labelled with the name and configuration count. The
left pane opens three tiles wide instead of half the window.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 18:11:22 -04:00
ajandClaude Opus 5.5 a3a75d589d fix(converter): accept a required quantity of 0 when loading drawings
Nest drawings can require no parts, but the CAD Converter's quantity
spinner had a minimum of 1, so Edit Drawings in Converter threw
ArgumentOutOfRangeException as soon as such a drawing was selected.
Lowering the minimum to 0 lets the converter load it and hand the
drawing back with its quantity still 0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:26:29 -04:00
ajandClaude Opus 5.5 16afb41c26 feat(desktop): undo machine changes and Nest Info edits
The nest's machine and its Nest Info fields were the last edits only the
fingerprint safety net could catch (and it misses most of them). Machine
is now one step, together with the support grid and cut-off settings the
machine brings. Nest Info is one step for what Undo can put back (units,
material, thickness, customer, notes and plate defaults); the name,
status, author and creation date stay as they are through Undo, so an
edit of only those records nothing.

The sheet strip only shows Auto Nest proposals; what it shows is
committed through Auto Nest, which is already recorded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:11:57 -04:00
ajandClaude Opus 5.5 2e72469d6c feat(desktop): undo drawing imports, edits and deletes
Drawing changes were unrecorded, so Undo skipped them or lumped them
into an anonymous "Change". Each is now one labelled step: Import
Drawings, Shape Library (menu and panel button), Drawing Library (what
the dialog added or re-quantified), Save to Drawing Library (the nest
keeps the drawing's new library link), Edit Drawings in the converter,
Drawing Properties, Delete Drawing and Clean Unused Drawings. Dropping a
drawing on a plate was already recorded as Add Part and is now tested.

The converter can change live programs while it loads, even when it is
cancelled; a cancel that did so now rolls the nest back to before the
converter opened instead of leaving those edits unrecorded.

Deleting a drawing threw when removing its parts emptied the trailing
plates, because the plate manager drops trailing empty plates while the
loop walked the live plate list; it walks a copy now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:11:54 -04:00
ajandClaude Opus 5.5 3dd1acd3cf feat(desktop): undo cut-offs, sequencing, lead-ins and cutting plans
Cutting edits were unrecorded, so Undo skipped them or folded them into
an anonymous "Change". Each is now one labelled step: Add Cut-Off, Move
Cut-Off (one step per drag), Automatic Cut-Offs, Auto Sequence (current
plate or all plates, only when the order changed), Set Sequence (per
click), Sequence by Path (the whole tool session; Backspace and Ctrl+Z
inside it still take back one line), Place Lead-In, Remove Lead-Ins (the
tool's menu, the plate and the nest commands), Cutting Parameters (an
edited lead-in panel when the tool closes), Plan Cutting and Clear
Lead-ins and Cut-offs.

Plan Cutting stages scrap cut-offs on the live plates before it plans,
so its scope opens with the staging and records only when the plan is
applied; closing without applying records nothing. Clearing applied work
is its own step and no longer warns that it cannot be undone.

Opening the lead-in tool used to give a plate without parameters the
defaults straight away; the plate now takes the tool's parameters with
its first lead-in, so opening and closing the tool changes nothing.
Undo no longer waits while the tool has a part picked: it ends the tool.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:11:52 -04:00
ajandClaude Opus 5.5 9a62a5102d feat(desktop): undo plate edits, clamps and the support grid
Plate and clamp changes went unrecorded, so Undo skipped them or lumped
them into an anonymous "Change". Each is now one labelled step: Edit
Plate (only on OK), Rotate Plate, Resize Plate, Set Nest Default Plate,
Clamps and Support Grid (applying to the nest; saving machine defaults
stays outside the history), Remove Clamp / Put Clamp Back from the
plate's clamp menu, and Add/Move/Delete Clamp in Edit Clamps.

Edit Plate used to copy an empty plate's settings into the nest defaults
even when the dialog was cancelled; that now happens only on OK, so a
cancelled dialog changes nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:11:49 -04:00
ajandClaude Opus 5.5 223bfea47c feat(desktop): undo fills, pattern tiles, auto nest and clear nest
Placement edits were only caught by the fingerprint safety net, so they
undid as an anonymous "Change" or folded into the next edit. Each now
records one labelled step: Fill (at the commit, so a stopped fill that
keeps nothing records nothing), Fill Area, Pattern Tile, Auto Nest (from
the kept proposal only; Make Nests tabs too), Clear Nest, Remove Empty
Plates and Center Parts. Clear Nest no longer warns that it cannot be
undone.

Pattern Tile onto a new plate created a plate beside the empty sentinel,
which the plate manager dropped at once, so the pattern landed on a
detached plate; it now fills the sentinel.

The undo tests share one harness that compares a text description of the
nest before an edit and after Undo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:11:47 -04:00
ajandClaude Opus 5.5 d1270f5208 feat(desktop): undo and redo the most-used nest edits
Whole-nest snapshots make undo safe without a hand-written inverse per
operation: each recorded edit stores one NestSnapshot in the document's
history, and Undo/Redo read one back and swap it into the open window.

- Document.History is reset with the opened nest; Save and database
  saves mark the save point instead of clearing it.
- EditNestForm.BeginChange opens a scope: nested scopes merge into the
  outermost, Complete commits one entry, and leaving it incomplete rolls
  a changed nest back. No-ops are detected by the scope's changed flag,
  not by comparing bytes (copies are not byte-stable).
- RestoreNest shares the per-nest binding with the constructor and keeps
  the Document, the nest's identity, the plate index, the viewport and
  the selection. It ends the action, closes Cutting Inspection, side
  panels and the remnant viewer, rebuilds the PlateManager, reapplies
  the view's cut-off settings and recolours the drawings, because each
  of those holds or derives from the old nest's objects.
- An edit no scope recorded (Phase 3 sites) is detected by a cheap
  fingerprint and committed as its own "Change" entry before a scope,
  Undo or Redo, so it is never silently discarded; DEBUG builds also
  warn about it on idle.
- Edit > Undo/Redo name the next entry. Ctrl+Z/Ctrl+Y/Ctrl+Shift+Z go
  to focused text editors first, then to an action's own step-back
  (Sequence by Path), then to the nest. They wait for jobs, fills,
  background saves and busy actions, but not for a plain selection.
- Recorded: delete, drag, arrow nudges (coalesced), rotate, align,
  push, expand spacing, add part (drop and clone), cut, add and remove
  plate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:11:45 -04:00
ajandClaude Opus 5.5 27610c3b1d fix(library): lay out the set history's drawings grid on first show
The members group resumed layout only after the outer table had already
sized it, so its docked grid kept the default 240x150 until the form was
resized. Inner containers now resume before the table lays them out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:46:43 -04:00
ajandClaude Opus 5.5 6e40c2e6ed feat(library): redesign Edit Drawing with drop-downs, color modes and a rotation dial
Typing customer, material, grade and thickness by hand let near-duplicate
spellings into the library, which then split drawings that should match.
The fields are now drop-downs of the values the library and the machine
material catalog already use, while still accepting new values; thicknesses
already used for the material are listed ahead of the standard gauges.

A library color could be set but never cleared back to the color scheme's,
so Automatic and Reset are added. The rotation start/end/step boxes gave no
sense of the range, so a dial shades it, ticks the angles the engines try
(via RotationPolicy) and lets either end be dragged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:46:43 -04:00
ajandClaude Opus 5.5 e5e2c268b8 feat(ui): redesign the Nest Defaults dialog
The flat ten-row list squeezed the quadrant picker to 120x28 and gave no
hint of units or where the defaults are saved. Group the fields (General,
Plate Size, Quadrant, Spacing), lay the edge spacings out around a plate,
show in/mm suffixes, and convert the values when the units switch so a
48 in plate does not silently become 48 mm.

The footer says whether Save writes to this PC or the shared nest server,
and Save is disabled while the shared copy is read-only instead of
failing after the click.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 09:46:42 -04:00
ajandClaude Opus 5.5 96d8a6874f fix(autonest): show part rotation limits in degrees
The Rot Start, Rot End and Step columns showed the drawing's radian
constraints as-is, so users had to type 1.5708 for 90 degrees. The grid now
shows and accepts degrees; rows keep the radian values, so an unedited row
passes the drawing's limits to the engine without a conversion round trip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 07:10:59 -04:00
ajandClaude Opus 5.5 b0697f92b3 feat(cutoffs): keep large horizontal remnants in automatic scrap cut-offs
Strip lines now stop at a full-length horizontal cut-off that clears the
parts instead of slicing the band beyond it. The desktop dialog and Plan
Cutting also propose their own horizontal separator when that band beats
the X tail (opt-in for API callers via KeepHorizontalRemnant); a kept X
tail beside the band becomes a corner piece whose separator stops there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 00:20:34 -04:00
ajandClaude Opus 5.5 0c7ad5aefb refactor(engine): list the built-in fill strategies instead of scanning
FillStrategyRegistry now holds a fixed, ordered list of the seven
built-in strategies (Pairs, Row, Column, RectBestFit, Extents, Linear,
TiltedRemnant, in their Order sequence) instead of reflecting over the
Engine assembly. LoadFrom and LoadPlugins are gone; nothing outside
tests called them, so outside IFillStrategy plug-ins were never loaded
by a shipped host and none are loaded now. IFillStrategy stays public.

The disabled set stays process-wide and keeps its Disable, Enable,
SetEnabled, Strategies, AllStrategies and DisabledNames behavior for the
Options form. DefaultPlateFiller still reads Strategies, so interactive
Fill, the fixed-strategy engines, Irregular's block catalog and private
plate fill, the cutout lattice fill and the brute-force runner all keep
honoring it.

PlateViewFillLifetimeTests drives fills through PlateView, which builds
its own filler, so a filler-level seam can't reach it. The registry gets
an internal UseForTesting hook that swaps the list until disposed, and
the WinForms test project can see Engine internals for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 23:44:50 -04:00
ajandClaude Opus 5.5 079dfaf9ea fix(desktop): count only active MaterialLedger holds and link the nest page
MaterialLedger's Release lets a hold go, so a Released hold no longer keeps
a sheet for the nest; only Proposed, Approved and AwaitingCloseout holds,
the statuses ML counts against free stock, are open. The Has Been Cut
note's link pointed at /Nests/{id}, which ML does not serve; its nest page
is /Nests/Details/{id}.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 18:20:11 -04:00
ajandClaude Opus 5.5 be01124a0f feat(autonest): rank MaterialLedger stock and mark substitutes
MaterialLedger's /api/stock/opennest now resolves an OpenNest material
and grade through ranked acceptance rules. The client reads the new
spec rank, family, grade and finish and the item rank; an older ledger
that sends none of them deserializes as rank 1 with no label.

LedgerStockMapper groups drops only by identical size and spec, keeps
the ledger's order in rows and in each row's ItemCodes, and orders rows
by rank. Auto Nest's Source column shows the row's grade and finish
("A1011 P&O"); substitutes (rank above 1) read "A1011 P&O for HR" in
amber, name the substitution in their tooltip and still load ticked.
The engine still sees no rank.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 17:40:45 -04:00
ajandClaude Opus 5.5 f847b216f2 feat(desktop): show a server nest's MaterialLedger holds and closeout note
Server nests in Database mode get a read-only status bar label comparing their
open MaterialLedger holds with the sheets they cut, e.g. "Ledger: 2 of 4 held,
2 short". Nothing writes to the ledger and nothing waits on it.

- MaterialLedgerClient.GetHoldsAsync reads GET /api/stock/holds?openNestNestId=
  with the closed LedgerHoldsResult set; unknown status strings are kept. The
  request plumbing is shared with GetStockAsync.
- LedgerHoldSummary (OpenNest.Data) counts Proposed/Approved/Released/
  AwaitingCloseout holds against the plate quantities, skipping the trailing
  empty plate as /sheets does.
- NestHoldStatus refreshes on server open, after save, after storage or
  Options changes and on label click; it never polls. The tooltip lists holds
  in nest units. File-mode, unsaved and ledger-less nests show nothing.
- Setting Has Been Cut in Nest Info with holds still open shows a non-modal
  note linking to {ledgerUrl}/Nests/{id}. Posting is not gated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 17:40:45 -04:00
ajandClaude Opus 5.5 15750949dd feat(nest): plates name the ledger item each sheet is cut from
Auto Nest on MaterialLedger stock now records which inventory item each
physical sheet uses, so ML can hold exactly those items instead of matching
by size.

- Core: Plate.StockItemCodes (entry i = sheet i of Quantity; empty = uncoded).
  Core invalidates it: a resize clears it (turning the sheet keeps it), a lower
  Quantity truncates it, a nest material/grade/thickness change clears every
  plate's, ClearAll clears it and new plates never copy it.
- Desktop Auto Nest: after a kept proposal is committed, LedgerStockAssignment
  deals each ledger row's codes to its plates in Nest.Plates order (bundles
  repeat their code; clamp-removal variants use their base row). Rejected,
  discarded or cancelled proposals never reach it. NestPipelineCommit.PairWithStock
  pairs committed plates with their solved stock; the engine stays ledger-free.
- Plate list tooltip: "Stock: CODE (location)"; locations are display-only.
- nest.json: optional plate stockItemCodes, omitted when empty, read leniently.
- /api/nests/{id}/sheets: new plates[] { index, width, length, quantity,
  stockItemCodes }; sheets[] unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 17:40:44 -04:00
ajandClaude Opus 5.5 ea1decc097 feat(autonest): load sheet and drop stock from MaterialLedger
Auto Nest's Stock Options gets a Load from ledger button that reads the nest
material's free sheets and drops from MaterialLedger's API-key-protected
GET /api/stock/opennest. Ledger rows are request-local: the engine sees them as
ordinary NestPlateStock rows with ledger:{n} ids and finite quantities, and they
are never written to Nest.PlateOptions.

- OpenNest.Data/MaterialLedger: settings file, read-only client (X-Api-Key,
  5 s timeout, closed LedgerStockResult set) and LedgerStockMapper (bundles and
  sheets one row each, same-size drops grouped with ordered item codes, unknown
  shapes and too-small items skipped, inch/mm conversion).
- Options: MaterialLedger URL and API key (DPAPI, CurrentUser) with Test.
- Auto Nest grid: Use, Qty and Source columns for every row; PlateOption gains
  request-local Quantity and Id, which NestStockBuilder passes to the engine.
  Ledger rows score by area; hand-typed costs stay saved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 17:40:44 -04:00
ajandClaude Opus 5.5 f600c5e58b feat(desktop): nest released nests live in the main window
With Nest after release ticked, Make Nests now minimizes the Drawing
Sets window and nests each group's built nest in its own main-window
tab, before it is saved, with Auto Nest's progress window and live plan
strip, one nest at a time in plan order. Stop there (or switching tabs)
stops the whole release, as the panel's Stop does; the layout is kept
by the same rules as the headless renest, without the Keep review.

After upload each tab is bound to its saved record instead of a second
tab opening; a tab whose nest was not saved is closed. The main window
stays in front, and the Drawing Sets window flashes its taskbar button
when a group failed or was refused or the release was not recorded.

NestRenest splits into CreateRequest and Keep so the solve runs off the
UI thread and the commit on it; AutoNestCommand's solve-with-progress
step is shared rather than copied.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 21:21:28 -04:00
ajandClaude Opus 5.5 27796851f3 feat(desktop): build releases in a panel beside the Drawing Sets lists
The modal release dialog is replaced by ReleasePanel, docked beside the
Library and Sets tabs and shared by both. A double-click or Enter adds a
set at one kit or a library drawing on its own at the entered quantity;
adding one already listed adds to its quantity. Lines are edited in
place with a remove button, and the nests it will make preview live.

Each group now merges into a matching Draft nest by default: the only
one, or the most recently saved of several (chosen in the row); a draft
open in a tab blocks Make Nests instead of making a parallel nest.
Nest after release is remembered per user. Edit Set and Edit Drawing
move to their buttons and right-click menus.

The Drawing Sets window is now an unowned top-level window with its own
taskbar entry and remembered bounds, closed with the main window; a
release not yet made survives closing it, and Make Nests brings the
main window forward. ReleaseSetForm remains as a thin dialog host for
releasing from Nest > Add from Drawing Library.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 21:21:27 -04:00
ajandClaude Opus 5.5 d4269c1f06 refactor(cutting): merge circle lead settings into internal leads
Full circles now take InternalLeadIn/InternalLeadOut like every other
cutout; the ArcCircle lead settings and the cutting panel's Arc / Circle
tab are removed. Circle-specific geometry handling (radius clamp, angle
rounding, pierce zone) is unchanged.

Older nest files and desktop settings still load: their arcCircleLeadIn/
arcCircleLeadOut keys are ignored and no longer written, so re-planned
circles take the internal leads. Saved part programs are untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 21:20:09 -04:00
ajandClaude Sonnet 5.5 a6056a6065 feat(desktop): Drawing Library is a tab of the Drawing Sets window
The drawing library browser becomes DrawingLibraryView, a control. The Drawing
Sets window hosts it as its Library tab beside Sets and Releases, and File >
Drawing Library opens the window on it. A library drawing's Releases item
switches to the Releases tab filtered to it. Nest > Add from Drawing Library
stays a dialog, now a thin wrapper around the same view.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 15:54:54 -04:00
ajandClaude Opus 5.5 87672543cd feat(desktop): import a BOM into a drawing set
Drawing Sets > More > Import BOM reads a BOM and its drawing folder,
matches each drawing to the library by its D4 identity and geometry
(reuse, new revision, or new drawing) and opens the set editor with a
new set prefilled with the BOM quantities. Reading only queries the
library; Create Set lists the uploads and revisions and asks before
storing them, and the set is stored only by the editor's Save.

Parts with no material or thickness still import and are flagged for
Edit Drawing. DrawingPackage.GeometryKey compares geometry independent
of the fresh entity ids each DXF import assigns. In Database mode File >
Import BOM opens this flow instead of creating nests directly; File mode
is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 15:33:13 -04:00