Commit Graph
1692 Commits
Author SHA1 Message Date
ajandClaude Opus 5.5 7949d41b6d feat(core): pinned contour preparation
PreparedContours.Capture(program, parameters, pins) takes CutPinResolver
results for the same contours and fixes every resolved pin's contour: its
one and only entry is the pin's point, and it is emitted through the
existing emitter with the pin's own lead-in, lead-out and tab (angle
rounding off, so the entry never moves). Every catalogue returns the pinned
entry alone and emission refuses any other entry for that contour, so no
search path can relocate it. The certified tab size is the pinned outside's
own, so a pinned tab gap is genuine and replay certifies it. Unpinned
contours keep the shared settings and automatic selection; without pins the
existing preparation is untouched (5.1 digests unchanged).

Capture now resolves a regenerated part's drawing pins. A pin that does not
resolve (not on a contour, on several, sharing one, or unplaceable) is never
guessed: its contour stays automatic and the plate gets a FixedLead warning
naming the pin, making the proposal UNVERIFIED. A tab pinned on an internal
contour cannot be cut as pinned (only the outside is tabbed) and warns the
same way. Pins-off, locked parts with pins and freshness follow in 5.4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:24 -04:00
ajandClaude Opus 5.5 d56f67a99a feat(engine): fixed-lead violations warn instead of refusing
D1a (user, 2026-10-14): one locked cutout must not refuse the whole layout.
With confirmed parameters a locked program is now a fixed emission, accepted
as given. The replay checker and the lead validator take a per-motion owner:
a violation inside the fixed emission (a lead meeting another part's or its
own material, a rapid inside the locked program crossing a cut contour, an
uncertifiable tab gap or a partial/reversed/retraced cut) is recorded apart
instead of failing the candidate. The search never rejects or learns an order
rule from them, so fixed emissions never steer it; the planner's rapid into
the locked program and every regenerated lead keep every strict check.

Replay turns those violations into typed FixedLead findings that name the
part, contour and the part hit. A plate whose only findings are these is
BestEffort with IndependentlyReplayed set: never Ready, applicable only with
the per-proposal acceptance, and CuttingPlanService.Apply still rejects it.
Overlap, unreadable programs, stale input and cancellation still block, and
unlocked programs a caller left ineligible and the no-parameter route keep
refusing as before.

Pre-post review now re-checks locked leads against every part's clean
material, so the same violations reappear before posting.

Existing tests that encoded the old locked refusal now assert the warning;
two batch tests that used a locked crossing as their hard block use an
overlap instead. The 5.1 digests are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:23 -04:00
ajandClaude Opus 5.5 36ba3c2d6b test(engine): planning characterization
Freeze what Plan Cutting produces today before pins and fixed-lead warnings
touch the planner: the six synthetic nests (placed deterministically, every
other part turned a quarter) and five focused fixtures go through the desktop
batch, and the proposals, expansions and every emitted motion are hashed.
Coordinates are rounded to six decimals so last-bit libm differences between
platforms cannot move a digest. OPENNEST_PLANNING_DIGESTS appends the computed
digests to a file for the slice record.

Two red rows record today's refusals that D1a will turn into warnings: a
locked hole lead that runs into a part nested in that hole, and a locked
tabbed perimeter under confirmed parameters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:22 -04:00
ajandClaude Opus 5.5 d9b8f054cc feat(core): mismatch drop and part copy
Two remaining pin rules from the drawing library plan:

- D3: a library drawing added to a nest whose material, grade or
  thickness differ from the library record now really arrives without
  its cut pins. The insert already warned and reported KeepPins = false;
  it now clears the copy's pins, because they were authored for the
  library material and thickness. The library link still records the
  revision the copy came from.
- A copy of a placement (Clone, CloneAtOffset) keeps its drawing pins
  off, so copying or patterning an overridden part does not silently
  bring the drawing's pins back. Clearing lead-ins keeps it too: pins-off
  is a placement choice, not lead-in state.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:22 -04:00
