Skip to content

feat(hotas-virpil): add protocol parser, button matrix, and axis curves#63

Open
EffortlessSteven wants to merge 2 commits intomainfrom
feat/virpil-protocol
Open

feat(hotas-virpil): add protocol parser, button matrix, and axis curves#63
EffortlessSteven wants to merge 2 commits intomainfrom
feat/virpil-protocol

Conversation

@EffortlessSteven
Copy link
Member

@EffortlessSteven EffortlessSteven commented Mar 1, 2026

Summary

Implements Virpil device protocol support for OpenFlight.

Devices Covered

  • Virpil Alpha Grip (128 buttons, twist)
  • Virpil WarBRD/CM3 Base (high-resolution axes)
  • Virpil MongoosT-50CM3 Throttle (dual throttle)
  • Virpil ACE Pedals (rudder + toe brakes)

Changes

  • protocol.rs: Device family enum, unified protocol handle, and generic report parsers (grip/base/throttle)
  • button_matrix.rs: Physical→logical button matrix resolver with shift layer support
  • axis_curves.rs: Firmware axis curve reading and application with linear interpolation

Tests

264 tests passing: 234 unit + 25 property + 4 snapshot + 1 doctest

- Virpil USB HID protocol parsing for Alpha, WarBRD, MongoosT, ACE Pedals
- Button matrix resolver for shifted/layered inputs
- Axis curve reading and application

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 1, 2026 03:28
@gemini-code-assist
Copy link

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link

coderabbitai bot commented Mar 1, 2026

Warning

Rate limit exceeded

@EffortlessSteven has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 19 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between cd2e54d and f46ce40.

📒 Files selected for processing (4)
  • crates/flight-hotas-virpil/src/axis_curves.rs
  • crates/flight-hotas-virpil/src/button_matrix.rs
  • crates/flight-hotas-virpil/src/lib.rs
  • crates/flight-hotas-virpil/src/protocol.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/virpil-protocol

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-free-for-open-source-projects

Review Summary by Qodo

Add VIRPIL axis curves, button matrix, and unified protocol support

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Adds axis curve parsing and application for VIRPIL device firmware response curves
• Implements button matrix resolver supporting shifted/layered inputs
• Introduces unified protocol types and parsers for grip, base, and throttle devices
• Exports new public API for axis curves, button matrix, and device protocol handling
Diagram
flowchart LR
  A["Axis Curves Module"] -->|"Control points & interpolation"| B["apply_curve"]
  C["Button Matrix Module"] -->|"Physical to logical mapping"| D["resolve_shifted"]
  E["Protocol Extensions"] -->|"Device family detection"| F["VirpilProtocol"]
  F -->|"Unified parsing"| G["GripState/BaseState/ThrottleState"]
  A --> H["Public API"]
  C --> H
  F --> H
Loading

Grey Divider

File Changes

1. crates/flight-hotas-virpil/src/axis_curves.rs ✨ Enhancement +427/-0

Axis response curve parsing and interpolation

• New module implementing VIRPIL axis response curve reading and application
• Defines ControlPoint struct for curve control points normalized to [0.0, 1.0]
• Implements AxisCurve with linear interpolation between up to 11 control points
• Provides read_axis_curve to parse wire format (point count + x,y percent pairs)
• Provides apply_curve to apply curves to normalized input values with clamping
• Comprehensive test coverage for parsing, validation, and curve application

crates/flight-hotas-virpil/src/axis_curves.rs


2. crates/flight-hotas-virpil/src/button_matrix.rs ✨ Enhancement +294/-0

Button matrix resolver with shift layer support

• New module implementing physical-to-logical button matrix resolution
• Defines ButtonMatrix supporting up to 4 shift layers (base + 3 shifted)
• Maps (row, col) positions to 1-indexed logical button IDs across layers
• Implements resolve and resolve_shifted for forward mapping
• Implements reverse for reverse mapping button ID back to (row, col, layer)
• Validates matrix dimensions fit within u8 button ID space (max 255)
• Comprehensive tests for resolution, layer handling, and roundtrip mapping

crates/flight-hotas-virpil/src/button_matrix.rs


3. crates/flight-hotas-virpil/src/protocol.rs ✨ Enhancement +397/-0

Unified protocol types and device family detection

• Adds VirpilDeviceFamily enum for high-level device grouping (Grip, Base, Throttle, Pedals,
 Panel, Collective)
• Implements VirpilProtocol struct as unified device handle with PID detection
• Adds unified state types: GripState, BaseState, ThrottleState with normalized axes and
 button bitmaps
• Implements parse_grip_report, parse_base_report, parse_throttle_report for generic HID
 report parsing
• Adds VirpilParseError for report parsing errors
• Includes comprehensive tests for device family detection and report parsing

crates/flight-hotas-virpil/src/protocol.rs


View more (1)
4. crates/flight-hotas-virpil/src/lib.rs ✨ Enhancement +12/-0

Export new axis curves and button matrix APIs

• Declares new public modules axis_curves and button_matrix
• Exports public API types from axis_curves: AxisCurve, AxisCurveError, ControlPoint,
 apply_curve, read_axis_curve
• Exports public API types from button_matrix: ButtonMatrix, ButtonMatrixError
• Exports public API types from protocol: VirpilProtocol, VirpilDeviceFamily, unified state
 types, and parse functions

crates/flight-hotas-virpil/src/lib.rs


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link

qodo-free-for-open-source-projects bot commented Mar 1, 2026

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. ButtonMatrix reverse can panic🐞 Bug ⛯ Reliability
Description
ButtonMatrix::new() allows rows==0 or cols==0, which makes buttons_per_layer==0; reverse()
then divides/modulos by buttons_per_layer and cols, causing a division-by-zero panic for any
non-zero button_id. This is a reliability issue because it can crash consumers given an
easy-to-construct invalid matrix.
Code

crates/flight-hotas-virpil/src/button_matrix.rs[R141-153]

