ci(lesavka): restore UVC guard hygiene baseline

This commit is contained in:
Brad Stein 2026-05-19 15:01:47 -03:00
parent b82694125e
commit 1d4077ab4f
6 changed files with 34 additions and 12 deletions

View File

@ -371,6 +371,7 @@ from `LESAVKA_CLIENT_PKI_SSH_SOURCE` over SSH. Runtime clients require the insta
| `LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_COVERAGE_PCT` | server MJPEG pixel-artifact guard threshold; minimum sampled-row coverage for partial-width mosaic/tile seams, default `32` |
| `LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_DELTA` | server MJPEG pixel-artifact guard threshold; sampled luma jump for partial-width mosaic/tile seams, default `28` |
| `LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_RUN_PCT` | server MJPEG pixel-artifact guard threshold; minimum contiguous sampled-row run for partial-width mosaic/tile seams, default `12` |
| `LESAVKA_UVC_MJPEG_PIXEL_GUARD_PARTIAL_SEAM_BLOCK_STDDEV` | server MJPEG pixel-artifact guard threshold; maximum sampled-block luma variation for partial-width mosaic/tile seams, default `14` |
| `LESAVKA_UVC_MJPEG_PIXEL_GUARD_SAMPLE_WIDTH` | server MJPEG pixel-artifact guard sampling width; defaults to `160` pixels and is clamped to `64..320` |
| `LESAVKA_UVC_MJPEG_PIXEL_GUARD_SEAM_COVERAGE_PCT` | server MJPEG pixel-artifact guard threshold; minimum sampled-row coverage for hard horizontal tile seams, default `42` |
| `LESAVKA_UVC_MJPEG_PIXEL_GUARD_SEAM_DELTA` | server MJPEG pixel-artifact guard threshold; sampled luma jump that marks a row as suspicious, default `34` |

View File

@ -1308,7 +1308,7 @@
"server/src/video_sinks/hevc_mjpeg_guard.rs": {
"clippy_warnings": 0,
"doc_debt": 0,
"loc": 385
"loc": 436
},
"server/src/video_sinks/hevc_mjpeg_guard/mjpeg_frame_inspection.rs": {
"clippy_warnings": 0,
@ -1323,22 +1323,17 @@
"server/src/video_sinks/hevc_mjpeg_guard/mjpeg_visual_seams.rs": {
"clippy_warnings": 0,
"doc_debt": 0,
"loc": 311
},
"server/src/video_sinks/hevc_mjpeg_guard/tests.rs": {
"clippy_warnings": 0,
"doc_debt": 7,
"loc": 471
"loc": 404
},
"server/src/video_sinks/mjpeg_spool.rs": {
"clippy_warnings": 0,
"doc_debt": 4,
"loc": 396
"loc": 443
},
"server/src/video_sinks/mjpeg_spool/audit.rs": {
"clippy_warnings": 0,
"doc_debt": 1,
"loc": 226
"doc_debt": 0,
"loc": 287
},
"server/src/video_sinks/mjpeg_spool/tests.rs": {
"clippy_warnings": 0,
@ -1358,7 +1353,7 @@
"server/src/video_sinks/webcam_sink/frame_handoff.rs": {
"clippy_warnings": 0,
"doc_debt": 4,
"loc": 347
"loc": 357
},
"server/src/video_sinks/webcam_sink/tests.rs": {
"clippy_warnings": 0,

View File

@ -311,6 +311,11 @@ pub(super) fn should_freeze_decoded_mjpeg(previous_bytes: u64, next_bytes: usize
next_bytes < threshold_bytes
}
/// Return the size-collapse reason for a decoded HEVC->MJPEG frame.
///
/// Inputs: last accepted decoded frame size and next frame size. Output: the
/// collapse reason when the next frame is too small. Why: callers need the
/// exact threshold for operator-visible diagnostics instead of a boolean.
fn decoded_size_collapse_reason(
previous_bytes: u64,
next_bytes: usize,
@ -427,5 +432,5 @@ pub(super) fn direct_mjpeg_reject_reason(
}
#[cfg(test)]
#[path = "hevc_mjpeg_guard/tests.rs"]
#[path = "hevc_mjpeg_guard/tests/mod.rs"]
mod tests;

View File

@ -138,6 +138,11 @@ fn row_bounds(frame: &SampledFrame) -> std::ops::Range<usize> {
start..end.min(frame.height)
}
/// Measure sampled luma variation inside a bounded rectangle.
///
/// Inputs: sampled frame and exclusive x/y bounds. Output: luma standard
/// deviation, or `None` for empty regions. Why: partial seam detection should
/// reject smooth fake tile blocks without punishing naturally textured edges.
fn region_luma_stddev(
frame: &SampledFrame,
row_start: usize,
@ -169,6 +174,11 @@ fn region_luma_stddev(
Some((sum_sq / count_f - mean * mean).max(0.0).sqrt())
}
/// Measure texture around a candidate partial-width seam.
///
/// Inputs: sampled frame, seam row, and candidate horizontal run. Output:
/// standard deviation for the lower suspect block. Why: real scene detail can
/// have a sharp edge, but damaged UVC tiles tend to be broad low-texture slabs.
fn partial_seam_block_stddev(
frame: &SampledFrame,
row: usize,

View File

@ -1,3 +1,5 @@
//! Unit coverage for HEVC and direct-MJPEG corruption guard decisions.
#[test]
fn hevc_jpeg_quality_defaults_to_moderate_transport_pressure() {
temp_env::with_var_unset("LESAVKA_UVC_HEVC_JPEG_QUALITY", || {

View File

@ -128,6 +128,10 @@ pub(super) fn mjpeg_spool_audit_log_path(dir: &Path) -> PathBuf {
.unwrap_or_else(|| dir.join("spool-audit.jsonl"))
}
/// Hash an audited frame payload into a compact stable identifier.
///
/// Inputs: frame bytes. Output: lowercase FNV-1a hex digest. Why: audit JSONL
/// should correlate frame files without embedding large binary payloads.
fn fnv1a64_hex(data: &[u8]) -> String {
let mut hash = FNV1A64_OFFSET;
for byte in data {
@ -199,6 +203,11 @@ fn format_audit_record(
)
}
/// Format one guard-rejected frame audit record.
///
/// Inputs: sequence, saved slot, rejected bytes, timing, filename, and reason.
/// Output: one JSONL row. Why: rejected frames need the same timing/hash
/// evidence as accepted frames so guard tuning can compare both paths.
fn format_rejected_audit_record(
sequence: u64,
slot: u64,