ajandClaude Opus 5.5 734346eeec test(core): pin frame lifecycle
Proves the source-to-program mapping the pins rely on (plan policy: prove
it or stop): the program frame is the source frame moved by
-Source.Offset, never rotated in place; a placement rotates it about the
program origin and adds the part location. Source.Angle is canonical
metadata and plays no part.

The oracle does not use Source.Offset or part rotation bookkeeping. It
recovers the rigid source-to-plate transform from the placed geometry
itself, using two holes of different sizes, and checks every pin at 0,
90 and 37 degrees, placed directly and the way engines place parts
(CreateAtOrigin), after:
- import (BuildDrawing re-origins at the first rapid);
- a converter edit that hides the first-cut hole and so moves
  Source.Offset;
- a converter edit of a drawing without source entities (the derived
  entities are moved back by Source.Offset);
- save and reload;
- a drawing package round trip.

To exercise the real converter paths headlessly, the desktop's entity
load and in-place apply move into CadImporter.EditableEntities and
CadImporter.ApplyEdit, unchanged; the in-place apply keeps the library
link and cut pins as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:21 -04:00
ajandClaude Opus 5.5 0f06748f28 feat(io): persist pins and pins-off
Drawing cut pins and the per-placement pins-off flag now survive
save/reload and travel in drawing packages.

- `DrawingDto.cutPins` reuses the plate cutting-parameter lead and tab
  DTOs. Pins are read strictly per entry: an unknown lead or tab type is
  never replaced by a default, because a pin that cut differently from
  what was saved is worse than no pin. A bad entry is skipped with a
  reader warning naming the drawing and pin, and the rest load; a value
  that is not a list loads no pins, with a warning. A nest never fails to
  open over pins.
- `PartDto.drawingPinsOff` is written only when true. Anything other than
  a boolean loads as pins on (the drawing wins, D1) with a warning naming
  the plate and part, so an operator's override is never lost silently.
- Packages carry pins as drawing content, so pinning a drawing changes
  its package hash and the newer-revision notice can tell geometry/pins
  changes from detail-only ones.
- `Part.DrawingPinsOff` holds the flag; nothing plans with it yet.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:21 -04:00
ajandClaude Opus 5.5 1bd0b258af feat(core): contour cut pins
A library drawing can say how individual contours must be cut. A
`ContourCutPin` holds the entry point in the drawing's source frame plus
the lead-in, lead-out and optional tab used there; `Drawing.CutPins`
lists them. Nothing plans with pins yet (Slice 5).

- Pins accept only the exact built-in lead and tab types, copied through
  the same owned copiers the planner uses, so a pin cannot carry a type
  the emitter would not certify. Properties return copies: the pin is
  immutable.
- A tab requires no lead-out, because the planner refuses a lead-out
  after an open contour.
- The source frame is the frame of the source entities. It does not move
  when BuildDrawing re-origins the program at its first rapid, so pins
  survive converter edits that change Source.Offset.

`CutPinResolver` maps pins to (contour ordinal, entity ordinal, local
point) for a placement rotation, using the same `PreparedContours`
ordinals Plan Cutting will use. It never guesses: a pin must lie within
the contour closure tolerance of exactly one contour that no other pin
claims, otherwise it is reported unresolved with a typed reason. A
drawing program rotated in place (a canonical copy) is not the source
frame and resolves nothing; canonical copies and split pieces carry no
pins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:20 -04:00
ajandClaude Opus 5.5 2aecafb356 feat(desktop): Save to Drawing Library dialog
Operators can now save a nest drawing to the shared drawing library. Right-
click a drawing in the drawing list > Save to Drawing Library... opens a
dialog with name, customer, material (post materials suggested), grade,
thickness, cut type and notes, prefilled by the save model; units follow the
nest.

Whenever the details change, the dialog looks up library drawings with the
same details and offers Save as: the next revision of the match (the default
for one match or the linked drawing), a choice among several, or a separate
drawing. Save stays disabled until the lookup for the current details has
finished, so a choice can never apply to details it was not made for. A 409
is shown and the choices are refreshed; a save that could not be confirmed
tells the operator that saving again checks it and never stores it twice.

