FA-80876 / Music interval and transposition theory / Open access
Key-aware MIDI note spelling: seven-accidental keys rejected · case 01
C# major and Cb major (seven accidentals) are rejected although both are legal key signatures.
ROOT CAUSE
The key range check treats six accidentals as the maximum.
VERIFIED REPAIR
Restore the fifths range step so that it reads `f < -7 or f > 7`.
Unsuccessful approach: Widening only the sharp side still rejects Cb major with seven flats.
Case contract
Input [midi, fifths] with midi 0..127 and fifths -7..7. Use flat names when fifths < 0, sharp names otherwise; in keys with at least six sharps pitch class 5 is E#, with seven sharps pitch class 0 is B# of the previous octave, and with at least six flats pitch class 11 is Cb of the next octave. Octave -1 starts at key 0. Invalid input returns None.
Why this case matters
Pitch spelling and interval arithmetic decide the notes that notation, transposition and analysis tools display or play.
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) != 2:
return None
m, f = x
if not isinstance(m, int) or m < 0 or m > 127:
return None
if not isinstance(f, int) or abs(f) > 6:
return None
sharps = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
flats = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B']
table = flats if f < 0 else sharps
pc = m % 12
octave = m // 12 - 1
name = table[pc]
if f >= 6 and pc == 5:
name = 'E#'
if f == 7 and pc == 0:
name = 'B#'
octave -= 1
if f <= -6 and pc == 11:
name = 'Cb'
octave += 1
return name + str(octave)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([60, 0], 'C4'), ([61, 0], 'C#4'), ([61, -1], 'Db4'), ([61, 1], 'C#4'), ([65, 7], 'E#4'), ([48, 7], 'B#2'), ([71, -7], 'Cb5'), ([64, -7], 'E4')], [([61, 1], 'C#4'), ([70, -2], 'Bb4'), ([70, 2], 'A#4'), ([65, 6], 'E#4'), ([65, 5], 'F4'), ([60, 7], 'B#3'), ([71, -7], 'Cb5'), ([60, -7], 'C4')], [([65, 6], 'E#4'), ([65, 5], 'F4'), ([65, -6], 'F4'), ([48, 7], 'B#2'), ([71, -6], 'Cb5'), ([127, 7], 'G9'), ([60, -7], 'C4'), ([66, -7], 'Gb4')], [([71, -6], 'Cb5'), ([71, -7], 'Cb5'), ([59, -6], 'Cb4'), ([0, 0], 'C-1'), ([1, -3], 'Db-1'), ([60, -7], 'C4'), ([66, -7], 'Gb4'), ([64, -7], 'E4')], [([71, -7], 'Cb5'), ([1, -3], 'Db-1'), ([11, 0], 'B-1'), ([127, 0], 'G9'), ([127, 7], 'G9'), ([128, 0], None), ([66, -7], 'Gb4'), ([64, -7], 'E4')]]
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 | C4 | C4 | Passed |
| oracle 1 | C#4 | C#4 | Passed |
| oracle 2 | Db4 | Db4 | Passed |
| oracle 3 | C#4 | C#4 | Passed |
| oracle 4 | None | E#4 | Failed |
| oracle 5 | None | B#2 | Failed |
| oracle 6 | None | Cb5 | Failed |
| oracle 7 | None | E4 | Failed |
SHA-256 / c762d340118efc97ebcaf447a055fe9a9b3bd31208e8c245eb4de231aac4c3d7
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) != 2:
return None
m, f = x
if not isinstance(m, int) or m < 0 or m > 127:
return None
if not isinstance(f, int) or f < -6 or f > 7:
return None
sharps = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
flats = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B']
table = flats if f < 0 else sharps
pc = m % 12
octave = m // 12 - 1
name = table[pc]
if f >= 6 and pc == 5:
name = 'E#'
if f == 7 and pc == 0:
name = 'B#'
octave -= 1
if f <= -6 and pc == 11:
name = 'Cb'
octave += 1
return name + str(octave)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([60, 0], 'C4'), ([61, 0], 'C#4'), ([61, -1], 'Db4'), ([61, 1], 'C#4'), ([65, 7], 'E#4'), ([48, 7], 'B#2'), ([71, -7], 'Cb5'), ([64, -7], 'E4')], [([61, 1], 'C#4'), ([70, -2], 'Bb4'), ([70, 2], 'A#4'), ([65, 6], 'E#4'), ([65, 5], 'F4'), ([60, 7], 'B#3'), ([71, -7], 'Cb5'), ([60, -7], 'C4')], [([65, 6], 'E#4'), ([65, 5], 'F4'), ([65, -6], 'F4'), ([48, 7], 'B#2'), ([71, -6], 'Cb5'), ([127, 7], 'G9'), ([60, -7], 'C4'), ([66, -7], 'Gb4')], [([71, -6], 'Cb5'), ([71, -7], 'Cb5'), ([59, -6], 'Cb4'), ([0, 0], 'C-1'), ([1, -3], 'Db-1'), ([60, -7], 'C4'), ([66, -7], 'Gb4'), ([64, -7], 'E4')], [([71, -7], 'Cb5'), ([1, -3], 'Db-1'), ([11, 0], 'B-1'), ([127, 0], 'G9'), ([127, 7], 'G9'), ([128, 0], None), ([66, -7], 'Gb4'), ([64, -7], 'E4')]]
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 | C4 | C4 | Passed |
| oracle 1 | C#4 | C#4 | Passed |
| oracle 2 | Db4 | Db4 | Passed |
| oracle 3 | C#4 | C#4 | Passed |
| oracle 4 | E#4 | E#4 | Passed |
| oracle 5 | B#2 | B#2 | Passed |
| oracle 6 | None | Cb5 | Failed |
| oracle 7 | None | E4 | Failed |
SHA-256 / 69b65cb5bbcc823c28cbb9245d06d1c85d1e3012da8e6c3692a24803d8209afe
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) != 2:
return None
m, f = x
if not isinstance(m, int) or m < 0 or m > 127:
return None
if not isinstance(f, int) or f < -7 or f > 7:
return None
sharps = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
flats = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B']
table = flats if f < 0 else sharps
pc = m % 12
octave = m // 12 - 1
name = table[pc]
if f >= 6 and pc == 5:
name = 'E#'
if f == 7 and pc == 0:
name = 'B#'
octave -= 1
if f <= -6 and pc == 11:
name = 'Cb'
octave += 1
return name + str(octave)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([60, 0], 'C4'), ([61, 0], 'C#4'), ([61, -1], 'Db4'), ([61, 1], 'C#4'), ([65, 7], 'E#4'), ([48, 7], 'B#2'), ([71, -7], 'Cb5'), ([64, -7], 'E4')], [([61, 1], 'C#4'), ([70, -2], 'Bb4'), ([70, 2], 'A#4'), ([65, 6], 'E#4'), ([65, 5], 'F4'), ([60, 7], 'B#3'), ([71, -7], 'Cb5'), ([60, -7], 'C4')], [([65, 6], 'E#4'), ([65, 5], 'F4'), ([65, -6], 'F4'), ([48, 7], 'B#2'), ([71, -6], 'Cb5'), ([127, 7], 'G9'), ([60, -7], 'C4'), ([66, -7], 'Gb4')], [([71, -6], 'Cb5'), ([71, -7], 'Cb5'), ([59, -6], 'Cb4'), ([0, 0], 'C-1'), ([1, -3], 'Db-1'), ([60, -7], 'C4'), ([66, -7], 'Gb4'), ([64, -7], 'E4')], [([71, -7], 'Cb5'), ([1, -3], 'Db-1'), ([11, 0], 'B-1'), ([127, 0], 'G9'), ([127, 7], 'G9'), ([128, 0], None), ([66, -7], 'Gb4'), ([64, -7], 'E4')]]
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 | C4 | C4 | Passed |
| oracle 1 | C#4 | C#4 | Passed |
| oracle 2 | Db4 | Db4 | Passed |
| oracle 3 | C#4 | C#4 | Passed |
| oracle 4 | E#4 | E#4 | Passed |
| oracle 5 | B#2 | B#2 | Passed |
| oracle 6 | Cb5 | Cb5 | Passed |
| oracle 7 | E4 | E4 | Passed |
SHA-256 / a224835075261e420033b06c0d271a67ec7d12e354b6105093fda25b15afdf15
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:49:57.985320+00:00.
Case digest / 5192acc55ba363ada3bd4f4e43aa87fdd67ac3022d224c8e6b779bec2b0877d3