FAILURE MAP
← Case archive

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

Key signature size for a named tonic: unknown mode treated as major · case 01

A dorian or capitalised Major request returns a major signature instead of None.

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

ROOT CAUSE

The mode guard only rejects empty values, so any unknown mode falls through to the major branch.

VERIFIED REPAIR

Restore the mode validation step so that it reads `if mode not in ('major', 'minor'):`.

Unsuccessful approach: Checking that the mode is a string still accepts arbitrary unknown mode names.

Case contract

Input [tonic, mode] with tonic a letter optionally followed by one # or b, and mode major or minor. The signature is the letter position on the line of fifths (F -1, C 0, G 1, D 2, A 3, E 4, B 5) plus 7 per sharp and minus 7 per flat; minor keys use the relative major, three fifths flatward. Return the count (positive sharps, negative flats) or None if it lies outside -7..7 or the input is invalid.

Why this case matters

Pitch spelling and interval arithmetic decide the notes that notation, transposition and analysis tools display or play.

1 / The failure

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    base = {'F': -1, 'C': 0, 'G': 1, 'D': 2, 'A': 3, 'E': 4, 'B': 5}
    if not isinstance(x, list) or len(x) != 2:
        return None
    tonic, mode = x
    if not mode:
        return None
    if not isinstance(tonic, str) or not tonic or tonic[0] not in base:
        return None
    rest = tonic[1:]
    if rest not in ('', '#', 'b'):
        return None
    acc = {'': 0, '#': 1, 'b': -1}[rest]
    fifths = base[tonic[0]] + 7 * acc
    if mode == 'minor':
        fifths -= 3
    if fifths < -7 or fifths > 7:
        return None
    return fifths
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[(['C', 'major'], 0), (['G', 'major'], 1), (['F', 'major'], -1), (['F#', 'major'], 6), (['Gb', 'major'], -6), (['C#', 'major'], 7), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['F#', 'major'], 6), (['Gb', 'major'], -6), (['C#', 'major'], 7), (['Cb', 'major'], -7), (['Db', 'major'], -5), (['B', 'major'], 5), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['Cb', 'major'], -7), (['Db', 'major'], -5), (['B', 'major'], 5), (['A', 'minor'], 0), (['E', 'minor'], 1), (['D', 'minor'], -1), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['A', 'minor'], 0), (['E', 'minor'], 1), (['D', 'minor'], -1), (['C#', 'minor'], 4), (['Eb', 'minor'], -6), (['Ab', 'minor'], -7), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['C#', 'minor'], 4), (['Eb', 'minor'], -6), (['Ab', 'minor'], -7), (['G#', 'minor'], 5), (['D#', 'minor'], 6), (['A#', 'minor'], 7), (['C', 'dorian'], None), (['C', 'Major'], None)]]
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 000Passed
oracle 111Passed
oracle 2-1-1Passed
oracle 366Passed
oracle 4-6-6Passed
oracle 577Passed
oracle 60NoneFailed
oracle 70NoneFailed

SHA-256 / f54cc6a73b42b776387ebb565c076cb592a25569939957603bc3ac19ae2d3f95

2 / The unsuccessful fix

Exit 1
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    base = {'F': -1, 'C': 0, 'G': 1, 'D': 2, 'A': 3, 'E': 4, 'B': 5}
    if not isinstance(x, list) or len(x) != 2:
        return None
    tonic, mode = x
    if not isinstance(mode, str):
        return None
    if not isinstance(tonic, str) or not tonic or tonic[0] not in base:
        return None
    rest = tonic[1:]
    if rest not in ('', '#', 'b'):
        return None
    acc = {'': 0, '#': 1, 'b': -1}[rest]
    fifths = base[tonic[0]] + 7 * acc
    if mode == 'minor':
        fifths -= 3
    if fifths < -7 or fifths > 7:
        return None
    return fifths
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[(['C', 'major'], 0), (['G', 'major'], 1), (['F', 'major'], -1), (['F#', 'major'], 6), (['Gb', 'major'], -6), (['C#', 'major'], 7), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['F#', 'major'], 6), (['Gb', 'major'], -6), (['C#', 'major'], 7), (['Cb', 'major'], -7), (['Db', 'major'], -5), (['B', 'major'], 5), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['Cb', 'major'], -7), (['Db', 'major'], -5), (['B', 'major'], 5), (['A', 'minor'], 0), (['E', 'minor'], 1), (['D', 'minor'], -1), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['A', 'minor'], 0), (['E', 'minor'], 1), (['D', 'minor'], -1), (['C#', 'minor'], 4), (['Eb', 'minor'], -6), (['Ab', 'minor'], -7), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['C#', 'minor'], 4), (['Eb', 'minor'], -6), (['Ab', 'minor'], -7), (['G#', 'minor'], 5), (['D#', 'minor'], 6), (['A#', 'minor'], 7), (['C', 'dorian'], None), (['C', 'Major'], None)]]
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 000Passed
oracle 111Passed
oracle 2-1-1Passed
oracle 366Passed
oracle 4-6-6Passed
oracle 577Passed
oracle 60NoneFailed
oracle 70NoneFailed

SHA-256 / 0965d1ca8f5399200748d8c1c45820a4a2154559921fe988c96e54c60ed15ef3

3 / The verified repair

Exit 0
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(x):
    base = {'F': -1, 'C': 0, 'G': 1, 'D': 2, 'A': 3, 'E': 4, 'B': 5}
    if not isinstance(x, list) or len(x) != 2:
        return None
    tonic, mode = x
    if mode not in ('major', 'minor'):
        return None
    if not isinstance(tonic, str) or not tonic or tonic[0] not in base:
        return None
    rest = tonic[1:]
    if rest not in ('', '#', 'b'):
        return None
    acc = {'': 0, '#': 1, 'b': -1}[rest]
    fifths = base[tonic[0]] + 7 * acc
    if mode == 'minor':
        fifths -= 3
    if fifths < -7 or fifths > 7:
        return None
    return fifths
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[(['C', 'major'], 0), (['G', 'major'], 1), (['F', 'major'], -1), (['F#', 'major'], 6), (['Gb', 'major'], -6), (['C#', 'major'], 7), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['F#', 'major'], 6), (['Gb', 'major'], -6), (['C#', 'major'], 7), (['Cb', 'major'], -7), (['Db', 'major'], -5), (['B', 'major'], 5), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['Cb', 'major'], -7), (['Db', 'major'], -5), (['B', 'major'], 5), (['A', 'minor'], 0), (['E', 'minor'], 1), (['D', 'minor'], -1), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['A', 'minor'], 0), (['E', 'minor'], 1), (['D', 'minor'], -1), (['C#', 'minor'], 4), (['Eb', 'minor'], -6), (['Ab', 'minor'], -7), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['C#', 'minor'], 4), (['Eb', 'minor'], -6), (['Ab', 'minor'], -7), (['G#', 'minor'], 5), (['D#', 'minor'], 6), (['A#', 'minor'], 7), (['C', 'dorian'], None), (['C', 'Major'], None)]]
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 000Passed
oracle 111Passed
oracle 2-1-1Passed
oracle 366Passed
oracle 4-6-6Passed
oracle 577Passed
oracle 6NoneNonePassed
oracle 7NoneNonePassed

SHA-256 / 45825ee6afbafba40ae8311109ca9dfcbd0e08816ebb65ca3d9b27333bd1ff48

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

Case digest / 02956d842d15ab6164ba0e169bed500ab3ab5c2564a0d7299d22634e0b03ccd5