On success only the drawing's library link changes, and the chosen cut type
is remembered per PC. There is no nest dirty flag to set, so the operator
saves the nest to keep the new link. The item is Database mode only and is
shown only where the drawing list's host handles it (not the best-fit viewer).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:20 -04:00
ajandClaude Opus 5.5 f93b0d6273 feat(data): library save model
Saving a nest drawing to the drawing library now has a Linux-testable model,
DrawingLibrarySaveSession, ahead of the desktop dialog.

Prefill starts from the drawing's name and customer (the nest's customer when
the drawing has none), the nest's material, grade, thickness and units, and the
linked revision's cut type and notes when the drawing came from this server's
library, otherwise the operator's last-used cut type.

Duplicates follow D4: active drawings whose normalized customer, name, material
and grade and exact thickness, units and cut type match. The server only
narrows (a blank filter means "any" there, and LIKE does not collapse
whitespace), so every key is checked again on the client. The default is the
linked drawing when it matches, else the only match; several matches require
the operator to choose, and a linked drawing that no longer matches is offered
but never the default, so a thickness change cannot silently rewrite it.

Writes follow NestSaveSession: a new drawing's id is allocated before the
upload, and a save that fails without a definite answer stays pending. The
next save first looks for the revision it would have produced and adopts it
when the package hash and details match; a not-stored new drawing is retried
under the same id, never onto another drawing, and a revision someone else
saved meanwhile is a conflict. A definite refusal (409, old server, invalid
request) leaves nothing pending. On success the drawing's link points at the
saved revision; nothing else in the nest copy changes (D2).

RemoteDrawingLibrary now implements IDrawingLibraryStore, the read/write
surface the session needs, so tests can use an in-memory store.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:19 -04:00
ajandClaude Opus 5.5 a1bd44d0fa feat(desktop): Add from Drawing Library
Operators can now pull shared library drawings into a nest. Nest > Add from
Drawing Library... and a Library button above the drawing list open a paged
browser (name, customer, material, grade, thickness, cut type, revision, saved)
with a notes preview and a quantity. It starts filtered to the nest's material,
grade and thickness, with Show all to lift that.

Add downloads the listed revision's immutable package, not the current one, so
a revision saved meanwhile can never be what lands in the nest. The insert is
planned first and every warning or refusal is shown before the nest changes;
the dialog is modal, so the nest cannot move between plan and apply. The dialog
stays open for further adds and the drawing list refreshes on close.

Both entries are Database mode only: the library lives on the nest server, so
in File mode they are disabled with a "Database mode only" tooltip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:19 -04:00
ajandClaude Opus 5.5 175782d8f8 feat(data): library browse session
Add from Drawing Library needs the same race-safe paging as the Database-mode
Open dialog: a generation counter so an older response never replaces a newer
one, cancellation after the superseding request is installed, and IsLoading
tracking only the latest request. `DrawingLibraryBrowseSession` mirrors
`NestBrowseSession` for library queries.

It starts filtered to the nest's material, grade and thickness, since that is
almost always what the operator wants and a mismatch drops cut pins anyway
(D3). "Show all" lifts the filter. A nest with no thickness filters by material
only, and the empty-result text tells the operator when the nest filter, rather
than an empty library, is why nothing is listed. Archived drawings stay hidden.

`IDrawingLibrary` is the read side the session and the add flow use, so both
are testable with fakes; `RemoteDrawingLibrary` implements it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:18 -04:00
ajandClaude Opus 5.5 4dbb4527e2 feat(data): library insert model
Adding a library drawing to a nest has several outcomes that must be decided
before anything changes, so the desktop can show warnings first and so every
rule is tested on Linux. `LibraryDrawingInsert.Plan` returns a new exact copy
carrying its library link, an added quantity on the copy already there, or a
refusal that leaves the nest untouched.

- Material, grade or thickness that differ from the nest still add the drawing
  but drop its cut pins, with one warning naming each difference (D3). Names
  compare by SharedListNames key and thickness at four decimals, matching the
  server's own filters.
- Different units are refused: conversion is out of scope and a silent unit
  mismatch would scale the part.
- The same revision from the same server only raises the quantity; a different
  revision of that drawing is refused in favour of Update Drawings (D2b).
