Claude Code skill · built 2026-09-08 transcription-repair

Repair an existing music transcription by treating the best human transcription as the musical model and isolated stems as evidence that tests individual claims inside it. Every rule below has a shipped failure behind it.

Executable assertions

101
6 suites, all passing, numpy and scipy only

Adversarial fixtures

21
each one a repair that actually shipped wrong

Promotion conditions

9
every one named separately on refusal

Evidence states

7
with a legal-transition table that blocks shortcuts

The principle

Start from the human transcription. Use stems to test claims inside it. A human transcription establishes the grid, the meter, the rhythmic spelling, the instrument vocabulary and the phrase structure. Audio decides whether the written events happened. When the two disagree, investigate that specific disagreement.

The failure this replaces. A repair placed 164 toms using a printed chart for the count and stem onsets for the timing. Ten toms in one measure landed at 11.23, 11.55, 11.94, 12.85, 13.78, 14.74, 15.73, 16.01, 16.45 and 18.63 sixteenths. Two pairs sat under a third of a sixteenth apart, so the writer subdivided to 32nds and stacked High Tom on Hi-Mid Tom. Across 40 tom measures, 30 held a placement over 0.20 of a sixteenth off grid. It was rewritten by hand as plain descending sixteenths 26 minutes later.

The pipeline, in order

  1. Asset inventory. Refuses a missing file, an empty file and an iCloud placeholder. A placeholder reads as empty and returns a clean, confident, wrong answer.
  2. Key census. tr_ledger.py keys prints every element and property name with counts. A missing key is evidence only after this runs. Searching <Ghost> and finding zero started the sweep that stripped 3,842 ghosted noteheads off sixteen live tabs. The element is <AntiAccent>.
  3. Recording identity. Seven checks, each needing evidence: duration, arrangement, opening, closing, three distributed landmarks, known edits, master. An unanswered check is a refusal.
  4. The musical clock. Rational quarter-note coordinates, integrating the complete tempo function including progressive automations. Reading only the first tempo builds a clock right for one bar and wrong for the rest.
  5. Alignment gate. One-to-one matching against four controls. No CONFIRMED, no stem timing authorizes an edit.
  6. Stem reading. The stem label is the instrument identity. Per-onset tom classification, cymbal attack against decay, leakage tests.
  7. Grid snapping. Onsets map through the clock into the chart's own subdivision vocabulary. A new subdivision needs affirmative evidence.
  8. Two hands, two feet. Run on the voice you did not edit.
  9. Edit ledger and promotion. Nine conditions. Passing yields LOCAL_VALIDATED, which is not a submitted revision.

Alignment: the three ways a match rate lies

TrapWhat it looked likeWhat it wasThe refusal
No null at all45.5% match 43.4% against the same audio reversed, 35.5% random the tab carried the idiom and density of the music and almost none of its events
Dense detector64.0% match58% chance baseline above a 35% null the gate demands 25 points, not 5
Periodic annotation100% match, z looks fine rotation null 94% a rotation of a metronome is nearly the metronome. UNUSABLE, route to landmarks

The landmark route is what actually carries a repetitive part. It requires a stated selection rule, at least 8 landmarks, 50% coverage, chance occupancy computed from the real detected set, a rotation null, a binomial p value, and the list of landmarks that failed. A selection rule chosen after seeing what matched is refused, because the landmarks would then have been chosen because they matched.

The 15 adversarial fixtures

The suite tests whether an answer was earned. Producing an answer from deliberately inadequate evidence fails even when the code runs clean.

#FixtureRequired behaviourResult
1tom onsets carried as raw secondsrefuse, name the off-grid count3/7 off grid
2two toms 3 Hz apartUNRESOLVED for every eventcalib distance 0.68
3a 6-second crash decayone attack1 of 3 candidates
4pedal chicks missing in three barsfind all threebars 2, 5, 9
5a ghost figure in 6 of 10 barssweep the other four as PROPOSEDbars 6–9
6wrong recording, same tempo and densityrefuse36% vs 23% null
7three tempo changesread all three84–132 bpm
8a track named Drums, all notes off the GM mapnot a drum staff100% off map
9a 4.2 px staff spaceUNRESOLVED without calibrationrefused
10an edit touching an unrelated trackregression failsmidi 43 → 45 caught
11a bar where only the ride playsprotected from a silence sweepbar 1 protected
12a 50 ms refractory at 170 bpm on 32ndsrefuse the detector setting1/32 = 44.1 ms
13a validation record for an older hashnot currenthash mismatch
14an unanswered recording-identity checkrefuse the whole map6 unanswered
15a cymbal proposalless machine credit than a kickF1 0.481 vs 0.931

Plus eight evidence-quality refusals

An edit with no evidence fields cannot enter the ledger. A PROPOSED edit cannot jump to VALIDATED. Promotion is refused on a failed regression, on a non-CONFIRMED alignment, and on a stale hash. Two tabs agreeing at 99.5% count as one source. An unmeasured source pair is reported rather than assumed independent. An iCloud placeholder is refused as an asset.

Evidence authority is scoped to the question

One ranking that answers every question is the wrong shape.

QuestionWho decides
Meter, barring, phrase structurepublisher or academic score, then specialist chart
Written subdivision and rhythmic spellinghuman transcription, then validated timing
Does this stroke exist in the takeisolated stem, then full mix, then the score
Which drum soundedisolated stem, then score, then chart
How loud relative to its neighboursisolated stem, then score
Which articulation is intendedscore, then chart, then stem
What a notation symbol meansthe notation standard, via /notation-evidence-gate

