FAILURE MAP
← Case archive

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.

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

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 fixtureActualExpectedOutcome
oracle 0dodoPassed
oracle 1rerePassed
oracle 2solsolPassed
oracle 3titiPassed
oracle 4radiFailed
oracle 5sefiFailed
oracle 6fiseFailed
oracle 7titiPassed

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 fixtureActualExpectedOutcome
oracle 0dodoPassed
oracle 1rerePassed
oracle 2solsolPassed
oracle 3titiPassed
oracle 4didiPassed
oracle 5fifiPassed
oracle 6fiseFailed
oracle 7titiPassed

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 fixtureActualExpectedOutcome
oracle 0dodoPassed
oracle 1rerePassed
oracle 2solsolPassed
oracle 3titiPassed
oracle 4didiPassed
oracle 5fifiPassed
oracle 6sesePassed
oracle 7titiPassed

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