- Another drawing with the same name is refused naming both, because the
  name-keyed DrawingCollection would otherwise drop one silently.
- A package whose hash or units disagree with its record is refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:18 -04:00
ajandClaude Opus 5.5 15654c0690 feat(core,io): drawing library link
A nest drawing copied from the drawing library has to remember exactly which
revision it is a copy of, so later slices can tell when the library moved on
(D2b) and so a save can target the right drawing. `Drawing.Library` holds the
server key, id, revision and a snapshot of that revision's cut type, thickness,
material, grade, units, notes and package hash. It is immutable, so copies can
share it.

`DrawingDto.library` is additive and omitted when null. It is read leniently:
anything that cannot be trusted as a link drops the link with a reader warning
and the drawing still loads, because a nest must never fail to open over
provenance. Enum names are checked as single names since Enum.TryParse would
accept numbers and comma lists.

Copy paths: converter edits update drawings in place and so keep the link;
canonical engine copies carry it; split pieces are new geometry and get none.
Packages strip it so linking never changes a drawing's package bytes or hash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:17 -04:00
ajandClaude Opus 5.5 8b63c042b5 test(server): drawing library end to end
Proves Slice 1's contract through the production routes and the real client:
a code-built drawing is packaged, uploaded, found by cut type, material, grade
and thickness among decoys, downloaded and read back with identical program
text; a stale If-Match update raises a conflict and leaves the current
revision, its package hash and the history unchanged. Archive, restore,
metadata edits and duplicate ids are exercised the same way.

Documents the /api/drawings contract, schema v4 and the fact that the backup
manifest and restore check do not yet verify drawings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:03 -04:00
ajandClaude Opus 5.5 0c1eb3ad65 feat(data): drawing library client
RemoteDrawingLibrary covers upload, query, get, package download, revisions,
revision packages, guarded package/metadata updates, archive and restore. It
checks the shared bounds before sending, refuses oversized or inconsistent
pages, and verifies that the server stored the exact package it sent.

A 404 on the library routes means the server predates them: the client raises
ServerTooOldException and never falls back to another store. Because a 404 for
one drawing is ambiguous, it probes the query route before deciding between
"unknown drawing" and "server too old". Conflicts raise
DrawingLibraryConflictException carrying the current record, which the save
flow needs to offer a reload or the next revision.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:03 -04:00
ajandClaude Opus 5.5 3c577d4ac7 feat(io): drawing package
Library drawings travel as a single-drawing, zero-plate .nest archive so the
server stores opaque bytes and the client reuses NestWriter/NestReader. A
characterization test first proves that shape round-trips the program, hole
programs, source entities and suppression, offset, material, bends and units.

Packages are canonical: fixed archive and nest timestamps, zero nest quantity
and no best-fit caches. The same drawing content therefore has the same bytes
and SHA-256, which later revision checks rely on to tell geometry changes from
detail-only edits. Read checks the archive's own declaration before the lenient
nest reader, which would otherwise default unknown units and drop empty plates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:02 -04:00
ajandClaude Opus 5.5 76133193df feat(server): drawing library schema and routes
The server becomes the system of record for shared drawings (cut type,
thickness, material and grade, customer, notes). Schema v4 adds `drawings`
(current row) and `drawing_revisions` (immutable) to the same SQLite file under
the existing monitor; the nest tables are untouched and a v3 upgrade keeps every
nest row byte-identical.

`/api/drawings` follows the nest revision contract: client-allocated ids,
If-Match on every existing-drawing write (428/400/409 with no state change),
archive instead of delete, and one transaction for promotion plus snapshot.
Geometry is an opaque package (a zero-plate .nest) the server never parses.
Enum fields accept single names only, because the JSON enum converter would
otherwise accept numbers and comma combinations. Material, grade and customer
filters match SharedListNames keys so spacing and case cannot split a drawing
family; thickness is stored and compared at four decimals.

