FA-81196 / Music interval and transposition theory / Open access
Roman numeral label for a chord in a key: diminished quality marker dropped · case 01
The leading-tone chord in C major is labelled vii with no diminished marker.
ROOT CAUSE
The suffix table maps diminished quality to an empty marker.
VERIFIED REPAIR
Restore the diminished suffix step so that it reads `'dim': '°'`.
Unsuccessful approach: Substituting a letter o for the degree sign does not match the stipulated ° marker.
Case contract
Input [tonic_pc, mode, root_pc, quality] with mode major or minor (natural minor scale 0 2 3 5 7 8 10) and quality maj, min, dim or aug. Diatonic roots use their degree; in minor the leading tone (11 semitones) is degree VII with no prefix. Other roots in major are written b + the degree a semitone above; in minor # + the degree a semitone below. Numerals are uppercase for maj and aug, lowercase for min and dim, with suffix ° for dim and + for aug. Invalid input returns None.
Why this case matters
Harmonic analysis and ear-training tools label chords relative to the key.
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
tonic, mode, root, quality = x
scales = {'major': [0, 2, 4, 5, 7, 9, 11], 'minor': [0, 2, 3, 5, 7, 8, 10]}
if mode not in scales or quality not in ('maj', 'min', 'dim', 'aug'):
return None
if not all(isinstance(v, int) for v in (tonic, root)):
return None
rel = (root - tonic) % 12
scale = scales[mode]
names = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII']
prefix = ''
if rel in scale:
deg = scale.index(rel)
elif mode == 'minor' and rel == 11:
deg = 6
elif mode == 'major':
prefix = 'b'
deg = scale.index((rel + 1) % 12)
else:
prefix = '#'
deg = scale.index((rel - 1) % 12)
numeral = names[deg] if quality in ('maj', 'aug') else names[deg].lower()
suffix = {'maj': '', 'min': '', 'dim': '', 'aug': '+'}[quality]
return prefix + numeral + suffix
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 'major', 7, 'maj'], 'V'), ([0, 'major', 2, 'min'], 'ii'), ([0, 'major', 11, 'dim'], 'vii°'), ([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 3, 'dim'], '#iv°')], [([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 3, 'maj'], 'bIII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 11, 'dim'], 'vii°')], [([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([0, 'minor', 11, 'dim'], 'vii°'), ([2, 'major', 1, 'dim'], 'vii°')], [([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 9, 'min'], '#vi'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([2, 'major', 1, 'dim'], 'vii°'), ([5, 'major', 4, 'dim'], 'vii°')], [([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([7, 'major', 2, 'maj'], 'V'), ([7, 'major', 0, 'maj'], 'IV'), ([0, 'major', 0, 'aug'], 'I+'), ([5, 'major', 4, 'dim'], 'vii°'), ([5, 'minor', 4, 'dim'], 'vii°')]]
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 | V | V | Passed |
| oracle 1 | ii | ii | Passed |
| oracle 2 | vii | vii° | Failed |
| oracle 3 | bVI | bVI | Passed |
| oracle 4 | bVII | bVII | Passed |
| oracle 5 | bII | bII | Passed |
| oracle 6 | vii | vii° | Failed |
| oracle 7 | #iv | #iv° | Failed |
SHA-256 / dba3e10d8f75b05ddc6c067c69a61dff7d593d21636a97f9096a3617ea75a0db
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
tonic, mode, root, quality = x
scales = {'major': [0, 2, 4, 5, 7, 9, 11], 'minor': [0, 2, 3, 5, 7, 8, 10]}
if mode not in scales or quality not in ('maj', 'min', 'dim', 'aug'):
return None
if not all(isinstance(v, int) for v in (tonic, root)):
return None
rel = (root - tonic) % 12
scale = scales[mode]
names = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII']
prefix = ''
if rel in scale:
deg = scale.index(rel)
elif mode == 'minor' and rel == 11:
deg = 6
elif mode == 'major':
prefix = 'b'
deg = scale.index((rel + 1) % 12)
else:
prefix = '#'
deg = scale.index((rel - 1) % 12)
numeral = names[deg] if quality in ('maj', 'aug') else names[deg].lower()
suffix = {'maj': '', 'min': '', 'dim': 'o', 'aug': '+'}[quality]
return prefix + numeral + suffix
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 'major', 7, 'maj'], 'V'), ([0, 'major', 2, 'min'], 'ii'), ([0, 'major', 11, 'dim'], 'vii°'), ([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 3, 'dim'], '#iv°')], [([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 3, 'maj'], 'bIII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 11, 'dim'], 'vii°')], [([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([0, 'minor', 11, 'dim'], 'vii°'), ([2, 'major', 1, 'dim'], 'vii°')], [([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 9, 'min'], '#vi'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([2, 'major', 1, 'dim'], 'vii°'), ([5, 'major', 4, 'dim'], 'vii°')], [([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([7, 'major', 2, 'maj'], 'V'), ([7, 'major', 0, 'maj'], 'IV'), ([0, 'major', 0, 'aug'], 'I+'), ([5, 'major', 4, 'dim'], 'vii°'), ([5, 'minor', 4, 'dim'], 'vii°')]]
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 | V | V | Passed |
| oracle 1 | ii | ii | Passed |
| oracle 2 | viio | vii° | Failed |
| oracle 3 | bVI | bVI | Passed |
| oracle 4 | bVII | bVII | Passed |
| oracle 5 | bII | bII | Passed |
| oracle 6 | viio | vii° | Failed |
| oracle 7 | #ivo | #iv° | Failed |
SHA-256 / 8145fe4035bbdc4226ec4a42a1916d757459b951c38e03da0455509e5da82a7b
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
tonic, mode, root, quality = x
scales = {'major': [0, 2, 4, 5, 7, 9, 11], 'minor': [0, 2, 3, 5, 7, 8, 10]}
if mode not in scales or quality not in ('maj', 'min', 'dim', 'aug'):
return None
if not all(isinstance(v, int) for v in (tonic, root)):
return None
rel = (root - tonic) % 12
scale = scales[mode]
names = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII']
prefix = ''
if rel in scale:
deg = scale.index(rel)
elif mode == 'minor' and rel == 11:
deg = 6
elif mode == 'major':
prefix = 'b'
deg = scale.index((rel + 1) % 12)
else:
prefix = '#'
deg = scale.index((rel - 1) % 12)
numeral = names[deg] if quality in ('maj', 'aug') else names[deg].lower()
suffix = {'maj': '', 'min': '', 'dim': '°', 'aug': '+'}[quality]
return prefix + numeral + suffix
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 'major', 7, 'maj'], 'V'), ([0, 'major', 2, 'min'], 'ii'), ([0, 'major', 11, 'dim'], 'vii°'), ([0, 'major', 8, 'maj'], 'bVI'), ([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 3, 'dim'], '#iv°')], [([0, 'major', 10, 'maj'], 'bVII'), ([0, 'major', 1, 'maj'], 'bII'), ([0, 'major', 3, 'maj'], 'bIII'), ([0, 'major', 6, 'dim'], 'bv°'), ([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 11, 'dim'], 'vii°')], [([9, 'minor', 4, 'maj'], 'V'), ([9, 'minor', 8, 'dim'], 'vii°'), ([9, 'minor', 0, 'maj'], 'III'), ([9, 'minor', 7, 'maj'], 'VII'), ([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([0, 'minor', 11, 'dim'], 'vii°'), ([2, 'major', 1, 'dim'], 'vii°')], [([9, 'minor', 6, 'min'], '#vi'), ([9, 'minor', 1, 'maj'], '#III'), ([9, 'minor', 3, 'dim'], '#iv°'), ([0, 'minor', 9, 'min'], '#vi'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([2, 'major', 1, 'dim'], 'vii°'), ([5, 'major', 4, 'dim'], 'vii°')], [([0, 'minor', 11, 'dim'], 'vii°'), ([0, 'minor', 4, 'maj'], '#III'), ([0, 'minor', 3, 'aug'], 'III+'), ([7, 'major', 2, 'maj'], 'V'), ([7, 'major', 0, 'maj'], 'IV'), ([0, 'major', 0, 'aug'], 'I+'), ([5, 'major', 4, 'dim'], 'vii°'), ([5, 'minor', 4, 'dim'], 'vii°')]]
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 | V | V | Passed |
| oracle 1 | ii | ii | Passed |
| oracle 2 | vii° | vii° | Passed |
| oracle 3 | bVI | bVI | Passed |
| oracle 4 | bVII | bVII | Passed |
| oracle 5 | bII | bII | Passed |
| oracle 6 | vii° | vii° | Passed |
| oracle 7 | #iv° | #iv° | Passed |
SHA-256 / face72c9b0b32cbca9c1c93c9614455cfb5aac34799451f5cdb715192a08b089
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:00.640400+00:00.
Case digest / d45bd121644a88386c9b599d479d49b4e367845e0f19c633b4d625b049fd357b