S4.4 — Motion validator trait and discrete validator
Intent
Motion validation is today four private check_motion copies with a hidden ×0.1 oversampling factor (each step is longest_valid_segment_length × 0.1). Replace them with a public, pluggable MotionValidator and a default DiscreteMotionValidator, modelled on OMPL. Planners build the default internally in this story; how users attach their own validator is S4.5. Supersedes the rest of S2.2 (cancelled).
Decisions (ADR-0003)
- Glossary (
CONTEXT.md§ Validity): a motion is the transition traced by the space'sinterpolate; motion validation decides whether every state along it is valid, assuming the start is valid; resolution is owned by the space; checking strategy is owned by the validator, which may ignore the space's resolution. - Trait:
pub trait MotionValidator<S: State>: Send + Sync { fn check_motion(&self, s1: &S, s2: &S) -> Result<bool, UserError>; }. Object-safe (used asArc<dyn MotionValidator<S>>). - The trait docs state from day one that s1 is assumed valid (needed so a later last-valid method can default soundly).
- Exactly one required method. OMPL's second overload (last valid state + fraction) is deferred; when a planner needs it, it arrives as a provided method
check_motion_last_valid(&self, s1, s2) -> Result<Result<(), f64>, UserError>(exact shape decided then) defaulting toErr(0.0)on failure. Do not add it now. - No valid/invalid counters in the trait (a decorating validator can count later).
DiscreteMotionValidatorholds the space and the state validity checker; uses the space'svalid_segment_count(S4.3); checks s2 first, then interior states in bisection (BFS-midpoint) order, as OMPL'sDiscreteMotionValidator::checkMotion(s1, s2). Linear order is the cut-fallback if bisection slips.- The default validator is always the discrete one; per-space defaults (e.g. Dubins) may come later as a provided
StateSpacemethod.
Acceptance criteria
Tasks
Risks
- Behaviour drift: tests with tight geometry may start passing or failing differently because effective resolution changes (2× coarser for single spaces, finer for compound). S4.1's budgets absorb the PRM side; check RRT-family tests individually.
Source
Agreed in the senior-engineer grilling 2026-10-08 (decisions: repo docs/planning/adr/0003-motion-validation.md; glossary: CONTEXT.md). Regeneration spec: oxmpl - sprint-004. Line references are as of origin/main c558556 (2026-10-08), before E3. E3 renames things (rand Rng→RngExt, PyO3 with_gil→attach, edition 2024), so re-grep before trusting a line number.