Shared bounds live in OpenNest.Data so the client can refuse the same requests
before sending. If-Match parsing moves to one helper used by nests and drawings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:02 -04:00
ajandClaude Opus 5.5 0ee5b9d93e refactor(data): share server URL validation
The drawing library client needs the same base-address rule as the nest
repository. Extract it into one internal helper so both clients accept and
reject exactly the same addresses. Behavior is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:33:02 -04:00
ajandClaude Opus 5.5 7a5c06bc99 fix(bestfit): bind loaded pair candidates to a canonical copy
Saved pairs are in the drawing's canonical frame, but loaded candidates
held the source drawing, so BuildCanonicalParts/BuildSourceParts rebuilt
a different pair for any drawing with a non-zero canonical angle (a 30
degree T-shape came back 16.57 x 10.39 instead of its saved 16.92 x 8).
That reached the Irregular engine's pair catalog and the best-fit viewer
after opening a saved nest. Import now binds every candidate to one
canonical copy, as computed candidates are; fills already passed the
canonical drawing explicitly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 15:05:43 -04:00
ajandClaude Opus 5.5 844f360732 docs: document saved best-fit entries and IO's Core-only dependency
The bestfits/ archive entry was undocumented. Describe its JSON shape,
that it is an optional cache readers may ignore, and that it is read or
written only when a caller supplies an IBestFitStore.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:54:45 -04:00
ajandClaude Opus 5.5 2d5bf6f42c build(io): drop OpenNest.IO's reference to the engine
IO only needed Engine for the best-fit cache, which now goes through
IBestFitStore. Removing the reference stops every IO consumer pulling in
the engine and ONNX Runtime. A guard test keeps the assembly from
referencing it again; IO.Tests references Engine itself for its whole-job
round-trip tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:54:44 -04:00
ajandClaude Opus 5.5 6e66a1efe7 refactor(io): persist best fits through an explicit IBestFitStore
Reading a nest used to fill the engine's static BestFitCache as a side
effect, which is the only reason OpenNest.IO referenced OpenNest.Engine.
Core now defines SavedPairSet/SavedPairResult and IBestFitStore; the
mapping to BestFitResult moved verbatim into Engine's BestFitCacheStore.
NestReader/NestWriter take the store as an optional BestFitStore property
and skip bestfits/ entries without one.

Every production reader and writer opts into BestFitCacheStore.Shared, so
behaviour is unchanged; the golden round-trip test still matches byte for
byte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:54:43 -04:00
ajandClaude Opus 5.5 063362a674 test(io): pin best-fit round trip through .nest archives
Characterize the bestfits/ entries before moving their mapping out of
OpenNest.IO: golden bytes for hand-built sets, field-by-field restore of
hand-built and computed sets (kept results and used plate sizes only), a
nest without saved best fits, and the loaded-candidate frame on a rotated
source drawing, which today rebuilds to a different pair than its saved
bounds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 14:37:15 -04:00
ajandClaude Opus 5.5 4e0699de7a fix(rectangles): break exact material-area ties the same way on every platform
ZeroClampMixedShapeLayoutIsBitIdenticalToBaseline has failed on Windows since
it was added in de9a087 while passing on Linux CI (bisect pointing at
c374e02 was an artifact: the assumed-good start commit fails too). No
commit changed the layout; the two platforms always chose differently.

In that fixture two candidate sheets (ContactPoint/Global and
BestShortSide/Ordered) both place all 30 parts at the same cost, so Choose
falls to its "more material placed" tie-break. SheetPacker summed material
area in placement order, and the disc's area differs in the last bit
between the Windows CRT and glibc math libraries. On Linux the two orders
rounded to ...253 vs ...257, so the later candidate won on rounding noise;
on Windows both rounded to ...257 and the tie fell to enumeration order as
Choose documents.

Sum a plan's area per type in type order instead (the same form as the
engine's demand area), so plans placing the same parts get bit-identical
areas and exact ties keep enumeration order everywhere. No tolerance is
loosened. The Windows layout is unchanged; Linux now matches it, so the
frozen hash moves to the Windows value, verified identical on both.

