FA-81311 / Music interval and transposition theory / Open access
Movable-do chromatic solfege syllables: sharp and flat syllable sets swapped · case 01
Raised degrees are sung with flat syllables (ra, me) when sharp spelling is requested and vice versa.
ROOT CAUSE
The spelling test is negated, selecting the flat syllable table for sharp spelling.
VERIFIED REPAIR
Restore the chromatic spelling branch step so that it reads `if spelling == 'sharp':`.
Unsuccessful approach: Forcing fi for the tritone regardless of spelling still gives fi instead of se in flat spelling.
Case contract
Input [tonic_pc, pitch, spelling] with integer pitch values and spelling sharp or flat. The relative pitch class (pitch - tonic) mod 12 maps diatonic degrees to do re mi fa sol la ti; chromatic degrees use di ri fi si li for sharp spelling and ra me se le te for flat spelling. Invalid input returns None.
Why this case matters
Ear-training and sight-singing apps label notes with movable-do syllables 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) != 3:
return None
tonic, pitch, spelling = x
if not isinstance(tonic, int) or not isinstance(pitch, int) or spelling not in ('sharp', 'flat'):
return None
rel = (pitch - tonic) % 12
diatonic = {0: 'do', 2: 're', 4: 'mi', 5: 'fa', 7: 'sol', 9: 'la', 11: 'ti'}
if rel in diatonic:
return diatonic[rel]
if spelling != 'sharp':
return {1: 'di', 3: 'ri', 6: 'fi', 8: 'si', 10: 'li'}[rel]
return {1: 'ra', 3: 'me', 6: 'se', 8: 'le', 10: 'te'}[rel]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 60, 'sharp'], 'do'), ([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([7, 66, 'sharp'], 'ti')], [([0, 71, 'flat'], 'ti'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'flat'], 'se'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([5, 58, 'flat'], 'fa')], [([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None), ([0, 63, None], None)], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'flat'], 'se'), ([0, 70, 'sharp'], 'li'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([4, 69, 'sharp'], 'fa')], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([2, 63, 'flat'], 'ra'), ([4, 69, 'sharp'], 'fa')]]
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 | do | do | Passed |
| oracle 1 | re | re | Passed |
| oracle 2 | sol | sol | Passed |
| oracle 3 | ti | ti | Passed |
| oracle 4 | ra | di | Failed |
| oracle 5 | se | fi | Failed |
| oracle 6 | fi | se | Failed |
| oracle 7 | ti | ti | Passed |
SHA-256 / 16c77fd659468011ab4858544c105b840eabb2bc8c06e9101baa1c55e30b8183
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) != 3:
return None
tonic, pitch, spelling = x
if not isinstance(tonic, int) or not isinstance(pitch, int) or spelling not in ('sharp', 'flat'):
return None
rel = (pitch - tonic) % 12
diatonic = {0: 'do', 2: 're', 4: 'mi', 5: 'fa', 7: 'sol', 9: 'la', 11: 'ti'}
if rel in diatonic:
return diatonic[rel]
if spelling == 'sharp' or rel == 6:
return {1: 'di', 3: 'ri', 6: 'fi', 8: 'si', 10: 'li'}[rel]
return {1: 'ra', 3: 'me', 6: 'se', 8: 'le', 10: 'te'}[rel]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 60, 'sharp'], 'do'), ([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([7, 66, 'sharp'], 'ti')], [([0, 71, 'flat'], 'ti'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'flat'], 'se'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([5, 58, 'flat'], 'fa')], [([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None), ([0, 63, None], None)], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'flat'], 'se'), ([0, 70, 'sharp'], 'li'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([4, 69, 'sharp'], 'fa')], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([2, 63, 'flat'], 'ra'), ([4, 69, 'sharp'], 'fa')]]
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 | do | do | Passed |
| oracle 1 | re | re | Passed |
| oracle 2 | sol | sol | Passed |
| oracle 3 | ti | ti | Passed |
| oracle 4 | di | di | Passed |
| oracle 5 | fi | fi | Passed |
| oracle 6 | fi | se | Failed |
| oracle 7 | ti | ti | Passed |
SHA-256 / 0ce81251fbbb82e6ffef7ba1d5e2d65b0c78ef275cde9c89ad282d6ca04d659c
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) != 3:
return None
tonic, pitch, spelling = x
if not isinstance(tonic, int) or not isinstance(pitch, int) or spelling not in ('sharp', 'flat'):
return None
rel = (pitch - tonic) % 12
diatonic = {0: 'do', 2: 're', 4: 'mi', 5: 'fa', 7: 'sol', 9: 'la', 11: 'ti'}
if rel in diatonic:
return diatonic[rel]
if spelling == 'sharp':
return {1: 'di', 3: 'ri', 6: 'fi', 8: 'si', 10: 'li'}[rel]
return {1: 'ra', 3: 'me', 6: 'se', 8: 'le', 10: 'te'}[rel]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[([0, 60, 'sharp'], 'do'), ([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([7, 66, 'sharp'], 'ti')], [([0, 71, 'flat'], 'ti'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'flat'], 'se'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([5, 58, 'flat'], 'fa')], [([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None), ([0, 63, None], None)], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'flat'], 'se'), ([0, 70, 'sharp'], 'li'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([4, 69, 'sharp'], 'fa')], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([2, 63, 'flat'], 'ra'), ([4, 69, 'sharp'], 'fa')]]
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 | do | do | Passed |
| oracle 1 | re | re | Passed |
| oracle 2 | sol | sol | Passed |
| oracle 3 | ti | ti | Passed |
| oracle 4 | di | di | Passed |
| oracle 5 | fi | fi | Passed |
| oracle 6 | se | se | Passed |
| oracle 7 | ti | ti | Passed |
SHA-256 / 549c717ad0bf603a9835d33554faae8d06aaf35fa1c413913eb26d821a194886
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.847218+00:00.
Case digest / b1c01d78083d61e9273140ef0b8dd7f28cee4c87897d28a7e289a327650a67b1