FA-81241 / Music interval and transposition theory / Open access
Interval inversion by quality and number: octave reduced to unison before inverting · case 01
P8 inverts to P8 instead of P1 because the octave is first reduced to a unison.
ROOT CAUSE
The compound reduction loop also reduces the octave itself.
VERIFIED REPAIR
Restore the compound reduction step so that it reads `while n > 8:`.
Unsuccessful approach: Stopping at nine leaves ninths unreduced, so M9 inverts to m0.
Case contract
Input an interval string: quality from P, M, m, A, d, AA, dd followed by a positive integer. Compound numbers above 8 reduce by 7 until <= 8. P is valid only for 1, 4, 5, 8; M and m only for 2, 3, 6, 7. Inversion maps M<->m, A<->d, AA<->dd, P->P and number n -> 9-n. 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):
swap = {'M': 'm', 'm': 'M', 'A': 'd', 'd': 'A', 'AA': 'dd', 'dd': 'AA', 'P': 'P'}
if not isinstance(x, str):
return None
q = x.rstrip('0123456789')
digits = x[len(q):]
if q not in swap or not digits.isdigit() or int(digits) < 1:
return None
n = int(digits)
while n >= 8:
n -= 7
perfect = n in (1, 4, 5, 8)
if (q == 'P' and not perfect) or (q in ('M', 'm') and perfect):
return None
return swap[q] + str(9 - n)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('M3', 'm6'), ('m3', 'M6'), ('P5', 'P4'), ('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('d8', 'A1'), ('m9', 'M7')], [('P4', 'P5'), ('P1', 'P8'), ('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('P15', 'P1'), ('m9', 'M7'), ('P22', 'P1')], [('d5', 'A4'), ('M2', 'm7'), ('m7', 'M2'), ('M10', 'm6'), ('P12', 'P4'), ('d8', 'A1'), ('m9', 'M7'), ('A8', 'd1')], [('P8', 'P1'), ('M10', 'm6'), ('P12', 'P4'), ('AA4', 'dd5'), ('dd5', 'AA4'), ('A1', 'd8'), ('m9', 'M7'), ('P22', 'P1')], [('P15', 'P1'), ('dd5', 'AA4'), ('A1', 'd8'), ('M6', 'm3'), ('m9', 'M7'), ('P3', None), ('M4', None), ('A8', 'd1')]]
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 | m6 | m6 | Passed |
| oracle 1 | M6 | M6 | Passed |
| oracle 2 | P4 | P4 | Passed |
| oracle 3 | P5 | P5 | Passed |
| oracle 4 | P8 | P8 | Passed |
| oracle 5 | P8 | P1 | Failed |
| oracle 6 | A8 | A1 | Failed |
| oracle 7 | M7 | M7 | Passed |
SHA-256 / a1b16a3c87e6509bb0c733b2a6fe93138e3b3bd529ac99fed9f93aa9df0029b3
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
swap = {'M': 'm', 'm': 'M', 'A': 'd', 'd': 'A', 'AA': 'dd', 'dd': 'AA', 'P': 'P'}
if not isinstance(x, str):
return None
q = x.rstrip('0123456789')
digits = x[len(q):]
if q not in swap or not digits.isdigit() or int(digits) < 1:
return None
n = int(digits)
while n > 9:
n -= 7
perfect = n in (1, 4, 5, 8)
if (q == 'P' and not perfect) or (q in ('M', 'm') and perfect):
return None
return swap[q] + str(9 - n)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('M3', 'm6'), ('m3', 'M6'), ('P5', 'P4'), ('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('d8', 'A1'), ('m9', 'M7')], [('P4', 'P5'), ('P1', 'P8'), ('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('P15', 'P1'), ('m9', 'M7'), ('P22', 'P1')], [('d5', 'A4'), ('M2', 'm7'), ('m7', 'M2'), ('M10', 'm6'), ('P12', 'P4'), ('d8', 'A1'), ('m9', 'M7'), ('A8', 'd1')], [('P8', 'P1'), ('M10', 'm6'), ('P12', 'P4'), ('AA4', 'dd5'), ('dd5', 'AA4'), ('A1', 'd8'), ('m9', 'M7'), ('P22', 'P1')], [('P15', 'P1'), ('dd5', 'AA4'), ('A1', 'd8'), ('M6', 'm3'), ('m9', 'M7'), ('P3', None), ('M4', None), ('A8', 'd1')]]
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 | m6 | m6 | Passed |
| oracle 1 | M6 | M6 | Passed |
| oracle 2 | P4 | P4 | Passed |
| oracle 3 | P5 | P5 | Passed |
| oracle 4 | P8 | P8 | Passed |
| oracle 5 | P1 | P1 | Passed |
| oracle 6 | A1 | A1 | Passed |
| oracle 7 | M0 | M7 | Failed |
SHA-256 / 3db9737de1cf871eb681f18403f4fc4e329e416d999df6ad38020f263f6b0eac
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(x):
swap = {'M': 'm', 'm': 'M', 'A': 'd', 'd': 'A', 'AA': 'dd', 'dd': 'AA', 'P': 'P'}
if not isinstance(x, str):
return None
q = x.rstrip('0123456789')
digits = x[len(q):]
if q not in swap or not digits.isdigit() or int(digits) < 1:
return None
n = int(digits)
while n > 8:
n -= 7
perfect = n in (1, 4, 5, 8)
if (q == 'P' and not perfect) or (q in ('M', 'm') and perfect):
return None
return swap[q] + str(9 - n)
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('M3', 'm6'), ('m3', 'M6'), ('P5', 'P4'), ('P4', 'P5'), ('P1', 'P8'), ('P8', 'P1'), ('d8', 'A1'), ('m9', 'M7')], [('P4', 'P5'), ('P1', 'P8'), ('A4', 'd5'), ('d5', 'A4'), ('M2', 'm7'), ('P15', 'P1'), ('m9', 'M7'), ('P22', 'P1')], [('d5', 'A4'), ('M2', 'm7'), ('m7', 'M2'), ('M10', 'm6'), ('P12', 'P4'), ('d8', 'A1'), ('m9', 'M7'), ('A8', 'd1')], [('P8', 'P1'), ('M10', 'm6'), ('P12', 'P4'), ('AA4', 'dd5'), ('dd5', 'AA4'), ('A1', 'd8'), ('m9', 'M7'), ('P22', 'P1')], [('P15', 'P1'), ('dd5', 'AA4'), ('A1', 'd8'), ('M6', 'm3'), ('m9', 'M7'), ('P3', None), ('M4', None), ('A8', 'd1')]]
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 | m6 | m6 | Passed |
| oracle 1 | M6 | M6 | Passed |
| oracle 2 | P4 | P4 | Passed |
| oracle 3 | P5 | P5 | Passed |
| oracle 4 | P8 | P8 | Passed |
| oracle 5 | P1 | P1 | Passed |
| oracle 6 | A1 | A1 | Passed |
| oracle 7 | M7 | M7 | Passed |
SHA-256 / 64bca019c51f00d28a07b92dfd5600c78e547f1810de3b4bd9fd5a1cb9a05ea9
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.208322+00:00.
Case digest / c0c40dc0a085dca278c71d73cadd50894921309ff8e647ecf47c6145d7ed2813