fix(cam-lower): refuse invalid path length up front #128

Merged
patman merged 3 commits from patman/path-length-guard into main 2026-08-24 02:25:36 +00:00 AGit
Owner

Hardening: PathEval::eval clamps s against total_length and f64::clamp panics on a NaN bound AND on min>max. PathEval::new now refuses per-piece negative lengths (NegativePathLength{piece} — hand-built negative-radius Arc route) and non-finite/overflowed running sums (NonFinitePathLength{piece}), each attributed to the first offending piece. Zero-length pieces adjudicated legal and pinned by test so the guard is never silently widened. eval hot path untouched (bit-identity verified). Discovered via a NaN-fixture test in the SE(3) stack hitting the clamp before its own guard. Opus review PASS (condition: negative route — closed).

Hardening: PathEval::eval clamps s against total_length and f64::clamp panics on a NaN bound AND on min>max. PathEval::new now refuses per-piece negative lengths (NegativePathLength{piece} — hand-built negative-radius Arc route) and non-finite/overflowed running sums (NonFinitePathLength{piece}), each attributed to the first offending piece. Zero-length pieces adjudicated legal and pinned by test so the guard is never silently widened. eval hot path untouched (bit-identity verified). Discovered via a NaN-fixture test in the SE(3) stack hitting the clamp before its own guard. Opus review PASS (condition: negative route — closed).
fix(cam-lower): refuse invalid path length up front
Some checks failed
CI / build-test (pull_request) Failing after 5s
b7206ce4fb
PathEval::eval clamps the query arc length against total_length, and
f64::clamp panics both when its bound is NaN and when min > max. A
hand-built BlendedPass (its fields are pub) could reach either: NaN
geometry gives a NaN total, and ContourSegment::length is radius *
|sweep| with no absolute value on radius, so an Arc{radius: -1 m} has a
finite NEGATIVE length. Both aborted the process instead of reporting an
error; a negative length also breaks the monotonicity find_piece's
partition_point requires, silently selecting the wrong piece.

PathEval::new now rejects a negative piece length with the new
LowerError::NegativePathLength { piece }, and checks the running
cumulative length and quadrature bias after each piece for
LowerError::NonFinitePathLength { piece } — which also covers a finite
length overflowing the sum. Separate variants because the causes differ
in kind: inverted geometry vs lost precision.

Zero-length pieces stay legal (clamp(0.0, 0.0) is well-defined, the
search predicate stays monotone across them, and eval_host already maps
them to u = 0), pinned by its own test so the guard is not widened to
<= 0.0 by accident. Contour::new rejects both negative radii and
sub-tolerance segments, and blend_pass only trims a host when its length
exceeds twice the total trim, so no sanctioned pass reaches any of this.

eval's hot path is untouched: a 41-sample eval golden over a blended
rounded-rect pass (position, tangent, curvature, curvature rate, plus
total length and length bias) is bit-identical before and after.

Co-authored-by: patman-assist <patrick-ai@kgroo.co>
chore: normalize comments
Some checks failed
CI / build-test (pull_request) Failing after 5s
facbd99197
Co-authored-by: patman-assist <patrick-ai@kgroo.co>
style: rustfmt --edition 2024 drift fix
All checks were successful
CI / build-test (pull_request) Successful in 8m44s
afebbb8f09
Reformats files that predate the runner's current rustfmt; no code changes.

Co-authored-by: patman-assist <patrick-ai@kgroo.co>
patman merged commit 0c2c17dc23 into main 2026-08-24 02:25:36 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
patman/KGROO!128
No description provided.