Verified: full Engine.Tests pass on Windows and Linux (1105 passed, 2
skipped); Rectangles and Default benchmark results on the six synthetic
nests are identical before and after (validity, placed parts, cost,
utilization, plates).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 13:20:20 -04:00
ajandClaude Opus 5.5 9f627c1a9d build(mcp): target net8.0 and pin package versions
The MCP server uses no Windows APIs, so net8.0-windows only kept it from
building on Linux. Floating 0.*-* / 9.* versions let a restore silently pick
up a new ModelContextProtocol preview; pin the currently resolved versions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 13:15:52 -04:00
ajandClaude Opus 5.5 7600d75f41 refactor(desktop): stop shipping the unused GPU evaluator
The GPU hooks in MainForm were commented out, so ILGPU only powered a
status-bar label that reported a GPU device the nesting never used. Removing
the reference drops OpenNest.Gpu and ILGPU from the desktop output. The GPU
kernel tests reference OpenNest.Gpu directly; Training still uses it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 13:15:50 -04:00
ajandClaude Opus 5.5 90a6d9e4d2 refactor(core): drop System.Drawing.Common and fix CutParameters namespace
Core only uses System.Drawing.Color, which ships in the shared framework, so
the System.Drawing.Common package (Windows-only beyond primitives) was an
unneeded dependency of the cross-platform domain library. The desktop app
keeps its own reference.

CutParameters lives in OpenNest.Core but declared namespace OpenNest.Api,
forcing Core and desktop files to import the Api namespace for a Core type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 13:15:48 -04:00
aj 19adfbcfbd merge: drop the orange banner during part-order search 2026-10-16 11:21:34 -04:00
ajandClaude Opus 5.5 2ea201140b fix(desktop): drop the orange banner during part-order search
The saturated orange Busy tone broke the panel's single alert style and
read as a warning while planning was simply running. The part-order
search now shows the same neutral banner as the other planning phases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:21:33 -04:00
aj 6bf0658d68 merge: ask for a new nest name on database Save As 2026-10-16 11:18:28 -04:00
ajandClaude Opus 5.5 4e95a09706 feat(desktop): ask for a new nest name on database Save As
Database Save As uploaded the copy under the same name as the original,
so the saved nests list showed two indistinguishable entries. It now
prompts for the copy's name first (prefilled with the current one) and
cancelling aborts the save. The prompt is skipped while a lost upload
is being reconciled, since that click never writes. If the upload fails
outright the original name is restored, so a later Save cannot rename
the original nest; it is kept only while the copy may still be pending.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 11:18:28 -04:00
aj 37ddf1b7b2 merge: continue strip lines into a tail too short to keep 2026-10-16 10:40:05 -04:00
ajandClaude Opus 5.5 75195e8ba4 fix(cutoffs): continue strip lines into a tail too short to keep
When the end tail was shorter than the minimum tail to keep, the planner
dropped the separator but still stopped the strip grid at it, so the last
strip ran to the sheet end and could exceed the maximum spacing (e.g. a
39-inch strip from 105 to 144 with 35-inch spacing). The grid now spans the
whole sheet whenever the separator is skipped, keeping every strip within
the spacing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 10:40:04 -04:00
aj 274a1a1dea merge: show cut-plan status in a banner at the top of the panel 2026-10-16 10:12:10 -04:00
ajandClaude Opus 5.5 91b693be90 feat(desktop): show cut-plan status in a banner at the top of the panel
The outcome line sat mid-panel in coloured text and was easy to miss. It
now leads the panel in a tinted, outlined banner, and the existing
lead-in/cut-off alert uses the same style so the panel has one alert
look. The part-order search turns the banner bright orange because it is
the slow phase the operator waits on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 10:12:09 -04:00
aj 648c0f1efc merge: replay seams whose bridge lengthens the cut 2026-10-16 09:55:49 -04:00
ajandClaude Opus 5.5 017e06de2d fix(cutting): replay seams whose bridge lengthens the cut
A nominal ring may close within NominalContourClosure.Tolerance, and replay
already carried that admitted gap as slack when bridging it shortens the cut.
When the gap instead lies across the following edge, the emitted path starts
that edge at the ring's end point, so the cut is longer by the gap. Two checks
still compared at the exact epsilon and refused it as "invalid input":

- the retrace guard rejected any surplus length beyond 1e-8;
- Follows matched the edge's leftover sliver against the next nominal entity
  and failed its direction check.

