FAILURE MAP
← Case archive

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.

Verified by executionVariant 1 · 8 checks per implementationDownload source bundle ↓JSON ↗

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 fixtureActualExpectedOutcome
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 5NoneNonePassed
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 fixtureActualExpectedOutcome
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 5NoneNonePassed
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 fixtureActualExpectedOutcome
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 5NoneNonePassed
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