From 50136c920d6297d4422d70cb9e04a184ae08b315 Mon Sep 17 00:00:00 2001 From: rUv Date: Sun, 17 May 2026 19:34:08 -0400 Subject: [PATCH] fix(archive/v1/pose-service): call sanitize_phase, not sanitize (closes #612) (#614) Reported by @bannned-bit. archive/v1/src/services/pose_service.py:223: sanitized_phase = self.phase_sanitizer.sanitize(phase_data) PhaseSanitizer exposes the full-pipeline entry point as `sanitize_phase` (unwrap_phase + remove_outliers + smooth_phase), not `sanitize`. The shorter name doesn't exist on the class, so any path that reaches this branch raises AttributeError mid-frame and crashes the pose service. archive/v1/src/core/phase_sanitizer.py:266 is the canonical name: def sanitize_phase(self, phase_data: np.ndarray) -> np.ndarray: """Sanitize phase data through complete pipeline.""" One-line rename. No other call sites use the wrong name; verified with grep -rn 'phase_sanitizer\.sanitize\b' archive/v1/src/. This is v1 archived code, but the proof verify path still exercises it (./verify reaches into archive/v1/src/), so the bug was a latent regression risk for the trust-kill-switch flow. --- CHANGELOG.md | 1 + archive/v1/src/services/pose_service.py | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2db4593..9ee7ab9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Fixed +- **`archive/v1/src/services/pose_service.py:223` calls the right method on `PhaseSanitizer`** (closes #612). The call was `self.phase_sanitizer.sanitize(phase_data)`, but `PhaseSanitizer`'s full-pipeline entry point is named `sanitize_phase()` (`unwrap_phase` + `remove_outliers` + `smooth_phase` chained, see `archive/v1/src/core/phase_sanitizer.py:266`). The shorter `sanitize` name doesn't exist on the class, so any path that reached this branch raised `AttributeError` and crashed the pose service mid-frame. - **`adaptive_classifier.rs:94` no longer panics on NaN feature values** (closes #611). `sorted.sort_by(|a, b| a.partial_cmp(b).unwrap())` returned `None` and panicked whenever a single `NaN` reached the classifier from real ESP32 hardware (silent diff --git a/archive/v1/src/services/pose_service.py b/archive/v1/src/services/pose_service.py index f5013c1e..436c21f8 100644 --- a/archive/v1/src/services/pose_service.py +++ b/archive/v1/src/services/pose_service.py @@ -220,7 +220,11 @@ class PoseService: # Apply phase sanitization if we have phase data if hasattr(detection_result.features, 'phase_difference'): phase_data = detection_result.features.phase_difference - sanitized_phase = self.phase_sanitizer.sanitize(phase_data) + # PhaseSanitizer's full-pipeline method is sanitize_phase, + # not sanitize (issue #612). The shorter name was an + # AttributeError waiting to fire on any code path that + # reaches this branch. + sanitized_phase = self.phase_sanitizer.sanitize_phase(phase_data) # Combine amplitude and phase data return np.concatenate([amplitude_data, sanitized_phase])