FA-81236 / Music interval and transposition theory / Open access
Melody transposition fitted into an instrument range: octave shift applied to untransposed notes · case 01
The requested transposition is lost from the output; only the octave shift is applied.
ROOT CAUSE
The final octave shift is applied to the original notes rather than the transposed ones.
VERIFIED REPAIR
Restore the transposed base step so that it reads `[n + 12 * k for n in moved]`.
Unsuccessful approach: Re-adding the transposition to the already transposed notes applies it twice.
Case contract
Input [notes, semitones, lo, hi]. Transpose every note by the semitone amount, then shift the whole melody by the octave offset k (|k| <= 10) of smallest magnitude that places every note within [lo, hi] inclusive. Return the notes, or None if the melody is empty, lo > hi, or no octave fits.
Why this case matters
Arranging tools transpose parts into playable instrument ranges.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
if not isinstance(x, list) or len(x) != 4:
return None
notes, t, lo, hi = x
if not notes or lo > hi:
return None
moved = [n + t for n in notes]
low, high = min(moved), max(moved)
if high - low > hi - lo:
return None
options = []
for k in range(-10, 11):
if lo <= low + 12 * k and high + 12 * k <= hi:
options.append((abs(k), k))
if not options:
return None
k = min(options)[1]
return [n + 12 * k for n in notes]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([[60, 64, 67], 0, 55, 79], [60, 64, 67]), ([[60, 64, 67], 2, 55, 79], [62, 66, 69]), ([[60, 64, 67], 0, 72, 96], [72, 76, 79]), ([[60, 64, 67], 0, 36, 60], [48, 52, 55]), ([[60, 72], 0, 60, 72], [60, 72]), ([[60, 72], 0, 61, 73], None), ([[48, 50], -2, 50, 70], [58, 60]), ([[60, 64, 67], -12, 55, 79], [60, 64, 67])], [([[60, 72], 0, 60, 72], [60, 72]), ([[60, 72], 0, 61, 73], None), ([[60, 64], 0, 54, 78], [60, 64]), ([[60, 62], 5, 40, 50], [41, 43]), ([[60, 79], 0, 60, 78], None), ([[70], 0, 52, 64], [58]), ([[60, 64, 67], -12, 55, 79], [60, 64, 67]), ([[60], 6, 54, 67], [66])], [([[60, 79], 0, 60, 78], None), ([[70], 0, 52, 64], [58]), ([[70], 0, 58, 70], [70]), ([[48, 50], -2, 50, 70], [58, 60]), ([[], 0, 0, 127], None), ([[60], 0, 70, 60], None), ([[60], 6, 54, 67], [66]), ([[60, 63], 3, 48, 60], [51, 54])], [([[60, 64, 67], 2, 55, 79], [62, 66, 69]), ([[], 0, 0, 127], None), ([[60], 0, 70, 60], None), ([[60, 64, 67], -12, 55, 79], [60, 64, 67]), ([[62, 65], 0, 50, 62], [50, 53]), ([[60, 67], 0, 62, 73], None), ([[60, 63], 3, 48, 60], [51, 54]), ([[60], 0, 48, 48], [48])], [([[60, 64, 67], 2, 55, 79], [62, 66, 69]), ([[60, 62], 5, 40, 50], [41, 43]), ([[48, 50], -2, 50, 70], [58, 60]), ([[60, 64, 67], -12, 55, 79], [60, 64, 67]), ([[60], 6, 54, 67], [66]), ([[60, 67], 0, 62, 73], None), ([[60], 0, 48, 48], [48]), ([[59, 61], 0, 47, 49], [47, 49])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("oracle %d" % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| oracle 0 | [60, 64, 67] | [60, 64, 67] | Passed |
| oracle 1 | [60, 64, 67] | [62, 66, 69] | Failed |
| oracle 2 | [72, 76, 79] | [72, 76, 79] | Passed |
| oracle 3 | [48, 52, 55] | [48, 52, 55] | Passed |
| oracle 4 | [60, 72] | [60, 72] | Passed |
| oracle 5 | None | None | Passed |
| oracle 6 | [60, 62] | [58, 60] | Failed |
| oracle 7 | [72, 76, 79] | [60, 64, 67] | Failed |
SHA-256 / 4bb08f380051dae9fcfb51f8680ea56df11a194d598d1cc9af7c9d762d725e71
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
if not isinstance(x, list) or len(x) != 4:
return None
notes, t, lo, hi = x
if not notes or lo > hi:
return None
moved = [n + t for n in notes]
low, high = min(moved), max(moved)
if high - low > hi - lo:
return None
options = []
for k in range(-10, 11):
if lo <= low + 12 * k and high + 12 * k <= hi:
options.append((abs(k), k))
if not options:
return None
k = min(options)[1]
return [n + t + 12 * k for n in moved]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([[60, 64, 67], 0, 55, 79], [60, 64, 67]), ([[60, 64, 67], 2, 55, 79], [62, 66, 69]), ([[60, 64, 67], 0, 72, 96], [72, 76, 79]), ([[60, 64, 67], 0, 36, 60], [48, 52, 55]), ([[60, 72], 0, 60, 72], [60, 72]), ([[60, 72], 0, 61, 73], None), ([[48, 50], -2, 50, 70], [58, 60]), ([[60, 64, 67], -12, 55, 79], [60, 64, 67])], [([[60, 72], 0, 60, 72], [60, 72]), ([[60, 72], 0, 61, 73], None), ([[60, 64], 0, 54, 78], [60, 64]), ([[60, 62], 5, 40, 50], [41, 43]), ([[60, 79], 0, 60, 78], None), ([[70], 0, 52, 64], [58]), ([[60, 64, 67], -12, 55, 79], [60, 64, 67]), ([[60], 6, 54, 67], [66])], [([[60, 79], 0, 60, 78], None), ([[70], 0, 52, 64], [58]), ([[70], 0, 58, 70], [70]), ([[48, 50], -2, 50, 70], [58, 60]), ([[], 0, 0, 127], None), ([[60], 0, 70, 60], None), ([[60], 6, 54, 67], [66]), ([[60, 63], 3, 48, 60], [51, 54])], [([[60, 64, 67], 2, 55, 79], [62, 66, 69]), ([[], 0, 0, 127], None), ([[60], 0, 70, 60], None), ([[60, 64, 67], -12, 55, 79], [60, 64, 67]), ([[62, 65], 0, 50, 62], [50, 53]), ([[60, 67], 0, 62, 73], None), ([[60, 63], 3, 48, 60], [51, 54]), ([[60], 0, 48, 48], [48])], [([[60, 64, 67], 2, 55, 79], [62, 66, 69]), ([[60, 62], 5, 40, 50], [41, 43]), ([[48, 50], -2, 50, 70], [58, 60]), ([[60, 64, 67], -12, 55, 79], [60, 64, 67]), ([[60], 6, 54, 67], [66]), ([[60, 67], 0, 62, 73], None), ([[60], 0, 48, 48], [48]), ([[59, 61], 0, 47, 49], [47, 49])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("oracle %d" % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| oracle 0 | [60, 64, 67] | [60, 64, 67] | Passed |
| oracle 1 | [64, 68, 71] | [62, 66, 69] | Failed |
| oracle 2 | [72, 76, 79] | [72, 76, 79] | Passed |
| oracle 3 | [48, 52, 55] | [48, 52, 55] | Passed |
| oracle 4 | [60, 72] | [60, 72] | Passed |
| oracle 5 | None | None | Passed |
| oracle 6 | [56, 58] | [58, 60] | Failed |
| oracle 7 | [48, 52, 55] | [60, 64, 67] | Failed |
SHA-256 / 3e24ffa632c27d4ffee56c22bfac7810769026337716fdd380eaa3b329a80a6c
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
if not isinstance(x, list) or len(x) != 4:
return None
notes, t, lo, hi = x
if not notes or lo > hi:
return None
moved = [n + t for n in notes]
low, high = min(moved), max(moved)
if high - low > hi - lo:
return None
options = []
for k in range(-10, 11):
if lo <= low + 12 * k and high + 12 * k <= hi:
options.append((abs(k), k))
if not options:
return None
k = min(options)[1]
return [n + 12 * k for n in moved]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([[60, 64, 67], 0, 55, 79], [60, 64, 67]), ([[60, 64, 67], 2, 55, 79], [62, 66, 69]), ([[60, 64, 67], 0, 72, 96], [72, 76, 79]), ([[60, 64, 67], 0, 36, 60], [48, 52, 55]), ([[60, 72], 0, 60, 72], [60, 72]), ([[60, 72], 0, 61, 73], None), ([[48, 50], -2, 50, 70], [58, 60]), ([[60, 64, 67], -12, 55, 79], [60, 64, 67])], [([[60, 72], 0, 60, 72], [60, 72]), ([[60, 72], 0, 61, 73], None), ([[60, 64], 0, 54, 78], [60, 64]), ([[60, 62], 5, 40, 50], [41, 43]), ([[60, 79], 0, 60, 78], None), ([[70], 0, 52, 64], [58]), ([[60, 64, 67], -12, 55, 79], [60, 64, 67]), ([[60], 6, 54, 67], [66])], [([[60, 79], 0, 60, 78], None), ([[70], 0, 52, 64], [58]), ([[70], 0, 58, 70], [70]), ([[48, 50], -2, 50, 70], [58, 60]), ([[], 0, 0, 127], None), ([[60], 0, 70, 60], None), ([[60], 6, 54, 67], [66]), ([[60, 63], 3, 48, 60], [51, 54])], [([[60, 64, 67], 2, 55, 79], [62, 66, 69]), ([[], 0, 0, 127], None), ([[60], 0, 70, 60], None), ([[60, 64, 67], -12, 55, 79], [60, 64, 67]), ([[62, 65], 0, 50, 62], [50, 53]), ([[60, 67], 0, 62, 73], None), ([[60, 63], 3, 48, 60], [51, 54]), ([[60], 0, 48, 48], [48])], [([[60, 64, 67], 2, 55, 79], [62, 66, 69]), ([[60, 62], 5, 40, 50], [41, 43]), ([[48, 50], -2, 50, 70], [58, 60]), ([[60, 64, 67], -12, 55, 79], [60, 64, 67]), ([[60], 6, 54, 67], [66]), ([[60, 67], 0, 62, 73], None), ([[60], 0, 48, 48], [48]), ([[59, 61], 0, 47, 49], [47, 49])]]
for i, (args, expected) in enumerate(fixtures[N-1]):
check("oracle %d" % i, solve(args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| oracle 0 | [60, 64, 67] | [60, 64, 67] | Passed |
| oracle 1 | [62, 66, 69] | [62, 66, 69] | Passed |
| oracle 2 | [72, 76, 79] | [72, 76, 79] | Passed |
| oracle 3 | [48, 52, 55] | [48, 52, 55] | Passed |
| oracle 4 | [60, 72] | [60, 72] | Passed |
| oracle 5 | None | None | Passed |
| oracle 6 | [58, 60] | [58, 60] | Passed |
| oracle 7 | [60, 64, 67] | [60, 64, 67] | Passed |
SHA-256 / 6573be12a6bd05d6a7353507cc647c93fba21eeb373ae8c255412fc13e8f71f1
Verification & scope
A deterministic bounded teaching model with a stipulated toy contract; it is not a complete music notation or theory engine. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:50:01.208247+00:00.
Case digest / 58bd6d53ab1cc392203487810fc696accabf6ec9ce00fc7e388acaa5d500c085