From c35c63d8a997266dc4483da6fdfc8118018970f3 Mon Sep 17 00:00:00 2001 From: swipelab Date: Fri, 5 Jun 2026 20:06:21 +0300 Subject: [PATCH] P10.4: snapshot-test cascade-cue depth->index mapping (sx) Add tests/cascade_cue.sx, a headless logic test that reuses audio.sx's pure cascade_cue_index / cascade_cue_name (the exact functions play_cascade calls) to lock the cascade-depth -> combo-cue clamp: depth <= 1 -> combo1, depth >= COMBO_CLIPS -> combo5, monotonic between. Covers the escalation logic the audio playback path can't gate-cover, with no audio. Committed stdout/exit snapshot; suite is now 19 tests. --- tests/cascade_cue.sx | 34 +++++++++++++++++++++++++++++++ tests/expected/cascade_cue.exit | 1 + tests/expected/cascade_cue.stdout | 12 +++++++++++ 3 files changed, 47 insertions(+) create mode 100644 tests/cascade_cue.sx create mode 100644 tests/expected/cascade_cue.exit create mode 100644 tests/expected/cascade_cue.stdout diff --git a/tests/cascade_cue.sx b/tests/cascade_cue.sx new file mode 100644 index 0000000..f558d68 --- /dev/null +++ b/tests/cascade_cue.sx @@ -0,0 +1,34 @@ +// P10.4 — Cascade-cue selection snapshot: prove the cascade-depth → combo-cue +// mapping is a PURE, headless clamp. It reuses audio.sx's `cascade_cue_index` +// (and `cascade_cue_name`) UNCHANGED — the exact functions `play_cascade` calls +// — so the escalation logic the audio playback path can't gate-cover is covered +// here with no audio. The mapping clamps depth <= 1 to the first cue (combo1) +// and depth >= COMBO_CLIPS to the last (combo5), stepping up monotonically in +// between. The depth→index/name table below is locked by the committed snapshot. +#import "modules/std.sx"; +#import "audio.sx"; + +main :: () -> s32 { + print("== cascade cue selection (depth -> combo cue) ==\n"); + + // Walk a representative depth range (0..9) so both clamps and the monotonic + // middle are visible: depths 0,1 pin to the first cue; depths >= 5 pin to + // the last; 2,3,4 step up one cue at a time. + prev : s64 = -1; + for 0..10: (depth) { + idx := cascade_cue_index(depth); + print("depth {} -> idx {} ({})\n", depth, idx, cascade_cue_name(idx)); + // The mapping must never step down as depth grows. + if idx < prev { print("FAIL: cue index decreased at depth {}\n", depth); return 1; } + prev = idx; + } + + // Explicit clamp boundaries, independent of the loop above. + if cascade_cue_index(0) != 0 { print("FAIL: depth 0 not clamped to first cue\n"); return 1; } + if cascade_cue_index(1) != 0 { print("FAIL: depth 1 not clamped to first cue\n"); return 1; } + if cascade_cue_index(COMBO_CLIPS) != COMBO_CLIPS - 1 { print("FAIL: depth COMBO_CLIPS not at last cue\n"); return 1; } + if cascade_cue_index(9) != COMBO_CLIPS - 1 { print("FAIL: deep cascade not clamped to last cue\n"); return 1; } + + print("ok: cascade cue mapping clamps into combo1..combo{}\n", COMBO_CLIPS); + return 0; +} diff --git a/tests/expected/cascade_cue.exit b/tests/expected/cascade_cue.exit new file mode 100644 index 0000000..573541a --- /dev/null +++ b/tests/expected/cascade_cue.exit @@ -0,0 +1 @@ +0 diff --git a/tests/expected/cascade_cue.stdout b/tests/expected/cascade_cue.stdout new file mode 100644 index 0000000..2fb21cd --- /dev/null +++ b/tests/expected/cascade_cue.stdout @@ -0,0 +1,12 @@ +== cascade cue selection (depth -> combo cue) == +depth 0 -> idx 0 ([sx] audio: cue combo1) +depth 1 -> idx 0 ([sx] audio: cue combo1) +depth 2 -> idx 1 ([sx] audio: cue combo2) +depth 3 -> idx 2 ([sx] audio: cue combo3) +depth 4 -> idx 3 ([sx] audio: cue combo4) +depth 5 -> idx 4 ([sx] audio: cue combo5) +depth 6 -> idx 4 ([sx] audio: cue combo5) +depth 7 -> idx 4 ([sx] audio: cue combo5) +depth 8 -> idx 4 ([sx] audio: cue combo5) +depth 9 -> idx 4 ([sx] audio: cue combo5) +ok: cascade cue mapping clamps into combo1..combo5