FAILURE MAP
← Case archive

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

Key signature size for a named tonic: minor key shifted sharpward · case 01

A minor reports three sharps and D minor two sharps instead of zero and one flat.

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

ROOT CAUSE

The relative-major offset for minor keys is applied three fifths sharpward instead of flatward.

VERIFIED REPAIR

Restore the relative minor direction step so that it reads `fifths -= 3`.

Unsuccessful approach: Applying the offset only to natural-letter tonics leaves C# minor and Eb minor at their parallel-major signatures.

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 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), (['A', 'minor'], 0), (['D', 'minor'], -1), (['C#', 'minor'], 4), (['G#', 'minor'], 5)], [(['F#', 'major'], 6), (['Gb', 'major'], -6), (['C#', 'major'], 7), (['Cb', 'major'], -7), (['E', 'minor'], 1), (['C#', 'minor'], 4), (['Eb', 'minor'], -6), (['D#', 'minor'], 6)], [(['Cb', 'major'], -7), (['Db', 'major'], -5), (['B', 'major'], 5), (['D', 'minor'], -1), (['Eb', 'minor'], -6), (['Ab', 'minor'], -7), (['A#', 'minor'], 7), (['Fb', 'major'], None)], [(['C#', 'minor'], 4), (['Ab', 'minor'], -7), (['G#', 'minor'], 5), (['Fb', 'major'], None), (['B#', 'major'], None), (['Bb', 'minor'], -5), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['Eb', 'minor'], -6), (['G#', 'minor'], 5), (['D#', 'minor'], 6), (['C', 'Major'], None), (['H', 'major'], None), (['Cx', 'major'], None), (['E#', 'major'], None), (['Gb', 'minor'], 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 460Failed
oracle 55-1Failed
oracle 6None4Failed
oracle 7None5Failed

SHA-256 / 90582b2c3d0c73261c77e6effcc04ebbca81792210ef796427d317154f832358

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 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 acc == 0 else 0
    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), (['A', 'minor'], 0), (['D', 'minor'], -1), (['C#', 'minor'], 4), (['G#', 'minor'], 5)], [(['F#', 'major'], 6), (['Gb', 'major'], -6), (['C#', 'major'], 7), (['Cb', 'major'], -7), (['E', 'minor'], 1), (['C#', 'minor'], 4), (['Eb', 'minor'], -6), (['D#', 'minor'], 6)], [(['Cb', 'major'], -7), (['Db', 'major'], -5), (['B', 'major'], 5), (['D', 'minor'], -1), (['Eb', 'minor'], -6), (['Ab', 'minor'], -7), (['A#', 'minor'], 7), (['Fb', 'major'], None)], [(['C#', 'minor'], 4), (['Ab', 'minor'], -7), (['G#', 'minor'], 5), (['Fb', 'major'], None), (['B#', 'major'], None), (['Bb', 'minor'], -5), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['Eb', 'minor'], -6), (['G#', 'minor'], 5), (['D#', 'minor'], 6), (['C', 'Major'], None), (['H', 'major'], None), (['Cx', 'major'], None), (['E#', 'major'], None), (['Gb', 'minor'], 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 400Passed
oracle 5-1-1Passed
oracle 674Failed
oracle 7None5Failed

SHA-256 / 9bcc1e1fa4c6253858edf492729d27323be51c94283abdfdb9eb48190d4433cc

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), (['A', 'minor'], 0), (['D', 'minor'], -1), (['C#', 'minor'], 4), (['G#', 'minor'], 5)], [(['F#', 'major'], 6), (['Gb', 'major'], -6), (['C#', 'major'], 7), (['Cb', 'major'], -7), (['E', 'minor'], 1), (['C#', 'minor'], 4), (['Eb', 'minor'], -6), (['D#', 'minor'], 6)], [(['Cb', 'major'], -7), (['Db', 'major'], -5), (['B', 'major'], 5), (['D', 'minor'], -1), (['Eb', 'minor'], -6), (['Ab', 'minor'], -7), (['A#', 'minor'], 7), (['Fb', 'major'], None)], [(['C#', 'minor'], 4), (['Ab', 'minor'], -7), (['G#', 'minor'], 5), (['Fb', 'major'], None), (['B#', 'major'], None), (['Bb', 'minor'], -5), (['C', 'dorian'], None), (['C', 'Major'], None)], [(['Eb', 'minor'], -6), (['G#', 'minor'], 5), (['D#', 'minor'], 6), (['C', 'Major'], None), (['H', 'major'], None), (['Cx', 'major'], None), (['E#', 'major'], None), (['Gb', 'minor'], 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 400Passed
oracle 5-1-1Passed
oracle 644Passed
oracle 755Passed

SHA-256 / 8055cffd85afb650ed2e87443c2178dc2e84fff49c0459056f3586d424554051

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

Case digest / 85d971a811c30b57ca48c0817a93126569ffe9208d47f336062cfb32a980e5e5