Beta hardening: fuzz/audit fixes + dead-dep prune
Code-fuzz: fix trial copy (14->30 days), add storage_stats tombstone
read-path filter (M019 Phase-1 completeness) with test, correct a
misleading sync changelog log message.
Rust-fuzz: remove a per-frame magnitude clone in the STFT hot path
(derive flux from stored frames; drop redundant prev_spectrum), add the
missing SAFETY comment on the libdispatch extern block, and convert a
provably-safe manifest unwrap to expect.
Build cleanup: clear all warnings (unused tags import; extract testable
aiff_sample_data_size helper). Dependency-prune: drop dead docengine
workspace dependency.
806 tests green, 0 warnings.
- Co-Authored-By
- Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9 files changed,
+53 insertions,
-39 deletions
| 46 |
46 |
|
rayon = "1.10"
|
| 47 |
47 |
|
libc = "0.2"
|
| 48 |
48 |
|
midir = "0.11"
|
| 49 |
|
- |
docengine = { path = "../../MNW/shared/docengine" }
|
| 50 |
49 |
|
tagtree = { path = "../../MNW/shared/tagtree" }
|
| 51 |
50 |
|
theme-common = { path = "../../MNW/shared/theme-common" }
|
| 65 |
65 |
|
"Trial expired".to_string()
|
| 66 |
66 |
|
}
|
| 67 |
67 |
|
}
|
| 68 |
|
- |
None => "Start free trial — 14 days, no card".to_string(),
|
|
68 |
+ |
None => "Start free trial — 30 days, no card".to_string(),
|
| 69 |
69 |
|
};
|
| 70 |
70 |
|
let trial_btn = egui::Button::new(egui::RichText::new(trial_label).strong());
|
| 71 |
71 |
|
if ui.add_enabled(!trial_expired, trial_btn).clicked() {
|
| 1324 |
1324 |
|
}
|
| 1325 |
1325 |
|
|
| 1326 |
1326 |
|
/// Aggregate storage stats: (sample_count, total_file_bytes).
|
|
1327 |
+ |
///
|
|
1328 |
+ |
/// Excludes tombstoned rows (`deleted_at IS NOT NULL`) so the figure matches
|
|
1329 |
+ |
/// the library the user actually sees — the M019 read-path filter applies here
|
|
1330 |
+ |
/// like every other sample read site.
|
| 1327 |
1331 |
|
pub fn storage_stats(&self) -> Result<(u64, u64), DbError> {
|
| 1328 |
1332 |
|
let (count, total): (u64, u64) = self.conn.query_row(
|
| 1329 |
|
- |
"SELECT COUNT(*), COALESCE(SUM(file_size), 0) FROM samples",
|
|
1333 |
+ |
"SELECT COUNT(*), COALESCE(SUM(file_size), 0) FROM samples WHERE deleted_at IS NULL",
|
| 1330 |
1334 |
|
[],
|
| 1331 |
1335 |
|
|row| Ok((row.get(0)?, row.get(1)?)),
|
| 1332 |
1336 |
|
)?;
|
| 1619 |
1623 |
|
"tombstoned sample should be hidden from sample_extension; got {tomb_ext:?}"
|
| 1620 |
1624 |
|
);
|
| 1621 |
1625 |
|
|
|
1626 |
+ |
// storage_stats also applies the read-path filter: only the live sample
|
|
1627 |
+ |
// (file_size 1) is counted, not the tombstoned one.
|
|
1628 |
+ |
let (count, bytes) = db.storage_stats().unwrap();
|
|
1629 |
+ |
assert_eq!(count, 1, "tombstoned sample should not be counted");
|
|
1630 |
+ |
assert_eq!(bytes, 1, "tombstoned sample's bytes should be excluded");
|
|
1631 |
+ |
|
| 1622 |
1632 |
|
// Default retain-days seed is present.
|
| 1623 |
1633 |
|
let retain: String = conn
|
| 1624 |
1634 |
|
.query_row(
|
| 146 |
146 |
|
section.separator,
|
| 147 |
147 |
|
)));
|
| 148 |
148 |
|
}
|
| 149 |
|
- |
let separator = section.separator.chars().next().unwrap();
|
|
149 |
+ |
let separator = section
|
|
150 |
+ |
.separator
|
|
151 |
+ |
.chars()
|
|
152 |
+ |
.next()
|
|
153 |
+ |
.expect("separator length checked to be exactly 1 above");
|
| 150 |
154 |
|
|
| 151 |
155 |
|
Ok(NamingRules {
|
| 152 |
156 |
|
case,
|
| 24 |
24 |
|
use objc2_foundation::{NSArray, NSPoint, NSRect, NSSize, NSURL};
|
| 25 |
25 |
|
use tracing::{debug, warn};
|
| 26 |
26 |
|
|
|
27 |
+ |
// SAFETY: `_dispatch_main_q` and `dispatch_async` are public symbols exported by
|
|
28 |
+ |
// Apple's libdispatch. The declared signatures match the system headers; dispatch
|
|
29 |
+ |
// is thread-safe and `RcBlock` keeps the closure alive across the async boundary.
|
| 27 |
30 |
|
unsafe extern "C" {
|
| 28 |
31 |
|
static _dispatch_main_q: c_void;
|
| 29 |
32 |
|
fn dispatch_async(queue: *const c_void, block: &block2::Block<dyn Fn()>);
|