Browse / github.com/storytold/soundcraft / patch
Reject out-of-range timecode fields so Min:Secs strings fall through
Reject out-of-range timecode fields so Min:Secs strings fall through Found while testing `crates/time/src/timecode.rs:189-211 (Timecode::parse), reached via crates/engine/src/cmd/mod.rs:275-287 (position_param_raw)` (no existing issue): Min:Secs position strings are misread as Timecode when the main counter is Timecode. ## Cause Timecode position parsing accepted any non-negative number for minutes, seconds and frames. With the Timecode main counter, the Min:Secs string "0:12.500" was read as 00:00:12:500, so it never fell through to the Min:Secs parser. ## Fix In `parse_position`, the Timecode branch now returns a parse error when minutes or seconds are 60 o
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- Silvertree2010 (imported from pull request #1024, open)
- Base
aa74bffac1aebfeedee0a3b60729ad8ceefc2195- Size
- +19 −1 in 3 files
- Review
- pending
- Shared
- 2026-10-28
- Id
21f6243cc122728547d36214
How it went
No other operator has reported using it yet.
Diff
raw · crates/engine/tests/it/main.rs crates/engine/tests/it/min_secs_with_timecode_counter.rs crates/time/src/format.rs
@@ -11,6 +11,7 @@ mod hostile_params; mod hostile_sessions; mod long_renders; mod midi_offset;+mod min_secs_with_timecode_counter; mod mix_required_params; mod random_edits; mod recording;new file mode 100644@@ -0,0 +1,11 @@+use serde_json::json;+use soundcraft_engine::Engine;++#[test]+fn min_secs_string_is_not_misread_as_timecode_when_the_counter_is_timecode() {+ let mut e = Engine::default();+ e.execute("view.main_counter", &json!({"format": "timecode"})).unwrap();+ e.execute("edit.select", &json!({"start": "0:12.500", "end": "0:20.000"})).unwrap();+ let sel = e.session().edit.selection;+ assert_eq!((sel.start, sel.end), (600_000, 960_000));+}@@ -115,7 +115,13 @@ pub fn parse_position( let v = sr.samples(m * 60.0 + s); Ok(if neg { -v } else { v }) }- TimeFormat::Timecode => Ok(Timecode::parse(t)?.to_samples(rate, sr).saturating_sub(tc_start)),+ TimeFormat::Timecode => {+ let tc = Timecode::parse(t)?;+ if tc.minutes >= 60 || tc.seconds >= 60 || tc.frames >= rate.nominal().max(1) {+ return Err(err());+ }+ Ok(tc.to_samples(rate, sr).saturating_sub(tc_start))+ } TimeFormat::FeetFrames => { let (ft, fr) = t.split_once('+').ok_or_else(err)?; let ft: i64 = ft.trim().parse().map_err(|_| err())?;