FAILURE MAP
← Case archive

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

Movable-do chromatic solfege syllables: unknown spelling defaults to flats · case 01

An unknown spelling such as "weird" yields flat syllables instead of None.

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

ROOT CAUSE

Validation only rejects a missing spelling, so any other value falls through to the flat table.

VERIFIED REPAIR

Restore the spelling validation step so that it reads `spelling not in ('sharp', 'flat')`.

Unsuccessful approach: Checking only for a string type still accepts arbitrary spelling names.

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 is None:
        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, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 65, 'weird'], None)], [([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([0, 65, 'weird'], None)], [([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([0, 65, 'weird'], None)], [([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None)], [([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([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 fixtureActualExpectedOutcome
oracle 0dodoPassed
oracle 1rerePassed
oracle 2solsolPassed
oracle 3titiPassed
oracle 4didiPassed
oracle 5raraPassed
oracle 6fifiPassed
oracle 7faNoneFailed

SHA-256 / 835217801696dc98288d7a62b471e44ccec786165b3aad5fe1c0380c112bbbcc

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 not isinstance(spelling, str):
        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, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 65, 'weird'], None)], [([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([0, 65, 'weird'], None)], [([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([0, 65, 'weird'], None)], [([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None)], [([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([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 fixtureActualExpectedOutcome
oracle 0dodoPassed
oracle 1rerePassed
oracle 2solsolPassed
oracle 3titiPassed
oracle 4didiPassed
oracle 5raraPassed
oracle 6fifiPassed
oracle 7faNoneFailed

SHA-256 / 8a83e14e4a30f268b487b510c3cd68d6db419601dc4449b369b62fd06aabf6b4

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, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 65, 'weird'], None)], [([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([0, 65, 'weird'], None)], [([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([0, 65, 'weird'], None)], [([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None)], [([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([5, 58, 'flat'], 'fa'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([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 fixtureActualExpectedOutcome
oracle 0dodoPassed
oracle 1rerePassed
oracle 2solsolPassed
oracle 3titiPassed
oracle 4didiPassed
oracle 5raraPassed
oracle 6fifiPassed
oracle 7NoneNonePassed

SHA-256 / bf5a8a690205630dfa9eaf200aea6e26b3c6503abe2aca4caeb111a755d8d5d5

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

Case digest / 9874d3e1de35303f572922d2c41e9493e9e8d22a2540d91203f29ec6ad18217d