Both now use the ring's admitted slack, the same bound the shortfall and the
nominal side of Follows already use. Exactly closed rings keep the epsilon, and
a second circuit still exceeds the slack by a whole ring.

A0227-08's sprocket outline misses its start by 1e-6 and refused planning in
both keep-order and reorder modes; it now plans Ready and applies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 09:55:49 -04:00
aj 21e1aee342 merge: mark cut-plan issues on the plate, simplify the inspection panel and draw planned cut-offs 2026-10-16 09:20:30 -04:00
ajandClaude Opus 5.5 571776716f chore(desktop): add AutomaticCutOffForm designer resource file
Visual Studio generated the standard empty .resx for the form; every other
designer form keeps its .resx in source control, so track this one too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 09:20:29 -04:00
ajandClaude Opus 5.5 405a867a77 fix(desktop): draw planned cut-offs and issue markers on the plan preview
The proposal preview skipped the cut-off overlay: it carries cut-off parts but no
cut-off definitions, so planner cut-offs looked like thin black part outlines
instead of the orange-red dashes used everywhere else. The preview now draws each
cut-off part's own cutting moves in that style.

The same paint guard hid the validation overlay over a preview, so issue markers
for unverified plans were set but never drawn. The overlay now draws on proposals
too, with the marker's part numbers mapped to the preview's proposed order so the
right parts stay highlighted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 09:18:48 -04:00
ajandClaude Opus 5.5 c3fa8e79e0 feat(desktop): mark cut-plan issues on the plate and trim the inspection panel
Plan Cutting findings dropped the checker's geometry, so selecting one could only
zoom to part extents, and overlap-blocked plates (no preview) did nothing at all.
Findings now keep the check's world-coordinate witness (overlap regions, rapid,
contacts); selecting a row draws it with the Validate Nest overlay, on the proposal
or a blocked plate's live sheet. The witness is excluded from finding equality so
repeated search rejections still collapse to one finding.

The side panel's scrolling report was a wall of text operators skipped. It is now
a colored outcome line, one line for the shown plate, and one remedy or marker
hint above the issue grid, with secondary detail moved to tooltips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 09:11:13 -04:00
ajandClaude Opus 5.5 658c1c9ee3 style(desktop): give every data grid the nest browser's look
Grids across the desktop app each set their own borders, header styles
and selection colours, so tables looked different from form to form.
The database nest browser's grid style moves into a shared GridStyle
helper that the AutoNest, BOM import, options, nest history, cutting
inspection and post settings grids now apply too. The helper also fixes
row heights so users cannot resize rows; editing, selection and column
sizing stay with each grid.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 08:53:23 -04:00
aj 697b6492c7 fix(browser): integrate metadata-safe nest information edits 2026-10-16 06:52:33 -04:00
ajandClaude Opus 5.5 f05533f69c merge: integrate inspection-view navigation lock with live header zoom
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 06:46:12 -04:00
ajandClaude Opus 5.5 7d254ce18d feat(desktop): remove or restore a clamp by right-click
Operators sometimes pull a clamp for a manual layout, but only Auto Nest's
last-resort search could take clamps off a sheet. Right-clicking a clamp in
Select mode now offers to remove it from that sheet or put it back, reusing
the existing per-sheet RemovedClamps, so the zones, cut-time charge, display
and .nest persistence all behave as they do for Auto Nest removals.

The change is refused while a nest run or fill may be reading the clamps,
sharing the guard the Clamps dialog already used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 06:20:30 -04:00
aj b305b56876 test(browser): run asynchronous edits with the UI dispatcher 2026-10-16 00:18:55 -04:00
aj f4dd8d2a85 fix(browser): preserve all current nest metadata during edits 2026-10-16 00:07:37 -04:00
aj 9f0d4f37ce feat(browser): edit nest information without opening the nest 2026-10-16 00:03:32 -04:00
aj d028d82f0a fix(ci): follow the material-marker overlay acceptance test 2026-10-15 23:41:57 -04:00
aj ee3bc3aabe docs(geometry): align collision guidance with overlap diagnostics 2026-10-15 23:32:20 -04:00