+    pub fn reverse(&self, button_id: u8) -> Option<(u8, u8, u8)> {
+        if button_id == 0 {
+            return None;
+        }
+        let id = button_id as u16 - 1;
+        let layer = (id / self.buttons_per_layer) as u8;
+        if layer >= self.shift_layers {
+            return None;
+        }
+        let within_layer = (id % self.buttons_per_layer) as u8;
+        let row = within_layer / self.cols;
+        let col = within_layer % self.cols;
+        Some((row, col, layer))
Evidence
new() computes buttons_per_layer from rows*cols without enforcing the documented constraint
that both are ≥1, so buttons_per_layer can be 0. reverse() divides by self.buttons_per_layer
and divides/modulos by self.cols without guarding against zero, which will panic at runtime.

crates/flight-hotas-virpil/src/button_matrix.rs[63-79]
crates/flight-hotas-virpil/src/button_matrix.rs[141-153]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ButtonMatrix::reverse()` can panic due to division/modulo by zero because `ButtonMatrix::new()` permits `rows == 0` or `cols == 0`.
## Issue Context
The public docs state `rows`/`cols` must be ≥ 1, but this is not enforced. A consumer can easily construct an invalid matrix and trigger a runtime crash by calling `reverse()` with any `button_id != 0`.
## Fix Focus Areas
- crates/flight-hotas-virpil/src/button_matrix.rs[71-80]
- crates/flight-hotas-virpil/src/button_matrix.rs[141-153]
## Suggested direction
- Change `pub fn new(...) -&amp;gt; Result&amp;lt;Self, ButtonMatrixError&amp;gt;` and validate `rows != 0 &amp;amp;&amp;amp; cols != 0` and `total_buttons &amp;lt;= 255` (call `validate()` internally).
- If you want to keep `new(...) -&amp;gt; Self`, then:
- introduce `debug_assert!(rows &amp;gt; 0 &amp;amp;&amp;amp; cols &amp;gt; 0)` and
- harden `reverse()` with early returns when `self.buttons_per_layer == 0 || self.cols == 0`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Axis curve clamps invalid bytes 🐞 Bug ✓ Correctness
Description
read_axis_curve() accepts X/Y percent bytes outside the documented 0–100 range and silently clamps
them via ControlPoint::new(). This can collapse distinct raw X values into the same normalized X
(e.g., >100% → 1.0), bypassing the duplicate-X checks (which compare raw bytes) and producing
degenerate segments at runtime.
Code

crates/flight-hotas-virpil/src/axis_curves.rs[R153-174]

+    let mut points = Vec::with_capacity(point_count);
+    for i in 0..point_count {
+        let x_pct = data[1 + i * 2];
+        let y_pct = data[2 + i * 2];
+        points.push(ControlPoint::new(x_pct as f64 / 100.0, y_pct as f64 / 100.0));
+    }
+
+    // Validate sorted order
+    for i in 1..points.len() {
+        let x_raw = data[1 + i * 2];
+        let prev_raw = data[1 + (i - 1) * 2];
+        if x_raw < prev_raw {
+            return Err(AxisCurveError::NotSorted {
+                index: i,
+                x: x_raw,
+                prev_x: prev_raw,
+            });
+        }
+        if x_raw == prev_raw {
+            return Err(AxisCurveError::DuplicateX { index: i, x: x_raw });
+        }
+    }
Evidence
The module docs state the wire format uses percentages 0–100, but the parser never enforces that
invariant. Instead it normalizes and then clamps, while ordering/duplicate checks are performed on
the raw bytes, not the post-clamp normalized values; therefore invalid raw inputs can yield
duplicated normalized X values that are not rejected.

crates/flight-hotas-virpil/src/axis_curves.rs[18-25]
crates/flight-hotas-virpil/src/axis_curves.rs[49-58]
crates/flight-hotas-virpil/src/axis_curves.rs[154-174]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`read_axis_curve()` allows out-of-range percent bytes and silently clamps them, which can create duplicated normalized X values and degenerate curve segments without returning an error.
## Issue Context
Wire format is documented as 0–100%. The parser should reject values outside that range to preserve the curve invariants and avoid surprising behavior.
## Fix Focus Areas
- crates/flight-hotas-virpil/src/axis_curves.rs[154-174]
- crates/flight-hotas-virpil/src/axis_curves.rs[49-58]
## Suggested direction
- Add a new error variant like `OutOfRange { index, x: u8, y: u8 }`.
- In the point-reading loop, return an error if `x_pct &amp;gt; 100 || y_pct &amp;gt; 100`.
- (Optional) Add a unit test covering a case like `x_pct=150` to ensure it errors instead of clamping.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

3. apply_curve docs mismatch🐞 Bug ✓ Correctness
Description
The apply_curve() docs say values below/above the endpoints are extrapolated, but the
implementation clamps to the first/last control point’s y (no extrapolation). This can mislead
callers and cause incorrect assumptions in downstream logic/tests.
Code

crates/flight-hotas-virpil/src/axis_curves.rs[R179-203]

+/// Apply a response curve to a normalised input value.
+///
+/// The input is clamped to `[0.0, 1.0]`. Linear interpolation is used between
+/// control points. Values below the first control point or above the last are
+/// extrapolated from the nearest segment (but the result is still clamped to
+/// `[0.0, 1.0]`).
+pub fn apply_curve(input: f64, curve: &AxisCurve) -> f64 {
+    let input = input.clamp(0.0, 1.0);
+    let points = &curve.points;
+
+    if points.is_empty() {
+        return input;
+    }
+    if points.len() == 1 {
+        return points[0].y;
+    }
+
+    // Below the first point
+    if input <= points[0].x {
+        return points[0].y;
+    }
+    // Above the last point
+    if input >= points[points.len() - 1].x {
+        return points[points.len() - 1].y;
+    }
Evidence
The function documentation promises extrapolation outside the control point range, but the code
explicitly returns the endpoint y values for inputs outside the first/last x values.

crates/flight-hotas-virpil/src/axis_curves.rs[179-184]
crates/flight-hotas-virpil/src/axis_curves.rs[196-203]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`apply_curve()` documentation describes extrapolation outside the control-point range, but the implementation returns the first/last `y` value (clamping behavior).
## Issue Context
This is not a runtime crash, but it’s a contract mismatch that can lead to incorrect usage.
## Fix Focus Areas
- crates/flight-hotas-virpil/src/axis_curves.rs[179-203]
## Suggested direction
- If endpoint clamping is intended: update the doc comment to remove the extrapolation claim.
- If extrapolation is intended: compute `t` using the first segment for inputs below the first point and the last segment for inputs above the last point, then clamp the final value.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +141 to +153
pub fn reverse(&self, button_id: u8) -> Option<(u8, u8, u8)> {
if button_id == 0 {
return None;
}
let id = button_id as u16 - 1;
let layer = (id / self.buttons_per_layer) as u8;
if layer >= self.shift_layers {
return None;
}
let within_layer = (id % self.buttons_per_layer) as u8;
let row = within_layer / self.cols;
let col = within_layer % self.cols;
Some((row, col, layer))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Buttonmatrix reverse can panic 🐞 Bug ⛯ Reliability

ButtonMatrix::new() allows rows==0 or cols==0, which makes buttons_per_layer==0; reverse()
then divides/modulos by buttons_per_layer and cols, causing a division-by-zero panic for any
non-zero button_id. This is a reliability issue because it can crash consumers given an
easy-to-construct invalid matrix.
Agent Prompt
## Issue description
`ButtonMatrix::reverse()` can panic due to division/modulo by zero because `ButtonMatrix::new()` permits `rows == 0` or `cols == 0`.

## Issue Context
The public docs state `rows`/`cols` must be ≥ 1, but this is not enforced. A consumer can easily construct an invalid matrix and trigger a runtime crash by calling `reverse()` with any `button_id != 0`.

## Fix Focus Areas
- crates/flight-hotas-virpil/src/button_matrix.rs[71-80]
- crates/flight-hotas-virpil/src/button_matrix.rs[141-153]

## Suggested direction
- Change `pub fn new(...) -> Result<Self, ButtonMatrixError>` and validate `rows != 0 && cols != 0` and `total_buttons <= 255` (call `validate()` internally).
- If you want to keep `new(...) -> Self`, then:
  - introduce `debug_assert!(rows > 0 && cols > 0)` and
  - harden `reverse()` with early returns when `self.buttons_per_layer == 0 || self.cols == 0`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Virpil VPC protocol utilities to flight-hotas-virpil, aiming to provide higher-level device identification plus reusable helpers for interpreting reports and firmware configuration.

Changes:

  • Introduces VirpilDeviceFamily + VirpilProtocol handle and unified report parsers (parse_grip_report, parse_base_report, parse_throttle_report).
  • Adds ButtonMatrix utility for resolving (row, col, layer) → logical button ID mapping.
  • Adds AxisCurve parsing/application utilities for Virpil firmware response curves and re-exports new APIs from the crate root.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
crates/flight-hotas-virpil/src/protocol.rs Adds device family classification, a PID-based protocol handle, and unified report parsing types/functions + tests.
crates/flight-hotas-virpil/src/lib.rs Exposes new modules and re-exports the new protocol/button-matrix/axis-curve APIs.
crates/flight-hotas-virpil/src/button_matrix.rs New button matrix resolver with shift-layer support and reverse mapping + tests.
crates/flight-hotas-virpil/src/axis_curves.rs New axis-curve wire-format parser and curve application logic + tests.

Comment on lines +196 to +202
// Below the first point
if input <= points[0].x {
return points[0].y;
}
// Above the last point
if input >= points[points.len() - 1].x {
return points[points.len() - 1].y;
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

apply_curve’s docstring says values below the first control point or above the last are “extrapolated from the nearest segment”, but the implementation clamps by returning the first/last point’s y (constant extension). Either implement true linear extrapolation using the first/last segment slope, or update the documentation to match the current behavior.

Suggested change
// Below the first point
if input <= points[0].x {
return points[0].y;
}
// Above the last point
if input >= points[points.len() - 1].x {
return points[points.len() - 1].y;
// Below the first point: extrapolate from the first segment
if input <= points[0].x {
let p0 = &points[0];
let p1 = &points[1];
let dx = p1.x - p0.x;
if dx.abs() < 1e-12 {
return p0.y;
}
let t = (input - p0.x) / dx;
let result = p0.y + t * (p1.y - p0.y);
return result.clamp(0.0, 1.0);
}
// Above the last point: extrapolate from the last segment
if input >= points[points.len() - 1].x {
let last = points.len() - 1;
let p0 = &points[last - 1];
let p1 = &points[last];
let dx = p1.x - p0.x;
if dx.abs() < 1e-12 {
return p1.y;
}
let t = (input - p0.x) / dx;
let result = p0.y + t * (p1.y - p0.y);
return result.clamp(0.0, 1.0);

Copilot uses AI. Check for mistakes.
Comment on lines +338 to +344
// ─── Unified report types ─────────────────────────────────────────────────────

use thiserror::Error;

/// Error from the unified report parsers.
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum VirpilParseError {
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use thiserror::Error; is placed mid-file, unlike the rest of this crate where use items are grouped at the top of the module. Consider moving this import up with the other use statements to keep the module layout consistent and easier to scan.

Copilot uses AI. Check for mistakes.
Comment on lines +349 to +456
/// Unified grip/stick state: normalised axes + button bitmap.
#[derive(Debug, Clone, PartialEq)]
pub struct GripState {
/// Normalised axis values `[0.0, 1.0]`. Typically 5 axes (X, Y, Z, SZ, SL).
pub axes: Vec<f32>,
/// Raw button bytes (LSB-first per byte).
pub buttons_raw: Vec<u8>,
}

impl GripState {
/// Return `true` if button `n` (1-indexed) is pressed.
pub fn is_pressed(&self, n: u8) -> bool {
if n == 0 {
return false;
}
let idx = (n - 1) as usize;
let byte = idx / 8;
let bit = idx % 8;
self.buttons_raw
.get(byte)
.is_some_and(|b| (b >> bit) & 1 == 1)
}
}

/// Unified base/gimbal state: normalised axes + button bitmap.
#[derive(Debug, Clone, PartialEq)]
pub struct BaseState {
/// Normalised axis values `[0.0, 1.0]`. Typically 5 axes (X, Y, Z, SZ, SL).
pub axes: Vec<f32>,
/// Raw button bytes (LSB-first per byte).
pub buttons_raw: Vec<u8>,
}

/// Unified throttle state: normalised axes + button bitmap.
#[derive(Debug, Clone, PartialEq)]
pub struct ThrottleState {
/// Normalised axis values `[0.0, 1.0]`. Typically 6 axes.
pub axes: Vec<f32>,
/// Raw button bytes (LSB-first per byte).
pub buttons_raw: Vec<u8>,
}

// ─── Unified parse functions ──────────────────────────────────────────────────

const GRIP_AXIS_COUNT: usize = 5;
const GRIP_BUTTON_BYTES: usize = 4;
const GRIP_MIN_BYTES: usize = 1 + GRIP_AXIS_COUNT * 2 + GRIP_BUTTON_BYTES; // 15

const BASE_AXIS_COUNT: usize = 5;
const BASE_BUTTON_BYTES: usize = 4;
const BASE_MIN_BYTES: usize = 1 + BASE_AXIS_COUNT * 2 + BASE_BUTTON_BYTES; // 15

const THROTTLE_AXIS_COUNT: usize = 6;
const THROTTLE_BUTTON_BYTES: usize = 10;
const THROTTLE_MIN_BYTES: usize = 1 + THROTTLE_AXIS_COUNT * 2 + THROTTLE_BUTTON_BYTES; // 23

/// Parse a generic grip/stick HID report into [`GripState`].
///
/// Compatible with Alpha, Alpha Prime, MongoosT-50CM3 grips (15-byte reports).
pub fn parse_grip_report(data: &[u8]) -> Result<GripState, VirpilParseError> {
if data.len() < GRIP_MIN_BYTES {
return Err(VirpilParseError::TooShort(data.len()));
}
let payload = &data[1..];
let mut axes = Vec::with_capacity(GRIP_AXIS_COUNT);
for i in 0..GRIP_AXIS_COUNT {
let raw = u16::from_le_bytes([payload[i * 2], payload[i * 2 + 1]]);
axes.push(normalize_axis(raw));
}
let btn_start = 1 + GRIP_AXIS_COUNT * 2;
let buttons_raw = data[btn_start..btn_start + GRIP_BUTTON_BYTES].to_vec();
Ok(GripState { axes, buttons_raw })
}

/// Parse a generic base/gimbal HID report into [`BaseState`].
///
/// Compatible with WarBRD, WarBRD-D bases (15-byte reports, same format as grips).
pub fn parse_base_report(data: &[u8]) -> Result<BaseState, VirpilParseError> {
if data.len() < BASE_MIN_BYTES {
return Err(VirpilParseError::TooShort(data.len()));
}
let payload = &data[1..];
let mut axes = Vec::with_capacity(BASE_AXIS_COUNT);
for i in 0..BASE_AXIS_COUNT {
let raw = u16::from_le_bytes([payload[i * 2], payload[i * 2 + 1]]);
axes.push(normalize_axis(raw));
}
let btn_start = 1 + BASE_AXIS_COUNT * 2;
let buttons_raw = data[btn_start..btn_start + BASE_BUTTON_BYTES].to_vec();
Ok(BaseState { axes, buttons_raw })
}

/// Parse a generic throttle HID report into [`ThrottleState`].
///
/// Compatible with VPC Throttle CM3 (23-byte reports).
pub fn parse_throttle_report(data: &[u8]) -> Result<ThrottleState, VirpilParseError> {
if data.len() < THROTTLE_MIN_BYTES {
return Err(VirpilParseError::TooShort(data.len()));
}
let payload = &data[1..];
let mut axes = Vec::with_capacity(THROTTLE_AXIS_COUNT);
for i in 0..THROTTLE_AXIS_COUNT {
let raw = u16::from_le_bytes([payload[i * 2], payload[i * 2 + 1]]);
axes.push(normalize_axis(raw));
}
let btn_start = 1 + THROTTLE_AXIS_COUNT * 2;
let buttons_raw = data[btn_start..btn_start + THROTTLE_BUTTON_BYTES].to_vec();
Ok(ThrottleState { axes, buttons_raw })
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unified parse_*_report functions allocate (Vec::with_capacity + to_vec) on every parse. Existing device-specific parsers in this crate generally avoid heap allocation by using fixed-size arrays in Copy state structs. If these unified parsers are used in a per-frame/per-tick input path, consider switching axes/buttons_raw to fixed-size arrays (or returning slices into the input buffer) to avoid repeated allocations and copies.

Copilot uses AI. Check for mistakes.
Comment on lines +141 to +153
pub fn reverse(&self, button_id: u8) -> Option<(u8, u8, u8)> {
if button_id == 0 {
return None;
}
let id = button_id as u16 - 1;
let layer = (id / self.buttons_per_layer) as u8;
if layer >= self.shift_layers {
return None;
}
let within_layer = (id % self.buttons_per_layer) as u8;
let row = within_layer / self.cols;
let col = within_layer % self.cols;
Some((row, col, layer))
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ButtonMatrix::reverse can panic due to division by zero if rows == 0 or cols == 0 (then buttons_per_layer == 0 and/or self.cols == 0). Since ButtonMatrix::new currently allows 0 for rows/cols and validate() doesn’t reject it, this is reachable from public API. Enforce rows >= 1 and cols >= 1 at construction (prefer returning Result<Self, ButtonMatrixError>), and/or make validate() fail for zero dimensions before reverse() can be used.

Copilot uses AI. Check for mistakes.
Comment on lines +59 to +79
/// Create a new button matrix.
///
/// # Arguments
///
/// * `rows` — number of physical rows in the matrix (must be ≥ 1).
/// * `cols` — number of physical columns in the matrix (must be ≥ 1).
/// * `shift_layers` — total number of layers including base (1–4).
///
/// # Errors
///
/// Returns [`ButtonMatrixError::DimensionsTooLarge`] if the total button
/// count (`rows × cols × layers`) exceeds 255.
pub fn new(rows: u8, cols: u8, shift_layers: u8) -> Self {
let layers = shift_layers.clamp(1, MAX_SHIFT_LAYERS);
let buttons_per_layer = rows as u16 * cols as u16;
Self {
rows,
cols,
shift_layers: layers,
buttons_per_layer,
}
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs for ButtonMatrix::new describe error cases (and ButtonMatrixError includes dimension errors), but new always returns Self and silently clamps shift_layers. This makes it easy to create an invalid matrix (e.g., dimensions too large or zero-sized) without noticing. Consider changing new to return Result<Self, ButtonMatrixError> (or updating the docs to match the current behavior and requiring callers to call validate() explicitly).

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +24
//! let matrix = ButtonMatrix::new(8, 16, 2);
//! assert_eq!(matrix.resolve(0, 0), Some(1));
//! assert_eq!(matrix.resolve(0, 1), Some(2));
//! assert_eq!(matrix.resolve_shifted(0, 0, 1), Some(129));
Copy link

Copilot AI Mar 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The module-level example constructs ButtonMatrix::new(8, 16, 2), but that configuration implies 256 logical buttons, which exceeds the u8 ID space and would fail validate() (and resolve_shifted will return None for some positions in the second layer). Please adjust the example to use dimensions that fit within the supported range, or update the API to support u16 button IDs if 256+ is intended.

Suggested change
//! let matrix = ButtonMatrix::new(8, 16, 2);
//! assert_eq!(matrix.resolve(0, 0), Some(1));
//! assert_eq!(matrix.resolve(0, 1), Some(2));
//! assert_eq!(matrix.resolve_shifted(0, 0, 1), Some(129));
//! let matrix = ButtonMatrix::new(8, 15, 2);
//! assert_eq!(matrix.resolve(0, 0), Some(1));
//! assert_eq!(matrix.resolve(0, 1), Some(2));
//! assert_eq!(matrix.resolve_shifted(0, 0, 1), Some(121));

Copilot uses AI. Check for mistakes.
- ButtonMatrix::new() now returns Result and rejects zero rows/cols
- Fix module doc example: use 8x15x2 to avoid u8 overflow
- Fix apply_curve docs to match clamping behavior
- Move thiserror import to top of protocol.rs
- Replace Vec with fixed-size arrays in parsed report structs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@qodo-free-for-open-source-projects

CI Feedback 🧐

A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

Action: Test Suite (windows-latest, 1.92.0)

Failed stage: Run tests [❌]

Failed test name: snapshot_alpha_yoke_full_right_roll

Failure summary:

The action failed during cargo test --all-features --workspace --lib --tests --exclude
flight-hub-examples because a snapshot test failed in the flight-hotas-honeycomb crate.
- Failed
test: snapshot_alpha_yoke_full_right_roll in
crates/flight-hotas-honeycomb/tests/snapshot_tests.rs:64
- The insta snapshot
alpha_yoke_full_right_roll did not match: the expected roll value was 1.0 but the new output was
0.9995117, causing an insta snapshot assertion panic and the test run to exit with code 101.

Relevant error logs:
1:  ##[group]Runner Image Provisioner
2:  Hosted Compute Agent
...

173:  RUST_BACKTRACE: 1
174:  targets: 
175:  components: rustfmt, clippy
176:  ##[endgroup]
177:  ##[group]Run : set $CARGO_HOME
178:  �[36;1m: set $CARGO_HOME�[0m
179:  �[36;1mecho CARGO_HOME=${CARGO_HOME:-"$USERPROFILE\.cargo"} >> $GITHUB_ENV�[0m
180:  shell: C:\Program Files\Git\bin\bash.EXE --noprofile --norc -e -o pipefail {0}
181:  env:
182:  CARGO_TERM_COLOR: always
183:  RUST_BACKTRACE: 1
184:  ##[endgroup]
185:  ##[group]Run : install rustup if needed on windows
186:  �[36;1m: install rustup if needed on windows�[0m
187:  �[36;1mif ! command -v rustup &>/dev/null; then�[0m
188:  �[36;1m  curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused --location --silent --show-error --fail https://win.rustup.rs/x86_64 --output 'D:\a\_temp\rustup-init.exe'�[0m
189:  �[36;1m  'D:\a\_temp\rustup-init.exe' --default-toolchain none --no-modify-path -y�[0m
...

269:  �[36;1m  if rustc +1.92.0 --version --verbose | grep -q '^release: 1\.6[89]\.'; then�[0m
270:  �[36;1m    touch "D:\a\_temp"/.implicit_cargo_registries_crates_io_protocol || true�[0m
271:  �[36;1m    echo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse >> $GITHUB_ENV�[0m
272:  �[36;1m  elif rustc +1.92.0 --version --verbose | grep -q '^release: 1\.6[67]\.'; then�[0m
273:  �[36;1m    touch "D:\a\_temp"/.implicit_cargo_registries_crates_io_protocol || true�[0m
274:  �[36;1m    echo CARGO_REGISTRIES_CRATES_IO_PROTOCOL=git >> $GITHUB_ENV�[0m
275:  �[36;1m  fi�[0m
276:  �[36;1mfi�[0m
277:  shell: C:\Program Files\Git\bin\bash.EXE --noprofile --norc -e -o pipefail {0}
278:  env:
279:  CARGO_TERM_COLOR: always
280:  RUST_BACKTRACE: 1
281:  CARGO_HOME: C:\Users\runneradmin\.cargo
282:  CARGO_INCREMENTAL: 0
283:  ##[endgroup]
284:  ##[group]Run : work around spurious network errors in curl 8.0
285:  �[36;1m: work around spurious network errors in curl 8.0�[0m
286:  �[36;1m# https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/timeout.20investigation�[0m
...

454:  - D:\a\OpenFlight\OpenFlight\examples\Cargo.toml
455:  - D:\a\OpenFlight\OpenFlight\installer\Cargo.toml
456:  - D:\a\OpenFlight\OpenFlight\specs\Cargo.toml
457:  - D:\a\OpenFlight\OpenFlight\xtask\Cargo.toml
458:  ##[endgroup]
459:  ... Restoring cache ...
460:  No cache found.
461:  ##[group]Run cargo fmt --all -- --check
462:  �[36;1mcargo fmt --all -- --check�[0m
463:  shell: C:\Program Files\Git\bin\bash.EXE --noprofile --norc -e -o pipefail {0}
464:  env:
465:  CARGO_TERM_COLOR: always
466:  RUST_BACKTRACE: 1
467:  CARGO_HOME: C:\Users\runneradmin\.cargo
468:  CARGO_INCREMENTAL: 0
469:  CACHE_ON_FAILURE: false
470:  ##[endgroup]
471:  ##[group]Run cargo clippy --workspace --all-features --lib --tests --exclude flight-hub-examples
472:  �[36;1mcargo clippy --workspace --all-features --lib --tests --exclude flight-hub-examples�[0m
473:  shell: C:\Program Files\Git\bin\bash.EXE --noprofile --norc -e -o pipefail {0}
474:  env:
475:  CARGO_TERM_COLOR: always
476:  RUST_BACKTRACE: 1
477:  CARGO_HOME: C:\Users\runneradmin\.cargo
478:  CARGO_INCREMENTAL: 0
479:  CACHE_ON_FAILURE: false
480:  ##[endgroup]
...

572:  �[1m�[92m  Downloaded�[0m rayon v1.11.0
573:  �[1m�[92m  Downloaded�[0m quinn-proto v0.11.13
574:  �[1m�[92m  Downloaded�[0m proptest v1.10.0
575:  �[1m�[92m  Downloaded�[0m bstr v1.12.1
576:  �[1m�[92m  Downloaded�[0m tower-service v0.3.3
577:  �[1m�[92m  Downloaded�[0m tower-layer v0.3.3
578:  �[1m�[92m  Downloaded�[0m tonic-prost v0.14.5
579:  �[1m�[92m  Downloaded�[0m toml_writer v1.0.6+spec-1.1.0
580:  �[1m�[92m  Downloaded�[0m serde v1.0.228
581:  �[1m�[92m  Downloaded�[0m tracing v0.1.44
582:  �[1m�[92m  Downloaded�[0m rustls-webpki v0.103.9
583:  �[1m�[92m  Downloaded�[0m reqwest v0.13.1
584:  �[1m�[92m  Downloaded�[0m rayon-core v1.13.0
585:  �[1m�[92m  Downloaded�[0m pulldown-cmark v0.13.1
586:  �[1m�[92m  Downloaded�[0m toml_write v0.1.2
587:  �[1m�[92m  Downloaded�[0m thiserror v2.0.18
588:  �[1m�[92m  Downloaded�[0m textwrap v0.16.2
589:  �[1m�[92m  Downloaded�[0m serde_spanned v1.0.4
590:  �[1m�[92m  Downloaded�[0m serde_derive v1.0.228
591:  �[1m�[92m  Downloaded�[0m sealed v0.6.0
592:  �[1m�[92m  Downloaded�[0m scopeguard v1.2.0
593:  �[1m�[92m  Downloaded�[0m same-file v1.0.6
594:  �[1m�[92m  Downloaded�[0m chrono v0.4.44
595:  �[1m�[92m  Downloaded�[0m writeable v0.6.2
596:  �[1m�[92m  Downloaded�[0m windows-threading v0.2.1
597:  �[1m�[92m  Downloaded�[0m windows-core v0.62.2
598:  �[1m�[92m  Downloaded�[0m walkdir v2.5.0
599:  �[1m�[92m  Downloaded�[0m tracing-core v0.1.36
600:  �[1m�[92m  Downloaded�[0m thiserror-impl v2.0.18
601:  �[1m�[92m  Downloaded�[0m tempfile v3.26.0
...

637:  �[1m�[92m  Downloaded�[0m toml_datetime v0.6.11
638:  �[1m�[92m  Downloaded�[0m tokio-tungstenite v0.28.0
639:  �[1m�[92m  Downloaded�[0m tokio-test v0.4.5
640:  �[1m�[92m  Downloaded�[0m tokio-rustls v0.26.4
641:  �[1m�[92m  Downloaded�[0m tokio-macros v2.6.0
642:  �[1m�[92m  Downloaded�[0m tinyvec_macros v0.1.1
643:  �[1m�[92m  Downloaded�[0m tinytemplate v1.2.1
644:  �[1m�[92m  Downloaded�[0m tinystr v0.8.2
645:  �[1m�[92m  Downloaded�[0m time-macros v0.2.27
646:  �[1m�[92m  Downloaded�[0m time-core v0.1.8
647:  �[1m�[92m  Downloaded�[0m thread_local v1.1.9
648:  �[1m�[92m  Downloaded�[0m spin v0.9.8
649:  �[1m�[92m  Downloaded�[0m smallvec v1.15.1
650:  �[1m�[92m  Downloaded�[0m sharded-slab v0.1.7
651:  �[1m�[92m  Downloaded�[0m serde_yaml_ng v0.10.0
652:  �[1m�[92m  Downloaded�[0m serde_path_to_error v0.1.20
653:  �[1m�[92m  Downloaded�[0m serde_core v1.0.228
...

701:  �[1m�[92m  Downloaded�[0m futures-util v0.3.32
702:  �[1m�[92m  Downloaded�[0m fraction v0.15.3
703:  �[1m�[92m  Downloaded�[0m crossbeam-channel v0.5.15
704:  �[1m�[92m  Downloaded�[0m cc v1.2.56
705:  �[1m�[92m  Downloaded�[0m rustc-hash v2.1.1
706:  �[1m�[92m  Downloaded�[0m quote v1.0.44
707:  �[1m�[92m  Downloaded�[0m protoc-bin-vendored v3.2.0
708:  �[1m�[92m  Downloaded�[0m proc-macro2 v1.0.106
709:  �[1m�[92m  Downloaded�[0m plotters-svg v0.3.7
710:  �[1m�[92m  Downloaded�[0m fancy-regex v0.17.0
711:  �[1m�[92m  Downloaded�[0m der v0.7.10
712:  �[1m�[92m  Downloaded�[0m cookie v0.18.1
713:  �[1m�[92m  Downloaded�[0m clap_builder v4.5.60
714:  �[1m�[92m  Downloaded�[0m bytes v1.11.1
715:  �[1m�[92m  Downloaded�[0m aho-corasick v1.1.4
716:  �[1m�[92m  Downloaded�[0m quick-error v1.2.3
717:  �[1m�[92m  Downloaded�[0m prost-types v0.14.3
...

892:  �[1m�[92m  Downloaded�[0m cargo-lock v11.0.1
893:  �[1m�[92m  Downloaded�[0m async-trait v0.1.89
894:  �[1m�[92m  Downloaded�[0m anyhow v1.0.102
895:  �[1m�[92m  Downloaded�[0m anstyle-parse v0.2.7
896:  �[1m�[92m  Downloaded�[0m anstyle v1.0.13
897:  �[1m�[92m  Downloaded�[0m alloca v0.4.0
898:  �[1m�[92m  Downloaded�[0m windows v0.62.2
899:  �[1m�[92m  Downloaded�[0m aws-lc-sys v0.37.1
900:  �[1m�[92m Downloading�[0m crates ...
901:  �[1m�[92m  Downloaded�[0m nix v0.31.2
902:  �[1m�[92m   Compiling�[0m proc-macro2 v1.0.106
903:  �[1m�[92m   Compiling�[0m unicode-ident v1.0.24
904:  �[1m�[92m   Compiling�[0m quote v1.0.44
905:  �[1m�[92m   Compiling�[0m serde_core v1.0.228
906:  �[1m�[92m   Compiling�[0m serde v1.0.228
907:  �[1m�[92m   Compiling�[0m thiserror v2.0.18
908:  �[1m�[92m   Compiling�[0m getrandom v0.3.4
...

922:  �[1m�[92m    Checking�[0m pin-project-lite v0.2.17
923:  �[1m�[92m   Compiling�[0m version_check v0.9.5
924:  �[1m�[92m    Checking�[0m log v0.4.29
925:  �[1m�[92m    Checking�[0m tracing-core v0.1.36
926:  �[1m�[92m   Compiling�[0m typenum v1.19.0
927:  �[1m�[92m   Compiling�[0m generic-array v0.14.7
928:  �[1m�[92m    Checking�[0m fnv v1.0.7
929:  �[1m�[92m    Checking�[0m regex-syntax v0.8.10
930:  �[1m�[92m    Checking�[0m rand_core v0.9.5
931:  �[1m�[92m    Checking�[0m fastrand v2.3.0
932:  �[1m�[92m    Checking�[0m bitflags v2.11.0
933:  �[1m�[92m    Checking�[0m memchr v2.8.0
934:  �[1m�[92m    Checking�[0m bit-vec v0.8.0
935:  �[1m�[92m    Checking�[0m bit-set v0.8.0
936:  �[1m�[92m    Checking�[0m wait-timeout v0.2.1
937:  �[1m�[92m    Checking�[0m quick-error v1.2.3
938:  �[1m�[92m    Checking�[0m rand_xorshift v0.4.0
939:  �[1m�[92m    Checking�[0m unarray v0.1.4
940:  �[1m�[92m    Checking�[0m itoa v1.0.17
941:  �[1m�[92m   Compiling�[0m crossbeam-utils v0.8.21
942:  �[1m�[92m   Compiling�[0m anyhow v1.0.102
943:  �[1m�[92m    Checking�[0m windows-targets v0.53.5
944:  �[1m�[92m    Checking�[0m windows-sys v0.60.2
945:  �[1m�[92m   Compiling�[0m semver v1.0.27
946:  �[1m�[92m   Compiling�[0m rustc_version v0.4.1
947:  �[1m�[92m    Checking�[0m bytes v1.11.1
948:  �[1m�[92m    Checking�[0m socket2 v0.6.2
949:  �[1m�[92m   Compiling�[0m serde_derive v1.0.228
950:  �[1m�[92m   Compiling�[0m thiserror-impl v2.0.18
951:  �[1m�[92m   Compiling�[0m tracing-attributes v0.1.31
...

1185:  �[1m�[92m   Compiling�[0m protoc-bin-vendored-linux-aarch_64 v3.2.0
1186:  �[1m�[92m   Compiling�[0m protoc-bin-vendored-linux-ppcle_64 v3.2.0
1187:  �[1m�[92m   Compiling�[0m protoc-bin-vendored-linux-x86_32 v3.2.0
1188:  �[1m�[92m   Compiling�[0m protoc-bin-vendored-macos-x86_64 v3.2.0
1189:  �[1m�[92m   Compiling�[0m protoc-bin-vendored-macos-aarch_64 v3.2.0
1190:  �[1m�[92m   Compiling�[0m protoc-bin-vendored-win32 v3.2.0
1191:  �[1m�[92m   Compiling�[0m protoc-bin-vendored-linux-s390_64 v3.2.0
1192:  �[1m�[92m   Compiling�[0m protoc-bin-vendored-linux-x86_64 v3.2.0
1193:  �[1m�[92m   Compiling�[0m protoc-bin-vendored v3.2.0
1194:  �[1m�[92m    Checking�[0m tracing-subscriber v0.3.22
1195:  �[1m�[92m   Compiling�[0m tonic-prost-build v0.14.5
1196:  �[1m�[92m    Checking�[0m tokio-tungstenite v0.28.0
1197:  �[1m�[92m    Checking�[0m axum-core v0.5.6
1198:  �[1m�[92m    Checking�[0m serde_urlencoded v0.7.1
1199:  �[1m�[92m    Checking�[0m futures-executor v0.3.32
1200:  �[1m�[92m    Checking�[0m serde_path_to_error v0.1.20
1201:  �[1m�[92m    Checking�[0m matchit v0.8.4
...

1475:  �[1m�[96m--> �[0mcrates\flight-watchdog\src\lib.rs:1134:9
1476:  �[1m�[96m|�[0m
1477:  �[1m�[96m1134�[0m �[1m�[96m|�[0m         config.enable_nan_guards = true;
1478:  �[1m�[96m|�[0m         �[1m�[93m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^�[0m
1479:  �[1m�[96m|�[0m
1480:  �[1m�[92mnote�[0m: consider initializing the variable with `WatchdogConfig { enable_nan_guards: true, ..Default::default() }` and removing relevant reassignments
1481:  �[1m�[96m--> �[0mcrates\flight-watchdog\src\lib.rs:1133:9
1482:  �[1m�[96m|�[0m
1483:  �[1m�[96m1133�[0m �[1m�[96m|�[0m         let mut config = WatchdogConfig::default();
1484:  �[1m�[96m|�[0m         �[1m�[92m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^�[0m
1485:  �[1m�[96m= �[0m�[1m�[97mhelp�[0m: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#field_reassign_with_default
1486:  �[1m�[96m= �[0m�[1m�[97mnote�[0m: `#[warn(clippy::field_reassign_with_default)]` on by default
1487:  �[1m�[93mwarning�[0m�[1m�[97m: field assignment outside of initializer for an instance created with Default::default()�[0m
1488:  �[1m�[96m--> �[0mcrates\flight-watchdog\src\lib.rs:1158:9
1489:  �[1m�[96m|�[0m
1490:  �[1m�[96m1158�[0m �[1m�[96m|�[0m         config.max_consecutive_failures = 2; // Lower threshold for testing
1491:  �[1m�[96m|�[0m         �[1m�[93m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^�[0m
1492:  �[1m�[96m|�[0m
1493:  �[1m�[92mnote�[0m: consider initializing the variable with `WatchdogConfig { max_consecutive_failures: 2, ..Default::default() }` and removing relevant reassignments
1494:  �[1m�[96m--> �[0mcrates\flight-watchdog\src\lib.rs:1157:9
...

1610:  �[1m�[93mwarning�[0m: `flight-axis` (test "mixer_tests") generated 1 warning (run `cargo clippy --fix --test "mixer_tests" -p flight-axis` to apply 1 suggestion)
1611:  �[1m�[93mwarning[E0133]�[0m�[1m�[97m: call to unsafe function `flight_axis::Node::step_soa` is unsafe and requires unsafe block�[0m
1612:  �[1m�[96m--> �[0mcrates\flight-axis\tests\detent_tests.rs:25:5
1613:  �[1m�[96m|�[0m
1614:  �[1m�[96m25�[0m �[1m�[96m|�[0m     node.step_soa(frame, state_ptr);
1615:  �[1m�[96m|�[0m     �[1m�[93m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^�[0m �[1m�[93mcall to unsafe function�[0m
1616:  �[1m�[96m|�[0m
1617:  �[1m�[96m= �[0m�[1m�[97mnote�[0m: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
1618:  �[1m�[96m= �[0m�[1m�[97mnote�[0m: consult the function's documentation for information on how to avoid undefined behavior
1619:  �[1m�[92mnote�[0m: an unsafe function restricts its caller, but its body is safe by default
1620:  �[1m�[96m--> �[0mcrates\flight-axis\tests\detent_tests.rs:23:1
1621:  �[1m�[96m|�[0m
1622:  �[1m�[96m23�[0m �[1m�[96m|�[0m unsafe fn process_frame_soa(node: &DetentNode, frame: &mut AxisFrame, state: &mut DetentState) {
1623:  �[1m�[96m|�[0m �[1m�[92m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^�[0m
1624:  �[1m�[96m= �[0m�[1m�[97mnote�[0m: `#[warn(unsafe_op_in_unsafe_fn)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
1625:  �[1m�[97mFor more information about this error, try `rustc --explain E0133`.�[0m
1626:  �[1m�[93mwarning�[0m: `flight-axis` (test "detent_tests") generated 1 warning (run `cargo clippy --fix --test "detent_tests" -p flight-axis` to apply 1 suggestion)
...

1795:  �[1m�[96m--> �[0mcrates\flight-core\src\lib.rs:131:30
1796:  �[1m�[96m|�[0m
1797:  �[1m�[96m131�[0m �[1m�[96m|�[0m         let r: Result<u32> = Ok(42);
1798:  �[1m�[96m|�[0m                              �[1m�[96m^^^^^^�[0m
1799:  �[1m�[96m= �[0m�[1m�[97mhelp�[0m: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.92.0/index.html#unnecessary_literal_unwrap
1800:  �[1m�[96m= �[0m�[1m�[97mnote�[0m: `#[warn(clippy::unnecessary_literal_unwrap)]` on by default
1801:  �[1m�[93mwarning�[0m�[1m�[97m: used `unwrap_err()` on `Err` value�[0m
1802:  �[1m�[96m--> �[0mcrates\flight-core\src\lib.rs:136:17
1803:  �[1m�[96m|�[0m
1804:  �[1m�[96m136�[0m �[1m�[96m|�[0m         assert!(e.unwrap_err().to_string().contains("Rules validation"));
1805:  �[1m�[96m|�[0m                 �[1m�[93m^^^^^^^^^^^^^^�[0m
1806:  �[1m�[96m|�[0m
1807:  �[1m�[96mhelp�[0m: remove the `Err` and `unwrap_err()`
1808:  �[1m�[96m--> �[0mcrates\flight-core\src\lib.rs:134:30
1809:  �[1m�[96m|�[0m
1810:  �[1m�[96m134�[0m �[1m�[96m|�[0m         let e: Result<u32> = Err(FlightError::RulesValidation("bad rule".to_string()));
1811:  �[1m�[96m|�[0m                              �[1m�[96m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^�[0m
...

2190:  �[36;1m# Apply strict warnings to core crates that must maintain high quality�[0m
2191:  �[36;1mcargo clippy -p flight-core --lib -- $STRICT_FLAGS�[0m
2192:  �[36;1mcargo clippy -p flight-axis --lib -- $STRICT_FLAGS�[0m
2193:  �[36;1mcargo clippy -p flight-bus --lib -- $STRICT_FLAGS�[0m
2194:  �[36;1mcargo clippy -p flight-hid --lib -- $STRICT_FLAGS�[0m
2195:  �[36;1mcargo clippy -p flight-ipc --lib -- $STRICT_FLAGS�[0m
2196:  �[36;1mcargo clippy -p flight-service --lib -- $STRICT_FLAGS�[0m
2197:  �[36;1mcargo clippy -p flight-simconnect --lib -- $STRICT_FLAGS�[0m
2198:  �[36;1mcargo clippy -p flight-panels --lib -- $STRICT_FLAGS�[0m
2199:  shell: C:\Program Files\Git\bin\bash.EXE --noprofile --norc -e -o pipefail {0}
2200:  env:
2201:  CARGO_TERM_COLOR: always
2202:  RUST_BACKTRACE: 1
2203:  CARGO_HOME: C:\Users\runneradmin\.cargo
2204:  CARGO_INCREMENTAL: 0
2205:  CACHE_ON_FAILURE: false
2206:  ##[endgroup]
...

2214:  �[1m�[92m   Compiling�[0m num-traits v0.2.19
2215:  �[1m�[92m    Checking�[0m crossbeam-epoch v0.9.18
2216:  �[1m�[92m    Checking�[0m aho-corasick v1.1.4
2217:  �[1m�[92m    Checking�[0m hashbrown v0.16.1
2218:  �[1m�[92m    Checking�[0m mio v1.1.1
2219:  �[1m�[92m    Checking�[0m regex-automata v0.4.14
2220:  �[1m�[92m    Checking�[0m indexmap v2.13.0
2221:  �[1m�[92m    Checking�[0m crossbeam-deque v0.8.6
2222:  �[1m�[92m    Checking�[0m crossbeam-channel v0.5.15
2223:  �[1m�[92m    Checking�[0m crossbeam-queue v0.3.12
2224:  �[1m�[92m    Checking�[0m tempfile v3.26.0
2225:  �[1m�[92m    Checking�[0m crossbeam v0.8.4
2226:  �[1m�[92m    Checking�[0m flight-metrics v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-metrics)
2227:  �[1m�[92m    Checking�[0m regex v1.12.3
2228:  �[1m�[92m   Compiling�[0m serde_derive v1.0.228
2229:  �[1m�[92m   Compiling�[0m thiserror-impl v2.0.18
2230:  �[1m�[92m   Compiling�[0m tracing-attributes v0.1.31
2231:  �[1m�[92m   Compiling�[0m windows-interface v0.59.3
2232:  �[1m�[92m   Compiling�[0m windows-implement v0.60.2
2233:  �[1m�[92m    Checking�[0m thiserror v2.0.18
2234:  �[1m�[92m    Checking�[0m tracing v0.1.44
...

2456:  �[1m�[92m    Checking�[0m flight-panels-saitek v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-panels-saitek)
2457:  �[1m�[92m    Checking�[0m flight-panels v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-panels)
2458:  �[1m�[92m    Finished�[0m `dev` profile [unoptimized + debuginfo] target(s) in 1.19s
2459:  ##[group]Run echo "🔍 Running file descriptor safety tests for public API crates..."
2460:  �[36;1mecho "🔍 Running file descriptor safety tests for public API crates..."�[0m
2461:  �[36;1m# Test that public API crates use typed file descriptors instead of RawFd�[0m
2462:  �[36;1mcargo test -p flight-hid fd_safety_tests�[0m
2463:  �[36;1mcargo test -p flight-ipc fd_safety_tests�[0m
2464:  �[36;1mcargo test -p flight-service fd_safety_tests�[0m
2465:  shell: C:\Program Files\Git\bin\bash.EXE --noprofile --norc -e -o pipefail {0}
2466:  env:
2467:  CARGO_TERM_COLOR: always
2468:  RUST_BACKTRACE: 1
2469:  CARGO_HOME: C:\Users\runneradmin\.cargo
2470:  CARGO_INCREMENTAL: 0
2471:  CACHE_ON_FAILURE: false
2472:  ##[endgroup]
2473:  🔍 Running file descriptor safety tests for public API crates...
2474:  �[1m�[92m   Compiling�[0m windows-link v0.2.1
2475:  �[1m�[92m   Compiling�[0m serde_core v1.0.228
2476:  �[1m�[92m   Compiling�[0m cfg-if v1.0.4
2477:  �[1m�[92m   Compiling�[0m once_cell v1.21.3
2478:  �[1m�[92m   Compiling�[0m windows-sys v0.61.2
2479:  �[1m�[92m   Compiling�[0m thiserror v2.0.18
2480:  �[1m�[92m   Compiling�[0m typenum v1.19.0
...

2546:  �[1m�[92m   Compiling�[0m hex v0.4.3
2547:  �[1m�[92m   Compiling�[0m flight-security v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-security)
2548:  �[1m�[92m   Compiling�[0m ppv-lite86 v0.2.21
2549:  �[1m�[92m   Compiling�[0m flight-session v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-session)
2550:  �[1m�[92m   Compiling�[0m toml v0.8.23
2551:  �[1m�[92m   Compiling�[0m flight-blackbox v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-blackbox)
2552:  �[1m�[92m   Compiling�[0m flight-writers v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-writers)
2553:  �[1m�[92m   Compiling�[0m windows-sys v0.59.0
2554:  �[1m�[92m   Compiling�[0m flight-watchdog v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-watchdog)
2555:  �[1m�[92m   Compiling�[0m flight-rules v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-rules)
2556:  �[1m�[92m   Compiling�[0m flight-units v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-units)
2557:  �[1m�[92m   Compiling�[0m fnv v1.0.7
2558:  �[1m�[92m   Compiling�[0m bit-vec v0.8.0
2559:  �[1m�[92m   Compiling�[0m flight-hid-types v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-hid-types)
2560:  �[1m�[92m   Compiling�[0m flight-metrics v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-metrics)
2561:  �[1m�[92m   Compiling�[0m quick-error v1.2.3
2562:  �[1m�[92m   Compiling�[0m encode_unicode v1.0.0
...

2569:  �[1m�[92m   Compiling�[0m hidapi v2.6.5
2570:  �[1m�[92m   Compiling�[0m rand_chacha v0.9.0
2571:  �[1m�[92m   Compiling�[0m rand v0.9.2
2572:  �[1m�[92m   Compiling�[0m rand_xorshift v0.4.0
2573:  �[1m�[92m   Compiling�[0m bitflags v2.11.0
2574:  �[1m�[92m   Compiling�[0m unarray v0.1.4
2575:  �[1m�[92m   Compiling�[0m similar v2.7.0
2576:  �[1m�[92m   Compiling�[0m flight-hid v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-hid)
2577:  �[1m�[92m   Compiling�[0m proptest v1.10.0
2578:  �[1m�[92m   Compiling�[0m insta v1.46.3
2579:  �[1m�[92m    Finished�[0m `test` profile [unoptimized + debuginfo] target(s) in 44.15s
2580:  �[1m�[92m     Running�[0m unittests src\lib.rs (target\debug\deps\flight_hid-043f7d3037b68f2b.exe)
2581:  running 2 tests
2582:  test fd_safety_tests::windows_tests::test_typed_handle_usage ... ok
2583:  test fd_safety_tests::clippy_config::test_fd_usage_examples ... ok
2584:  test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 200 filtered out; finished in 0.00s
2585:  �[1m�[92m     Running�[0m tests\integration.rs (target\debug\deps\integration-a81f826ce256a4c3.exe)
2586:  running 0 tests
2587:  test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 14 filtered out; finished in 0.00s
2588:  �[1m�[92m     Running�[0m tests\proptest_axis_calibration.rs (target\debug\deps\proptest_axis_calibration-452cbfb4e1ccccd9.exe)
2589:  running 0 tests
2590:  test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 13 filtered out; finished in 0.00s
2591:  �[1m�[92m     Running�[0m tests\snapshots.rs (target\debug\deps\snapshots-40569faf95b9e0fe.exe)
2592:  running 0 tests
2593:  test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out; finished in 0.00s
2594:  �[1m�[92m   Compiling�[0m windows-sys v0.61.2
...

2713:  �[1m�[92m   Compiling�[0m plotters v0.3.7
2714:  �[1m�[92m   Compiling�[0m matchers v0.2.0
2715:  �[1m�[92m   Compiling�[0m tinytemplate v1.2.1
2716:  �[1m�[92m   Compiling�[0m thread_local v1.1.9
2717:  �[1m�[92m   Compiling�[0m anes v0.1.6
2718:  �[1m�[92m   Compiling�[0m oorandom v11.1.5
2719:  �[1m�[92m   Compiling�[0m criterion v0.8.2
2720:  �[1m�[92m   Compiling�[0m proptest v1.10.0
2721:  �[1m�[92m   Compiling�[0m tracing-subscriber v0.3.22
2722:  �[1m�[92m   Compiling�[0m tokio-test v0.4.5
2723:  �[1m�[92m    Finished�[0m `test` profile [unoptimized + debuginfo] target(s) in 1m 16s
2724:  �[1m�[92m     Running�[0m unittests src\lib.rs (target\debug\deps\flight_ipc-79b4f8e059ecd494.exe)
2725:  running 2 tests
2726:  test fd_safety_tests::fd_usage_examples::test_ipc_fd_usage_examples ... ok
2727:  test fd_safety_tests::windows_tests::test_typed_handle_usage_ipc ... ok
2728:  test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 171 filtered out; finished in 0.00s
2729:  �[1m�[92m     Running�[0m tests\grpc_tests.rs (target\debug\deps\grpc_tests-799f22426cd2e282.exe)
2730:  running 0 tests
2731:  test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 21 filtered out; finished in 0.00s
2732:  �[1m�[92m     Running�[0m tests\ipc_fuzz_tests.rs (target\debug\deps\ipc_fuzz_tests-cea6c6991d4cd9b8.exe)
2733:  running 0 tests
2734:  test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out; finished in 0.00s
2735:  �[1m�[92m     Running�[0m tests\proto_tests.rs (target\debug\deps\proto_tests-dd5405f9784363ea.exe)
2736:  running 0 tests
2737:  test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 25 filtered out; finished in 0.00s
2738:  �[1m�[92m   Compiling�[0m windows-link v0.2.1
...

2741:  �[1m�[92m   Compiling�[0m serde v1.0.228
2742:  �[1m�[92m   Compiling�[0m windows-sys v0.61.2
2743:  �[1m�[92m   Compiling�[0m cc v1.2.56
2744:  �[1m�[92m   Compiling�[0m pin-project-lite v0.2.17
2745:  �[1m�[92m   Compiling�[0m serde_core v1.0.228
2746:  �[1m�[92m   Compiling�[0m num-traits v0.2.19
2747:  �[1m�[92m   Compiling�[0m once_cell v1.21.3
2748:  �[1m�[92m   Compiling�[0m memchr v2.8.0
2749:  �[1m�[92m   Compiling�[0m bytes v1.11.1
2750:  �[1m�[92m   Compiling�[0m itoa v1.0.17
2751:  �[1m�[92m   Compiling�[0m tracing v0.1.44
2752:  �[1m�[92m   Compiling�[0m windows_x86_64_msvc v0.53.1
2753:  �[1m�[92m   Compiling�[0m windows-targets v0.53.5
2754:  �[1m�[92m   Compiling�[0m tracing-core v0.1.36
2755:  �[1m�[92m   Compiling�[0m windows-sys v0.60.2
2756:  �[1m�[92m   Compiling�[0m thiserror v2.0.18
2757:  �[1m�[92m   Compiling�[0m stable_deref_trait v1.2.1
...

2873:  �[1m�[92m   Compiling�[0m icu_properties_data v2.1.2
2874:  �[1m�[92m   Compiling�[0m icu_normalizer_data v2.1.1
2875:  �[1m�[92m   Compiling�[0m flight-simconnect-sys v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-simconnect-sys)
2876:  �[1m�[92m   Compiling�[0m ryu v1.0.23
2877:  �[1m�[92m   Compiling�[0m untrusted v0.9.0
2878:  �[1m�[92m   Compiling�[0m icu_normalizer v2.1.1
2879:  �[1m�[92m   Compiling�[0m icu_properties v2.1.2
2880:  �[1m�[92m   Compiling�[0m tonic-prost-build v0.14.5
2881:  �[1m�[92m   Compiling�[0m http-body-util v0.1.3
2882:  �[1m�[92m   Compiling�[0m subtle v2.6.1
2883:  �[1m�[92m   Compiling�[0m flight-ipc v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-ipc)
2884:  �[1m�[92m   Compiling�[0m idna_adapter v1.2.1
2885:  �[1m�[92m   Compiling�[0m serde_urlencoded v0.7.1
2886:  �[1m�[92m   Compiling�[0m axum-core v0.5.6
2887:  �[1m�[92m   Compiling�[0m num-integer v0.1.46
2888:  �[1m�[92m   Compiling�[0m serde_path_to_error v0.1.20
2889:  �[1m�[92m   Compiling�[0m utf8_iter v1.0.4
...

2965:  �[1m�[92m   Compiling�[0m flight-hotas-thrustmaster v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-hotas-thrustmaster)
2966:  �[1m�[92m   Compiling�[0m matchers v0.2.0
2967:  �[1m�[92m   Compiling�[0m thread_local v1.1.9
2968:  �[1m�[92m   Compiling�[0m reserve-port v2.3.0
2969:  �[1m�[92m   Compiling�[0m bytesize v2.3.1
2970:  �[1m�[92m   Compiling�[0m unsafe-libyaml v0.2.11
2971:  �[1m�[92m   Compiling�[0m axum-test v18.7.0
2972:  �[1m�[92m   Compiling�[0m serde_yaml_ng v0.10.0
2973:  �[1m�[92m   Compiling�[0m tokio-test v0.4.5
2974:  �[1m�[92m   Compiling�[0m flight-service v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-service)
2975:  �[1m�[92m    Finished�[0m `test` profile [unoptimized + debuginfo] target(s) in 3m 19s
2976:  �[1m�[92m     Running�[0m unittests src\lib.rs (target\debug\deps\flight_service-d8f82d75b9ff0e24.exe)
2977:  running 2 tests
2978:  test fd_safety_tests::fd_usage_examples::test_service_fd_usage_examples ... ok
2979:  test fd_safety_tests::windows_tests::test_service_system_handle_safety ... ok
2980:  test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 408 filtered out; finished in 0.00s
2981:  �[1m�[92m     Running�[0m unittests src\main.rs (target\debug\deps\flightd-84913256cb38b6a4.exe)
2982:  running 0 tests
2983:  test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
2984:  �[1m�[92m     Running�[0m tests\service_integration.rs (target\debug\deps\service_integration-db98d8c9f0c173a1.exe)
2985:  running 0 tests
2986:  test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 9 filtered out; finished in 0.00s
2987:  �[1m�[92m     Running�[0m tests\service_integration_tests.rs (target\debug\deps\service_integration_tests-fcdf243b87b47859.exe)
2988:  running 0 tests
2989:  test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 11 filtered out; finished in 0.00s
2990:  ##[group]Run echo "🔍 Verifying critical patterns are fixed..."
...

3009:  �[36;1mfi�[0m
3010:  �[36;1m�[0m
3011:  �[36;1m# Check for criterion::black_box usage�[0m
3012:  �[36;1mif git grep -n "criterion::black_box" -- 'crates/' 'benches/'; then�[0m
3013:  �[36;1m  echo "❌ Found criterion::black_box - should be std::hint::black_box"�[0m
3014:  �[36;1m  exit 1�[0m
3015:  �[36;1mfi�[0m
3016:  �[36;1m�[0m
3017:  �[36;1mecho "✅ All critical patterns verified"�[0m
3018:  shell: C:\Program Files\Git\bin\bash.EXE --noprofile --norc -e -o pipefail {0}
3019:  env:
3020:  CARGO_TERM_COLOR: always
3021:  RUST_BACKTRACE: 1
3022:  CARGO_HOME: C:\Users\runneradmin\.cargo
3023:  CARGO_INCREMENTAL: 0
3024:  CACHE_ON_FAILURE: false
3025:  ##[endgroup]
3026:  🔍 Verifying critical patterns are fixed...
3027:  ✅ All critical patterns verified
3028:  ##[group]Run cargo test --all-features --workspace --lib --tests --exclude flight-hub-examples
3029:  �[36;1mcargo test --all-features --workspace --lib --tests --exclude flight-hub-examples�[0m
3030:  shell: C:\Program Files\Git\bin\bash.EXE --noprofile --norc -e -o pipefail {0}
3031:  env:
3032:  CARGO_TERM_COLOR: always
3033:  RUST_BACKTRACE: 1
3034:  CARGO_HOME: C:\Users\runneradmin\.cargo
3035:  CARGO_INCREMENTAL: 0
3036:  CACHE_ON_FAILURE: false
3037:  ##[endgroup]
...

3169:  �[1m�[92m   Compiling�[0m flight-hotas-ch v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-hotas-ch)
3170:  �[1m�[92m   Compiling�[0m flight-hotas-logitech v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-hotas-logitech)
3171:  �[1m�[92m   Compiling�[0m flight-hotas-virpil v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-hotas-virpil)
3172:  �[1m�[92m   Compiling�[0m flight-hotas-honeycomb v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-hotas-honeycomb)
3173:  �[1m�[92m   Compiling�[0m flight-hotas-vpforce v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-hotas-vpforce)
3174:  �[1m�[92m   Compiling�[0m flight-hotas-saitek v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-hotas-saitek)
3175:  �[1m�[92m   Compiling�[0m flight-hotas-brunner v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-hotas-brunner)
3176:  �[1m�[92m   Compiling�[0m crossbeam-utils v0.8.21
3177:  �[1m�[92m   Compiling�[0m flight-integration-tests v0.1.0 (D:\a\OpenFlight\OpenFlight\crates\flight-integration-tests)
3178:  �[1m�[92m   Compiling�[0m num-integer v0.1.46
3179:  �[1m�[92m   Compiling�[0m crossbeam-epoch v0.9.18
3180:  �[1m�[92m   Compiling�[0m crossbeam-deque v0.8.6
3181:  �[1m�[92m   Compiling�[0m num-bigint v0.4.6
3182:  �[1m�[92m   Compiling�[0m crossbeam-channel v0.5.15
3183:  �[1m�[92m   Compiling�[0m crossbeam-queue v0.3.12
3184:  �[1m�[92m   Compiling�[0m quick-error v1.2.3
3185:  �[1m�[92m   Compiling�[0m wait-timeout v0.2.1
...

3400:  �[1m�[93mwarning�[0m: `flight-axis` (test "detent_integration") generated 9 warnings
3401:  �[1m�[93mwarning[E0133]�[0m�[1m�[97m: call to unsafe function `flight_axis::Node::step_soa` is unsafe and requires unsafe block�[0m
3402:  �[1m�[96m--> �[0mcrates\flight-axis\tests\detent_tests.rs:25:5
3403:  �[1m�[96m|�[0m
3404:  �[1m�[96m25�[0m �[1m�[96m|�[0m     node.step_soa(frame, state_ptr);
3405:  �[1m�[96m|�[0m     �[1m�[93m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^�[0m �[1m�[93mcall to unsafe function�[0m
3406:  �[1m�[96m|�[0m
3407:  �[1m�[96m= �[0m�[1m�[97mnote�[0m: for more information, see <https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
3408:  �[1m�[96m= �[0m�[1m�[97mnote�[0m: consult the function's documentation for information on how to avoid undefined behavior
3409:  �[1m�[92mnote�[0m: an unsafe function restricts its caller, but its body is safe by default
3410:  �[1m�[96m--> �[0mcrates\flight-axis\tests\detent_tests.rs:23:1
3411:  �[1m�[96m|�[0m
3412:  �[1m�[96m23�[0m �[1m�[96m|�[0m unsafe fn process_frame_soa(node: &DetentNode, frame: &mut AxisFrame, state: &mut DetentState) {
3413:  �[1m�[96m|�[0m �[1m�[92m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^�[0m
3414:  �[1m�[96m= �[0m�[1m�[97mnote�[0m: `#[warn(unsafe_op_in_unsafe_fn)]` (part of `#[warn(rust_2024_compatibility)]`) on by default
3415:  �[1m�[97mFor more information about this error, try `rustc --explain E0133`.�[0m
3416:  �[1m�[93mwarning�[0m: `flight-axis` (test "detent_tests") generated 1 warning (run `cargo fix --test "detent_tests" -p flight-axis` to apply 1 suggestion)
...

3455:  test tests::applies_profile_replaces_existing_managed_block ... ok
3456:  test tests::managed_block_is_idempotent ... ok
3457:  test tests::install_creates_dir_and_file ... ok
3458:  test tests::installs_with_backup ... ok
3459:  test tests::rc_mode_index_values ... ok
3460:  test tests::renders_all_rc_modes ... ok
3461:  test tests::renders_managed_block ... ok
3462:  test tests::steam_input_hint_is_nonempty ... ok
3463:  test tests::validates_empty_profile_name ... ok
3464:  test tests::validates_out_of_range_deadzone ... ok
3465:  test tests::validates_out_of_range_exponent ... ok
3466:  test tests::validates_out_of_range_scale ... ok
3467:  test tests::property_valid_deadzone_range_accepted ... ok
3468:  test tests::property_valid_exponent_range_accepted ... ok
3469:  test tests::property_valid_scale_range_accepted ... ok
3470:  test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
3471:  �[1m�[92m     Running�[0m unittests src\lib.rs (target\debug\deps\flight_ac7_protocol-79ecd42f070e313c.exe)
3472:  running 13 tests
3473:  test tests::aircraft_label_trims_whitespace ... ok
3474:  test tests::parses_valid_packet ... ok
3475:  test tests::defaults_schema_and_label ... ok
3476:  test tests::json_round_trip ... ok
3477:  test tests::property_bounded_altitude_valid ... ok
3478:  test tests::rejects_invalid_json ... ok
3479:  test tests::property_pitch_control_is_bounded ... ok
3480:  test tests::rejects_negative_speed ... ok
3481:  test tests::rejects_out_of_range_altitude ... ok
3482:  test tests::property_out_of_bounds_throttle_rejected ... ok
3483:  test tests::rejects_out_of_range_control_value ... ok
3484:  test tests::rejects_wrong_schema ... ok
3485:  test tests::property_all_bounded_controls_valid ... ok
3486:  test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
3487:  �[1m�[92m     Running�[0m unittests src\lib.rs (target\debug\deps\flight_ac7_telemetry-c0c6090b90882fbf.exe)
3488:  running 10 tests
3489:  test tests::adapter_initial_state_is_disconnected ... ok
3490:  test tests::metrics_registry_tracks_config ... ok
3491:  test tests::snapshot_has_correct_sim_id ... ok
3492:  test tests::converts_packet_to_snapshot ... ok
3493:  test tests::snapshot_control_inputs_mapped ... ok
3494:  test tests::snapshot_validity_partial_packet ... ok
3495:  test tests::snapshot_validity_flags_set_from_full_packet ... ok
3496:  test tests::start_stop_cycle ... ok
3497:  test tests::poll_updates_source_addr ... ok
3498:  test tests::udp_poll_receives_packet ... ok
3499:  test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
3500:  �[1m�[92m     Running�[0m unittests src\lib.rs (target\debug\deps\flight_adapter_common-3fd27606273cc5dd.exe)
3501:  running 19 tests
3502:  test metrics::tests::test_record_update_tracks_samples ... ok
3503:  test metrics::tests::test_record_aircraft_change ... ok
3504:  test reconnect_backoff::tests::test_exponential_growth ... ok
3505:  test reconnect_backoff::tests::test_first_delay_equals_initial ... ok
3506:  test reconnect_backoff::tests::test_jitter_stays_within_bounds ... ok
3507:  test reconnect_backoff::tests::test_jitter_zero_means_no_jitter ... ok
3508:  test reconnect_backoff::tests::test_max_delay_cap ... ok
3509:  test reconnect_backoff::tests::test_reset_restarts_sequence ... ok
3510:  test reconnection::tests::test_backoff_progression ... ok
3511:  test reconnection::tests::test_should_retry ... ok
3512:  test tests::adapter_metrics_summary_format ... ok
3513:  test tests::adapter_error_display_variants ... ok
3514:  test tests::adapter_metrics_total_updates_increment ... ok
3515:  test tests::adapter_state_all_variants_debug ... ok
3516:  test tests::adapter_state_equality ... ok
3517:  test tests::reconnection_strategy_initial_backoff_on_first_attempt ... ok
3518:  test tests::reconnection_strategy_max_backoff_caps ... ok
3519:  test reconnect_backoff::tests::test_invalid_jitter_panics - should panic ... ok
3520:  test reconnect_backoff::tests::test_invalid_multiplier_panics - should panic ... ok
3521:  test result: ok. 19 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.08s
3522:  �[1m�[92m     Running�[0m unittests src\lib.rs (target\debug\deps\flight_aerofly-4369114a3a30ae5e.exe)
3523:  running 36 tests
3524:  test tests::adapter_custom_port ... ok
3525:  test tests::adapter_default_port ... ok
3526:  test tests::adapter_no_telemetry_initially ... ok
3527:  test tests::adapter_process_datagram_updates_last ... ok
3528:  test tests::adapter_process_invalid_datagram_returns_error ... ok
3529:  test tests::adapter_process_json_updates_last ... ok
3530:  test tests::adapter_process_text_updates_last ... ok
3531:  test tests::aircraft_type_case_insensitive ... ok
3532:  test tests::airspeed_conversion_knots_to_ms ... ok
3533:  test tests::aircraft_type_from_name ... ok
3534:  test tests::altitude_conversion_ft_to_m ... ok
3535:  test tests::attitude_conversion_deg_to_rad ... ok
3536:  test tests::bad_magic_returns_error ... ok
3537:  test tests::empty_frame_returns_error ... ok
3538:  test tests::flaps_ratio_clamped_below_zero ... ok
3539:  test tests::frame_too_short_returns_error ... ok
3540:  test tests::gear_down_byte_nonzero ... ok
3541:  test tests::gear_up_byte_zero ... ok
3542:  test tests::invalid_json_returns_error ... ok
3543:  test tests::json_vspeed_defaults_to_zero_when_absent ... ok
3544:  test tests::parse_text_all_fields ... ok
3545:  test tests::parse_text_empty_returns_error ... ok
3546:  test tests::parse_text_gear_state_boundary ... ok
3547:  test tests::parse_text_invalid_numbers_default_to_zero ... ok
3548:  test tests::parse_text_negative_altitude ... ok
3549:  test tests::parse_text_partial_uses_defaults ... ok
3550:  test tests::parse_text_throttle_clamped ... ok
3551:  test tests::parse_text_unknown_keys_ignored ... ok
3552:  test tests::parse_text_whitespace_tolerance ... ok
3553:  test tests::parse_valid_binary_frame ... ok
3554:  test tests::parse_valid_json ... ok
3555:  test tests::telemetry_default_values ... ok
3556:  test tests::telemetry_serde_round_trip ... ok
3557:  test tests::throttle_clamped_above_one ... ok
3558:  test tests::vspeed_conversion_fpm_to_ms ... ok
3559:  test tests::zero_altitude_conversion ... ok
3560:  test result: ok. 36 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
3561:  �[1m�[92m     Running�[0m tests\integration_tests.rs (target\debug\deps\integration_tests-dfca06ac3711825a.exe)
3562:  running 10 tests
3563:  test airspeed_and_vertical_state_fields_present ... ok
3564:  test attitude_roll_pitch_heading_in_correct_units ... ok
3565:  test adapter_processes_binary_and_json_paths ... ok
3566:  test adapter_json_round_trip_preserves_all_fields ... ok
3567:  test coordinates_altitude_and_heading_decoded_correctly ... ok
3568:  test unit_conversion_helpers_are_consistent ... ok
3569:  test text_format_parsed_and_all_three_paths_work ... ok
3570:  test missing_fields_in_json_returns_error_gracefully ... ok
3571:  test malformed_json_returns_error_not_panic ... ok
3572:  test valid_json_telemetry_packet_parsed ... ok
3573:  test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
3574:  �[1m�[92m     Running�[0m unittests src\lib.rs (target\debug\deps\flight_axis-40c750a44d747997.exe)
...

3581:  test accumulator::tests::test_reset_to_zero ... ok
3582:  test accumulator::tests::test_scale_factor ... ok
3583:  test accumulator::tests::test_wrap_negative ... ok
3584:  test accumulator::tests::test_wrap_positive ... ok
3585:  test blackbox::tests::test_annotator_creation ... ok
3586:  test blackbox::tests::test_disabled_annotation ... ok
3587:  test blackbox::tests::test_conflict_annotation ... ok
3588:  test blackbox::tests::test_buffer_flush ... ok
3589:  test blackbox::tests::test_conflict_data_conversion ... ok
3590:  test blackbox::tests::test_disabled_annotator ... ok
3591:  test blackbox::tests::test_resolution_annotation ... ok
3592:  test buttons::tests::test_axis_offset_action ... ok
3593:  test buttons::tests::test_axis_set_action ... ok
3594:  test buttons::tests::test_chord_partial_press_no_fire ... ok
3595:  test buttons::tests::test_chord_requires_all_buttons ... ok
3596:  test buttons::tests::test_chord_too_many_buttons_error ... ok
3597:  test buttons::tests::test_clear_removes_all_macros ... ok
3598:  test buttons::tests::test_duplicate_button_error ... ok
3599:  test buttons::tests::test_empty_chord_error ... ok
3600:  test buttons::tests::test_hold_fires_after_threshold ... ok
...

3623:  test calibration::tests::test_calbank_insert_and_get ... ok
3624:  test calibration::tests::test_calbank_unknown_axis_uses_default ... ok
3625:  test calibration::tests::test_normalize_8bit ... ok
3626:  test calibration::tests::test_normalize_above_deadband ... ok
3627:  test calibration::tests::test_normalize_center_is_zero ... ok
3628:  test calibration::tests::test_normalize_clamped_above_max ... ok
3629:  test calibration::tests::test_normalize_clamped_below_min ... ok
3630:  test calibration::tests::test_normalize_deadband_near_center ... ok
3631:  test buttons::tests::proptest_output_count_never_exceeds_8 ... ok
3632:  test calibration::tests::test_normalize_max_is_one ... ok
3633:  test calibration::tests::test_normalize_midpoint_above_center ... ok
3634:  test calibration::tests::test_normalize_midpoint_below_center ... ok
3635:  test calibration::tests::test_normalize_min_equals_max ... ok
3636:  test calibration::tests::test_normalize_min_is_neg_one ... ok
3637:  test calibration::tests::test_normalize_virpil_14bit ... ok
3638:  test calibration_wizard::tests::center_detection_noisy_fails ... ok
3639:  test calibration_wizard::tests::center_detection_stable_succeeds ... ok
3640:  test calibration_wizard::tests::complete_produces_result ... ok
3641:  test calibration_wizard::tests::deadzone_recommends_value ... ok
3642:  test calibration_wizard::tests::initial_state_is_not_started ... ok
3643:  test calibration_wizard::tests::progress_increases_through_steps ... ok
3644:  test calibration_wizard::tests::reset_returns_to_not_started ... ok
3645:  test calibration_wizard::tests::samples_ignored_in_terminal_states ... ok
3646:  test calibration_wizard::tests::start_transitions_to_center_detection ... ok
3647:  test calibration_wizard::tests::sweep_detects_full_range ... ok
3648:  test calibration_wizard::tests::sweep_insufficient_range_fails ... ok
3649:  test calibration_wizard::tests::timeout_fails_center_detection ... ok
3650:  test calibration_wizard::tests::verification_fails_non_monotonic ... ok
3651:  test calibration_wizard::tests::verification_passes_linear ... ok
...

3740:  test curve::tests::test_expo_negative_increases_center_sensitivity ... ok
3741:  test curve::tests::test_expo_one_input_maps_to_one ... ok
3742:  test curve::tests::test_expo_positive_reduces_center_sensitivity ... ok
3743:  test curve::tests::test_expo_zero_input_maps_to_zero ... ok
3744:  test curve::tests::test_expo_zero_is_linear ... ok
3745:  test curve::tests::test_is_monotone_identity ... ok
3746:  test curve::tests::test_linear_identity_constructor ... ok
3747:  test curve::tests::test_linear_identity_evaluates_x ... ok
3748:  test curve::tests::test_linear_identity_one ... ok
3749:  test curve::tests::test_linear_identity_zero ... ok
3750:  test curve::tests::test_linear_interpolation_midpoint ... ok
3751:  test curve::tests::prop_output_always_in_range ... ok
3752:  test curve::tests::test_monotone_cubic_identity ... ok
3753:  test curve::tests::test_standard_deadzone_expo_curve ... ok
3754:  test curve::tests::test_monotone_cubic_preserves_monotone ... ok
3755:  test curve::tests::test_too_few_points_error ... ok
3756:  test curve::tests::test_unsorted_points_error ... ok
3757:  test deadzone::tests::prop_output_in_range ... ok
...

3763:  test deadzone::tests::test_asymmetric_negative_deadzone ... ok
3764:  test deadzone::tests::test_asymmetric_positive_deadzone ... ok
3765:  test deadzone::tests::test_asymmetric_symmetric_matches_center_only ... ok
3766:  test deadzone::tests::test_asymmetric_zero_positive_passes_positive ... ok
3767:  test deadzone::tests::test_bank_apply ... ok
3768:  test deadzone::tests::test_bank_set_config ... ok
3769:  test deadzone::tests::test_center_deadzone_full_deflection ... ok
3770:  test deadzone::tests::test_center_deadzone_negative ... ok
3771:  test deadzone::tests::test_center_deadzone_outside_zone ... ok
3772:  test deadzone::tests::test_center_deadzone_within_zone ... ok
3773:  test deadzone::tests::test_clamp_above_one ... ok
3774:  test deadzone::tests::test_clamp_below_neg_one ... ok
3775:  test deadzone::tests::test_combined_center_and_edge ... ok
3776:  test deadzone::tests::test_edge_deadzone_below ... ok
3777:  test deadzone::tests::test_edge_deadzone_saturation ... ok
3778:  test deadzone::tests::test_invalid_center_error ... ok
3779:  test deadzone::tests::test_overlap_error ... ok
3780:  test deadzone::tests::test_zero_deadzone_passthrough ... ok
...

3902:  test invert::tests::test_invert_disabled_passthrough ... ok
3903:  test invert::tests::test_invert_enabled_negates ... ok
3904:  test invert::tests::test_invert_negative_one ... ok
3905:  test invert::tests::test_invert_positive_one ... ok
3906:  test invert::tests::test_invert_toggle ... ok
3907:  test invert::tests::test_invert_zero_unchanged ... ok
3908:  test lag_compensator::tests::first_sample_passes_through ... ok
3909:  test lag_compensator::tests::max_prediction_clamped ... ok
3910:  test lag_compensator::tests::moving_axis_is_predicted_ahead ... ok
3911:  test lag_compensator::tests::nan_passes_through_unchanged ... ok
3912:  test lag_compensator::tests::negative_movement_predicts_backward ... ok
3913:  test lag_compensator::tests::output_is_clamped_to_valid_range ... ok
3914:  test lag_compensator::tests::reset_clears_initialized ... ok
3915:  test lag_compensator::tests::static_axis_unchanged ... ok
3916:  test lag_compensator::tests::zero_dt_uses_last_dt ... ok
3917:  test mixer::tests::add_input_beyond_max_fails ... ok
3918:  test mixer::tests::add_input_increments_count ... ok
...

3994:  test pid::tests::test_pid_bank_reset_not_needed ... ok
3995:  test pid::tests::test_pid_bank_update_known_axis ... ok
3996:  test pid::tests::test_pid_bank_update_unknown_axis ... ok
3997:  test pid::tests::test_pid_converges_step_response ... ok
3998:  test pid::tests::test_pid_derivative_on_step ... ok
3999:  test pid::tests::test_pid_derivative_zero_first_tick ... ok
4000:  test pid::tests::test_pid_integral_accumulates ... ok
4001:  test pid::tests::test_pid_integral_windup_limited ... ok
4002:  test pid::tests::test_pid_output_clamped_to_1 ... ok
4003:  test pid::tests::test_pid_output_clamped_to_neg1 ... ok
4004:  test pid::tests::test_pid_proportional_only ... ok
4005:  test pid::tests::test_pid_reset_clears_state ... ok
4006:  test pid::tests::test_pid_set_integral_clamped ... ok
4007:  test pid::tests::test_pid_setpoint_above_pv ... ok
4008:  test pid::tests::test_pid_setpoint_below_pv ... ok
4009:  test pid::tests::test_pid_zero_error ... ok
4010:  test pipeline::tests::test_alignment ... ok
...

4024:  test pipeline::tests::test_enable_stage_after_bypass ... ok
4025:  test pipeline::tests::test_insert_stage_at_beginning ... ok
4026:  test pipeline::tests::test_insert_stage_at_end ... ok
4027:  test pipeline::tests::test_pipeline_multi_stage ... ok
4028:  test pipeline::tests::test_pipeline_state_creation ... ok
4029:  test pipeline::tests::test_remove_stage_out_of_bounds ... ok
4030:  test pipeline::tests::test_remove_stage_returns_stage ... ok
4031:  test pipeline::tests::test_sensitivity_stage ... ok
4032:  test pipeline::tests::test_smoothing_stage ... ok
4033:  test pipeline::tests::test_stage_count ... ok
4034:  test pipeline::tests::test_stage_names ... ok
4035:  test pipeline::tests::test_stages_accessor ... ok
4036:  test pipeline_bypass::tests::bypass_all_then_clear ... ok
4037:  test pipeline_bypass::tests::clear_single_stage ... ok
4038:  test pipeline_bypass::tests::default_is_empty ... ok
4039:  test pid::tests::proptest_zero_error_zero_output ... ok
4040:  test pipeline_bypass::tests::from_bits_round_trip ... ok
...

4110:  test recording::tests::test_playback_advance_returns_samples_in_window ... ok
4111:  test recording::tests::test_playback_is_finished_at_end ... ok
4112:  test recording::tests::test_playback_looping_wraps_around ... ok
4113:  test recording::tests::test_playback_rewind ... ok
4114:  test recording::tests::test_record_multiple_samples ... ok
4115:  test recording::tests::test_record_single_sample ... ok
4116:  test recording::tests::test_recording_duration ... ok
4117:  test recording::tests::test_recording_empty_by_default ... ok
4118:  test recording::tests::test_samples_in_range ... ok
4119:  test scale::tests::test_bank_apply ... ok
4120:  test scale::tests::test_bank_set_scale ... ok
4121:  test scale::tests::test_scale_clamp_max ... ok
4122:  test scale::tests::test_scale_clamp_min ... ok
4123:  test scale::tests::test_scale_default_passthrough ... ok
4124:  test scale::tests::test_scale_factor_half ... ok
4125:  test scale::tests::test_scale_invalid_range_error ... ok
4126:  test scale::tests::test_scale_nan_factor_error ... ok
4127:  test scale::tests::test_scale_negative_factor ... ok
...

4246:  test stages::tests::very_large_values_handled ... ok
4247:  test throttle_zone::tests::prop_output_always_in_range ... ok
4248:  test throttle_zone::tests::test_afterburner_zone_event ... ok
4249:  test throttle_zone::tests::test_builder_pattern ... ok
4250:  test throttle_zone::tests::test_combined_cut_and_milpower ... ok
4251:  test throttle_zone::tests::test_cut_zone_above_threshold ... ok
4252:  test throttle_zone::tests::test_cut_zone_at_threshold ... ok
4253:  test throttle_zone::tests::prop_event_count_never_exceeds_4 ... ok
4254:  test throttle_zone::tests::test_cut_zone_below_threshold ... ok
4255:  test throttle_zone::tests::test_max_zone_below_threshold ... ok
4256:  test throttle_zone::tests::test_max_zone_saturation ... ok
4257:  test throttle_zone::tests::test_milpower_zone_event_on_entry ... ok
4258:  test throttle_zone::tests::test_milpower_zone_event_on_exit ... ok
4259:  test throttle_zone::tests::test_no_zones_passthrough ... ok
4260:  test throttle_zone::tests::test_process_clamped_input_above_one ... ok
4261:  test throttle_zone::tests::test_validate_cut_above_max_error ... ok
4262:  test throttle_zone::tests::test_validate_invalid_cut_threshold ... ok
...

4287:  test trim::tests::test_trimbank_apply_unknown_axis ... ok
4288:  test trim::tests::test_trimbank_get_or_insert ... ok
4289:  test trim::tests::test_trimbank_reset_all ... ok
4290:  test trim::tests::proptest_apply_output_bounded ... ok
4291:  test velocity::tests::test_velocity_invalid_alpha_panics - should panic ... ok
4292:  test velocity::tests::test_velocity_negative_movement ... ok
4293:  test velocity::tests::test_velocity_no_smoothing ... ok
4294:  test velocity::tests::test_velocity_positive_movement ... ok
4295:  test velocity::tests::test_velocity_invalid_period_panics - should panic ... ok
4296:  test velocity::tests::test_velocity_reset ... ok
4297:  test velocity::tests::test_velocity_smoothing ... ok
4298:  test velocity::tests::test_velocity_units ... ok
4299:  test trim::tests::proptest_decrement_bounded ... ok
4300:  test velocity::tests::test_velocity_zero_at_rest ... ok
4301:  test trim::tests::proptest_increment_bounded ... ok
4302:  test result: ok. 726 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.52s
4303:  �[1m�[92m     Running�[0m tests\detent_integration.rs (target\debug\deps\detent_integration-e4480f02c14a395d.exe)
4304:  running 8 tests
4305:  test test_detent_events_in_pipeline ... ok
4306:  test test_detent_builder_api ... ok
4307:  test test_detent_hysteresis_with_slew ... ok
4308:  test test_detent_in_complete_pipeline ... ok
4309:  test test_detent_output_snapping ... ok
4310:  test test_detent_with_curve_interaction ... ok
4311:  test test_multiple_detent_transitions ... ok
4312:  test test_detent_performance_in_pipeline ... ok
4313:  test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.65s
4314:  �[1m�[92m     Running�[0m tests\detent_tests.rs (target\debug\deps\detent_tests-20ec193189a81072.exe)
4315:  running 13 tests
4316:  test test_detent_zone_clamping ... ok
4317:  test test_detent_role_names ... ok
4318:  test test_detent_zone_containment ... ok
4319:  test test_detent_zone_creation ... ok
4320:  test test_hysteresis_prevents_flapping ... ok
4321:  test test_multiple_detents_no_overlap ... ok
4322:  test test_no_snap_detent ... ok
4323:  test test_node_trait_implementation ... ok
4324:  test test_single_detent_entry_exit ... ok
4325:  test test_sweep_single_transitions ... ok
4326:  test test_zone_sorting ... ok
4327:  test test_hysteresis_stability ... ok
4328:  test test_deterministic_detent_behavior ... ok
4329:  test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s
4330:  �[1m�[92m     Running�[0m tests\filter_tests.rs (target\debug\deps\filter_tests-6526b0b860e21a54.exe)
4331:  running 10 tests
4332:  test test_filter_alpha_zero_holds_initial_value ... ok
4333:  test test_filter_alpha_one_is_identity ... ok
4334:  test test_b104_spike_rejection_ignores_single_transient ... ok
4335:  test test_filter_converges_toward_constant_input ... ok
4336:  test test_filter_first_sample_passthrough ... ok
4337:  test test_filter_ema_smoothing_on_step_input ... ok
4338:  test test_filter_inf_does_not_panic ... ok
4339:  test test_filter_nan_does_not_panic ... ok
4340:  test test_filter_output_bounded_for_valid_inputs ... ok
4341:  test filter_output_in_range ... ok
4342:  test result: ok. 10 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
4343:  �[1m�[92m     Running�[0m tests\integration_tests.rs (target\debug\deps\integration_tests-06c91449628a7bc8.exe)
4344:  running 26 tests
4345:  test test_allocation_guard ... ok
4346:  test test_axis_engine_creation ... ok
4347:  test test_axis_engine_process_without_pipeline ... ok
4348:  test test_atomic_pipeline_swap_with_ack ... ok
4349:  test test_axis_engine_with_config ... ok
4350:  test test_axis_frame_creation ... ok
4351:  test test_axis_frame_derivative_calculation ... ok
4352:  test test_compile_failure_safety ... ok
4353:  test test_curve_node_exponential ... ok
...

4356:  test test_deadzone_node_symmetric ... ok
4357:  test test_deterministic_processing ... ok
4358:  test test_end_to_end_pipeline_processing ... ok
4359:  test test_node_state_sizes ... ok
4360:  test test_node_type_identification ... ok
4361:  test test_performance_snapshot ... ok
4362:  test test_pipeline_builder ... ok
4363:  test test_pipeline_state_validation ... ok
4364:  test test_runtime_counters ... ok
4365:  test test_runtime_counters_averaging ... ok
4366:  test test_slew_node_rate_limiting ... ok
4367:  test test_zero_allocation_constraint_validation ... ok
4368:  test test_zero_allocation_guarantee ... ok
4369:  test test_processing_performance ... ok
4370:  test test_performance_under_load ... ok
4371:  test result: ok. 26 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.68s
4372:  �[1m�[92m     Running�[0m tests\mixer_tests.rs (target\debug\deps\mixer_tests-5e53fcb2ba9fde26.exe)
...

4389:  test test_mixer_input_creation ... ok
4390:  test test_mixer_input_with_scale ... ok
4391:  test test_mixer_mathematical_properties ... ok
4392:  test test_mixer_node_creation ... ok
4393:  test test_mixer_node_creation_with_invalid_config ... ok
4394:  test test_mixer_node_trait_implementation ... ok
4395:  test test_mixer_process_inputs_basic ... ok
4396:  test test_mixer_process_inputs_no_clamp ... ok
4397:  test test_mixer_process_inputs_with_gain ... ok
4398:  test test_mixer_soa_step_processing ... ok
4399:  test test_mixer_state_initialization ... ok
4400:  test test_mixer_unit_handling_validation ... ok
4401:  test test_mixer_zero_allocation_constraint ... ok
4402:  test test_mixer_zero_allocation_integration ... ok
4403:  test test_mixer_performance_characteristics ... ok
4404:  test result: ok. 30 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
4405:  �[1m�[92m     Running�[0m tests\performance_validation.rs (target\debug\deps\performance_validation-089fcfcc16391971.exe)
4406:  running 4 tests
4407:  test test_atomic_swap_performance ... ok
4408:  test test_jitter_requirements ... ok
4409:  test test_rt_performance_requirements ... ok
4410:  test test_zero_allocation_validation ... ok
4411:  test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.60s
4412:  �[1m�[92m     Running�[0m tests\pipeline_composition_tests.rs (target\debug\deps\pipeline_composition_tests-a708998be0ddc904.exe)
4413:  running 11 tests
4414:  test test_deadzone_curve_output_is_monotone_for_positive_inputs ... ok
4415:  test test_filter_smooths_step_after_deadzone ... ok
4416:  test test_max_positive_input_stays_bounded_through_deadzone_curve_slew ... ok
4417:  test test_nan_input_does_not_panic_in_full_pipeline ... ok
4418:  test test_neg_inf_does_not_panic_in_deadzone_pipeline ... ok
4419:  test test_positive_inf_does_not_panic_in_full_pipeline ... ok
4420:  test test_slew_limits_sudden_large_jump ... ok
4421:  test test_zero_input_stays_zero_through_deadzone_curve_slew ... ok
4422:  test full_pipeline_output_in_range ... ok
4423:  test deadzone_curve_output_in_range ... ok
4424:  test deadzone_curve_is_monotone_for_positive_inputs ... ok
4425:  test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
4426:  �[1m�[92m     Running�[0m tests\pipeline_integration.rs (target\debug\deps\pipeline_integration-7cd534de7282c6a7.exe)
4427:  running 7 tests
4428:  test test_pipeline_max_input_max_trim_clamps ... ok
4429:  test test_pipeline_max_input_no_trim ... ok
4430:  test test_pipeline_center_no_processing ... ok
4431:  test test_pipeline_min_input_no_trim ... ok
4432:  test test_pipeline_output_always_bounded ... ok
4433:  test test_pipeline_rate_limit_slows_changes ... ok
4434:  test test_pipeline_smoothing_reduces_step_response ... ok
4435:  test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
4436:  �[1m�[92m     Running�[0m tests\proptest_invariants.rs (target\debug\deps\proptest_invariants-266413960930285b.exe)
4437:  running 14 tests
4438:  test clamp_never_exceeds_bounds ... ok
4439:  test expo_preserves_sign ... ok
4440:  test expo_output_bounded ... ok
4441:  test deadzone_output_zero_within_zone ... ok
4442:  test rt_deadzone_output_bounded ... ok
4443:  test rt_curve_expo_monotone ... ok
4444:  test pipeline_output_finite ... ok
4445:  test rt_pipeline_output_finite ... ok
4446:  test saturation_bipolar_bounds ... ok
4447:  test saturation_output_within_bounds ... ok
4448:  test slew_rate_unlimited_passthrough ... ok
4449:  test smoothing_ema_converges_to_constant ... ok
4450:  test slew_rate_delta_bounded ... ok
4451:  test smoothing_output_always_finite ... ok
4452:  test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s
4453:  �[1m�[92m     Running�[0m tests\rt_coverage.rs (target\debug\deps\rt_coverage-c809db928d4cfe76.exe)
...

4464:  test test_combined_deadzone_expo_zeroes_inside_zone ... ok
4465:  test test_curve_expo_one_max_curvature ... ok
4466:  test test_curve_expo_zero_is_linear ... ok
4467:  test test_curve_scurve_reduces_centre_gain ... ok
4468:  test test_deadzone_negative_boundary ... ok
4469:  test test_deadzone_value_at_exact_threshold ... ok
4470:  test test_deadzone_value_inside_is_zero ... ok
4471:  test test_deadzone_value_just_outside_is_nonzero ... ok
4472:  test test_range_clamp_at_limits ... ok
4473:  test test_split_bipolar_half_positive ... ok
4474:  test test_split_bipolar_negative_one ... ok
4475:  test test_split_bipolar_positive_one ... ok
4476:  test test_split_bipolar_zero ... ok
4477:  test prop_split_bipolar_sum_equals_abs ... ok
4478:  test prop_combine_differential_bounded ... ok
4479:  test result: ok. 24 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
4480:  �[1m�[92m     Running�[0m tests\rt_timing_test.rs (target\debug\deps\rt_timing_test-d544fa381936811a.exe)
4481:  running 2 tests
4482:  test axis_pipeline_p99_within_4ms_budget ... ok
4483:  test axis_pipeline_fits_in_rt_budget ... ok
4484:  test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.09s
4485:  �[1m�[92m     Running�[0m tests\snapshot_tests.rs (target\debug\deps\snapshot_tests-1111d5c199650f93.exe)
4486:  running 3 tests
4487:  test snapshot_deadzone_expo_pipeline_output_values ... ok
4488:  test snapshot_curve_node_expo_0_4_outputs ... ok
4489:  test snapshot_deadzone_expo_pipeline_metadata ... ok
4490:  test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.16s
4491:  �[1m�[92m     Running�[0m unittests src\lib.rs (target\debug\deps\flight_bdd_metrics-6c5f6221692ddcc3.exe)
4492:  running 14 tests
4493:  test tests::coverage_percent_zero_denominator_returns_zero ... ok
4494:  test tests::coverage_percent_full_coverage ... ok
4495:  test tests::bdd_scenario_ac_tags_filters_non_ac_tags ... ok
4496:  test tests::bdd_traceability_row_coverage_methods ... ok
4497:  test tests::coverage_status_compute_all_branches ... ok
4498:  test tests::extract_crates_from_reference_cmd_prefix ... ok
4499:  test tests::extract_crates_from_command_parses_p_flag ... ok
4500:  test tests::extract_crates_from_reference_double_colon_notation ... ok
4501:  test tests::is_crate_name_candidate_valid_and_invalid ... ok
4502:  test tests::is_scenario_header_recognises_scenario_types ... ok
4503:  test tests::normalize_crate_name_strips_quotes_and_underscores ... ok
4504:  test tests::parse_tags_from_line_extracts_tags ... ok
4505:  test tests::with_workspace_crates_filters_non_workspace_rows ... ok
4506:  test tests::with_workspace_crates_preserves_unmapped_row ... ok
4507:  test result: ok. 14 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
4508:  �[1m�[92m     Running�[0m unittests src\lib.rs (target\debug\deps\flight_blackbox-8985d4d59c430f37.exe)
...

4533:  test recorder::tests::iterator_exact_size ... ok
4534:  test export::tests::json_csv_agree_on_axis_count ... ok
4535:  test recorder::tests::mixed_record_types_in_buffer ... ok
4536:  test recorder::tests::new_recorder_is_empty ... ok
4537:  test recorder::tests::record_and_retrieve_axis ... ok
4538:  test recorder::tests::large_overflow_preserves_newest ... ok
4539:  test recorder::tests::record_ffb_stores_correctly ... ok
4540:  test recorder::tests::record_event_stores_correctly ... ok
4541:  test recorder::tests::record_telemetry_stores_correctly ... ok
4542:  test recorder::tests::ring_buffer_exact_capacity_fill ... ok
4543:  test recorder::tests::ring_buffer_overflow_drops_oldest ... ok
4544:  test recorder::tests::zero_alloc_on_hot_path ... ok
4545:  test recorder::tests::zero_capacity_clamped_to_one ... ok
4546:  test tests::blackbox_config_defaults ... ok
4547:  test tests::blackbox_writer_starts_not_running ... ok
4548:  test tests::double_start_returns_error ... o...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants