FAILURE MAP
← Case archive

FA-81231 / Music interval and transposition theory / Open access

Melody transposition fitted into an instrument range: range endpoints treated as unplayable · case 01

A note exactly on the lowest or highest playable pitch forces an unnecessary octave shift or rejection.

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

ROOT CAUSE

Both range comparisons are strict, excluding the inclusive endpoints.

VERIFIED REPAIR

Restore the inclusive range bounds step so that it reads `lo <= low + 12 * k and high + 12 * k <= hi`.

Unsuccessful approach: Making only the lower bound inclusive still excludes the top note of the range.

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 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), ([[70], 0, 58, 70], [70]), ([[59, 61], 0, 47, 49], [47, 49])], [([[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]), ([[70], 0, 58, 70], [70]), ([[62, 65], 0, 50, 62], [50, 53])], [([[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, 64, 67], -12, 55, 79], [60, 64, 67]), ([[60], 0, 48, 48], [48])], [([[], 0, 0, 127], None), ([[60], 0, 70, 60], None), ([[60, 64, 67], -12, 55, 79], [60, 64, 67]), ([[60], 6, 54, 67], [66]), ([[62, 65], 0, 50, 62], [50, 53]), ([[60, 67], 0, 62, 73], None), ([[60], 0, 48, 48], [48]), ([[59, 61], 0, 47, 49], [47, 49])], [([[60, 64, 67], 0, 72, 96], [72, 76, 79]), ([[60, 72], 0, 60, 72], [60, 72]), ([[70], 0, 58, 70], [70]), ([[60], 6, 54, 67], [66]), ([[60, 67], 0, 62, 73], None), ([[60, 63], 3, 48, 60], [51, 54]), ([[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[84, 88, 91][72, 76, 79]Failed
oracle 3[48, 52, 55][48, 52, 55]Passed
oracle 4None[60, 72]Failed
oracle 5NoneNonePassed
oracle 6None[70]Failed
oracle 7None[47, 49]Failed

SHA-256 / 77bb29b5480d790a2c96b831c35a14905d4607d25690b78101f2e6ca4deed3a7

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 + 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), ([[70], 0, 58, 70], [70]), ([[59, 61], 0, 47, 49], [47, 49])], [([[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]), ([[70], 0, 58, 70], [70]), ([[62, 65], 0, 50, 62], [50, 53])], [([[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, 64, 67], -12, 55, 79], [60, 64, 67]), ([[60], 0, 48, 48], [48])], [([[], 0, 0, 127], None), ([[60], 0, 70, 60], None), ([[60, 64, 67], -12, 55, 79], [60, 64, 67]), ([[60], 6, 54, 67], [66]), ([[62, 65], 0, 50, 62], [50, 53]), ([[60, 67], 0, 62, 73], None), ([[60], 0, 48, 48], [48]), ([[59, 61], 0, 47, 49], [47, 49])], [([[60, 64, 67], 0, 72, 96], [72, 76, 79]), ([[60, 72], 0, 60, 72], [60, 72]), ([[70], 0, 58, 70], [70]), ([[60], 6, 54, 67], [66]), ([[60, 67], 0, 62, 73], None), ([[60, 63], 3, 48, 60], [51, 54]), ([[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 4None[60, 72]Failed
oracle 5NoneNonePassed
oracle 6[58][70]Failed
oracle 7None[47, 49]Failed

SHA-256 / ff32955c97c592e817dbff1bcf7fdab2e1e317943db68f45322f38ee3180c90a

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), ([[70], 0, 58, 70], [70]), ([[59, 61], 0, 47, 49], [47, 49])], [([[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]), ([[70], 0, 58, 70], [70]), ([[62, 65], 0, 50, 62], [50, 53])], [([[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, 64, 67], -12, 55, 79], [60, 64, 67]), ([[60], 0, 48, 48], [48])], [([[], 0, 0, 127], None), ([[60], 0, 70, 60], None), ([[60, 64, 67], -12, 55, 79], [60, 64, 67]), ([[60], 6, 54, 67], [66]), ([[62, 65], 0, 50, 62], [50, 53]), ([[60, 67], 0, 62, 73], None), ([[60], 0, 48, 48], [48]), ([[59, 61], 0, 47, 49], [47, 49])], [([[60, 64, 67], 0, 72, 96], [72, 76, 79]), ([[60, 72], 0, 60, 72], [60, 72]), ([[70], 0, 58, 70], [70]), ([[60], 6, 54, 67], [66]), ([[60, 67], 0, 62, 73], None), ([[60, 63], 3, 48, 60], [51, 54]), ([[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[70][70]Passed
oracle 7[47, 49][47, 49]Passed

SHA-256 / 1b82dba3a3b02fd9efcec20db71f1dc9875896fedac36caf7a71ccb50063d6aa

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.183379+00:00.

Case digest / 1f24515d598f64b99bc43f00199841c1a81c3470ca635008b37b2e83230e1075