So an isolated snare stem outranks a human transcription on whether one particular strike exists. A professional score outranks raw onset timing on whether a late strike belongs on the written sixteenth.

Machine evidence is weighted per drum class

Benchmark F1 at a 50 ms one-to-one protocol on MDB Drums. Treating separation quality as one number lets a cymbal proposal inherit a kick's credibility.

ClassF1Tier
kick0.931strong
snare0.760usable
hi-hat0.650weak
toms—weak, commonly one combined stem
cymbal0.481weak, dense broadband

Real audio found a defect the fixtures could not

On GP bars 99 to 103 of a coda marked p / pp and "cymbal on dome", cymbal_events(instrument="ride") returned zero fresh attacks against 75 written events. Nothing in the return value said the detector had failed, so the zero read as an absence and very nearly became a deletion.

Two repairs were tried on a reproduction fixture of twelve quiet dome pings under a loud crash bed. Both failed, and the failure is the finding.

RouteBest operating pointVerdict
novelty threshold sweep, 3 bands x 5 deltas x 2 refractory settings recall 0.92 at precision 0.11, or precision 0.60 at recall 0.25 unusable
spectral template matched to hand-labelled strokes from the same stem held-out gains +0.003 to +0.015 against random instants −0.027 to +0.015, fully overlapping unusable

A quiet dome ping far under a loud resonant bed is not recoverable from that stem. Three refusals shipped in place of a tuned number.

promotable: False

The bell profile returns CANDIDATE_ONLY. No downstream step may read one of its hits as an attack.

detector_reality_check

Under 15 percent of what the notation writes across 8 or more events returns DETECTOR_FAILURE. The silent zero becomes a loud refusal, and the eye wins.

cymbal_separability

Holds out half the labelled strokes against random instants clear of every label. NOT_SEPARABLE means stop sweeping and get a better-isolated stem.

Three design changes the self-test forced

Each of these failed on the first run, and each failure changed the design rather than the expectation.

1 · Periodicity

A metronomic fixture could not be CONFIRMED by a rotation null, and it should not be. Periodicity is now measured off the annotation's own intervals and routed to landmarks unconditionally.

2 · Decay constant

A hardcoded 0.6 s decay against a 1.4 s ring predicted a fall the cymbal never takes, and noise scored as five attacks where four existed. The constant is now measured on the recording.

3 · Separability

Two toms 2 Hz apart were labelled confidently because within-class spread was tiny. Every call is now gated on whether the calibration itself separates, with a measurement floor per feature.

Running it

T=~/.claude/skills/transcription-repair

python3 $T/tr_ledger.py keys FILE            # key census. Run FIRST of all
python3 $T/tr_ledger.py diff A B             # note-INSTANCE diff, 7 conflict classes
python3 $T/tr_ledger.py regress ORIG EDIT --scope-track 3

python3 $T/tr_audio.py  onsets STEM.wav --instrument snare --out on.txt
python3 $T/tr_audio.py  align  --notated n.txt --detected on.txt --duration 372.4
python3 $T/tr_audio.py  cymbal RIDE.wav      # NEW_ATTACK / DECAY_ONLY / UNRESOLVED
python3 $T/tr_audio.py  toms   TOMS.wav --calib calib.json
python3 $T/tr_audio.py  leak   --target TOM.wav --others SNARE.wav --at 91.44

python3 $T/tr_score.py  grid   L.json        # the chart's own subdivision vocabulary
python3 $T/tr_score.py  hands  L.json        # two hands, two feet, ornament guards
python3 $T/tr_score.py  ghosts L.json --lane 38
python3 $T/tr_score.py  pedal  L.json

python3 $T/tr_gate.py   tempo  SCORE.gp      # EVERY tempo event
python3 $T/tr_gate.py   track  SCORE.gp      # is this staff actually drums
python3 $T/tr_gate.py   promote --ledger E.jsonl --original A.gp --edited B.gp \
                                --scope-track 3

$T/run_selftests.sh                          # all 4 suites, exit 0 required

Completion

Completion is a saved, scoped artifact at an exact hash whose relevant track passed the whole validation suite, with an edit ledger explaining every changed instance. Successful script execution is not completion, since exit 0 proves only that a tool ran.

A finished repair reads bar by bar. Another musician can reconstruct why every changed event changed. Uncertain events stay visibly unresolved. Expect fewer edits than an unconstrained audio-to-MIDI pass would make. Existing expert work survives unless specific evidence justifies changing it, which is the design target rather than a shortfall against it.

Skill: ~/.claude/skills/transcription-repair/ · 4,344 lines of Python, 692 lines of SKILL.md, 404 lines of reference · SKILL.md, tr_ledger.py, tr_audio.py, tr_score.py, tr_gate.py, tr_verify.py, tr_edit_lock.py, run_selftests.sh, reference/research-dossier.md, reference/gp-percussion.md

Composes with: /notation-evidence-gate · /songsterr-drum-repair · /songsterr-upload · /stems-to-guitar-pro-drums · /impossible-guitar-parts · /composite-stem-alignment

Numbers on this page are measured. Benchmark F1 figures are cited from published drum-transcription evaluation and carried as priors on machine evidence only. Provenance is marked per fact in reference/research-dossier.md.