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>
This commit is contained in:
ajandClaude Opus 5.5 committed 2026-10-16 09:55:49 -04:00
1 parent 21e1aee342
commit 017e06de2d
2 files changed
+35 -3

No files matched your search

@@ -75,12 +75,13 @@ internal static class ContourProgramVerifier
// Capture admits a nominal ring that closes within NominalContourClosure.Tolerance, and
// preparation agrees at that inclusive boundary. A rotated tool path bridges that one
// admitted joint, so this ring's positional and length agreement carries exactly that
// admitted slack. Direction, coverage order and retrace accounting stay at the epsilon.
// admitted slack, whether bridging it shortens or lengthens the cut.
var tolerance = AdmittedClosureSlack(ring);
var nominalLength = ring.Sum(c => c.Length);
var cutLength = run.Curves.Sum(c => c.Length);
var missing = nominalLength - cutLength;
if (missing < -Epsilon) return false; // Never a second circuit/retrace.
// Bridging the admitted joint may add up to its gap; a second circuit/retrace never passes.
if (missing < -tolerance) return false;
if (missing > tolerance)
{
// Fixed legacy payloads have no certified selected tab/entry metadata.
@@ -135,7 +136,9 @@ internal static class ContourProgramVerifier
foreach (var curve in actual)
{
var consumed = 0.0;
while (consumed < curve.Length - Epsilon)
// Like the nominal side below, a remainder within the slack is consumed: a path that
// bridges the admitted joint leaves exactly that much on the edge it extends.
while (consumed < curve.Length - tolerance)
{
Query(token, ref budget);
if (index >= expected.Count)