S1.4 — Library hygiene: remove println from library code

Intent

RRT's solve loop contains a stray println!("Solution found...") — library code must not print to stdout; output goes through Result types.

Acceptance criteria

Tasks

Grep evidence (2026-09-22)

grep -rn "println!\|eprintln!\|dbg!" oxmpl/src oxmpl-py/src oxmpl-js/src → no matches. All 6 library println! calls converted to log::debug! (rrt.rs ×1, rrt_connect.rs ×2, rrt_star.rs ×1, prm.rs ×2). The ~100 println! in tests//examples//docs/ are intentionally untouched — binaries may print.

Completion record (2026-09-22)

Change: log = "0.4.34" facade (no features, no concrete logger — binaries decide), 6 call-site conversions. cargo test -p oxmpl 28/28 binaries + 15 doc-tests green; cargo check --workspace clean.

Defects found & fixed during verification (ship in the same PR as this story):

  1. oxmpl-py/tests/test_prm_so3ss.py — deterministic failure (4/4 pre-fix). Root cause: pyo3-bound checker (~122k calls/s) starves the 5s wall-clock PRM construction budget; roadmap too sparse to detour the forbidden cone. Fix: space.set_longest_valid_segment_fraction(0.25) in-test. Suite 30/30 green.
  2. oxmpl-js/tests/test_prm_compound.test.js — load-dependent flake (failed 2/2 full-suite runs, passed solo). Same mechanism, 2s budget, wasm boundary. Fix: setLongestValidLineSegmentFraction(0.25) on both subspaces pre-build. Full JS suite green 3/3 after.

Final gate: just test-all fully green (Rust + Python 30/30 + JS 26/26) in one pass.

Follow-ups filed (sprint-002 candidates, see S2.1 / S2.2): deterministic milestone-count termination (root cause of both failures above — protects the S1.5 release gate), and the ×0.1 motion-check oversampling in all four planners (10× throughput win for binding users). Interim test fixes give ~4–5× headroom but do not eliminate the wall-clock dependence.