FAILURE MAP
← Case archive

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

Movable-do chromatic solfege syllables: degree measured downward from the tonic · case 01

In C, the note D is sung te or li instead of re because the distance is measured from pitch to tonic.

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

ROOT CAUSE

The relative pitch class subtracts in the wrong order, mirroring every degree around the tonic.

VERIFIED REPAIR

Restore the relative degree direction step so that it reads `(pitch - tonic) % 12`.

Unsuccessful approach: Taking the absolute difference only works when the pitch lies above the tonic number.

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 = (tonic - pitch) % 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, 71, 'flat'], 'ti'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([3, 1, 'sharp'], 'li')], [([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([3, 1, 'sharp'], 'li')], [([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([3, 1, 'sharp'], 'li')], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([3, 1, 'sharp'], 'li')], [([0, 61, 'flat'], 'ra'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([3, 1, 'sharp'], 'li')]]
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 1tereFailed
oracle 2ratiFailed
oracle 3fifiPassed
oracle 4sesePassed
oracle 5NoneNonePassed
oracle 6NoneNonePassed
oracle 7reliFailed

SHA-256 / 1e89e6f131b1c5d528f07ae2277339b17397332e23b14855451e3d1637880283

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 = abs(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, 71, 'flat'], 'ti'), ([0, 66, 'sharp'], 'fi'), ([0, 66, 'flat'], 'se'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([3, 1, 'sharp'], 'li')], [([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 65, 'weird'], None), ([0, 63, None], None), ([9, 57, 'flat'], 'do'), ([3, 1, 'sharp'], 'li')], [([0, 62, 'flat'], 're'), ([0, 67, 'sharp'], 'sol'), ([0, 71, 'flat'], 'ti'), ([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([3, 1, 'sharp'], 'li')], [([0, 61, 'sharp'], 'di'), ([0, 61, 'flat'], 'ra'), ([0, 70, 'flat'], 'te'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([3, 1, 'sharp'], 'li')], [([0, 61, 'flat'], 'ra'), ([0, 70, 'sharp'], 'li'), ([7, 66, 'sharp'], 'ti'), ([7, 64, 'flat'], 'la'), ([7, 60, 'sharp'], 'fa'), ([2, 64, 'sharp'], 're'), ([2, 63, 'flat'], 'ra'), ([3, 1, 'sharp'], 'li')]]
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 2titiPassed
oracle 3fifiPassed
oracle 4sesePassed
oracle 5NoneNonePassed
oracle 6NoneNonePassed
oracle 7reliFailed

SHA-256 / fe136ad037987c0bb7f5d5ec566c02e672c7a26e96b3656b74addf4fb19edaeb

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

SHA-256 / 3df2e1667528a18b57598ba6019af1dce4c50dd5a4b1e2fdb11146fc83b0f63e

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

Case digest / b343b2c00e87827c42c133c58cbc25650a5ae8b6e12dc033fff36323c2a249ad