fix(cam-lower): refuse invalid path length up front #128
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "patman/path-length-guard"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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).
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>