epiphany/crates
Levi Neuwirth 6369d331f1 A transposition moves the authored spelling; recording Propagated is not enough
Audit finding 2, reproduced and fixed. The Propagated attachment met the letter
of req:opcat:transpose-interval-spelling and none of its purpose.

The repro: a C4 the author deliberately spelled "C", sharpened to C#4. Both
attachments present -- the stale UserChosen and the new Propagated -- and
resolve_spelling returns Authored(UserChosen) with accidentals []. The notehead
draws a C natural for a pitch sounding C#. The accidental vanishes. Default
precedence ranks UserChosen and Imported above Propagated, so the attachment
this operation writes is always outranked exactly when it is needed.

Per the ratified call, authored spellings are MOVED, not left and not
discarded. A spelling moves by its NOMINAL, because the nominal is what carries
the author's enharmonic decision: someone who wrote B#3 rather than C4 chose
the letter B, so a perfect fifth up is F##4, not G. The accidental is then
whatever the transposed pitch requires at that staff position -- the chromatic
component never touches the spelling except through the pitch. Source,
priority, and layer are preserved: a transposed UserChosen spelling is still
the user's choice. Imported moves too; import fidelity is a property of the
file on disk, which a transposition does not touch.

An authored spelling that cannot be written at the transposed position refuses
the whole operation (TranspositionOutOfRange), resolved before anything is
written, like every other refusal. The two application passes are ordered so
that every index-addressed rewrite lands before the propagated upsert can push
and shift the indices.

The Propagated attachment keeps its purpose: it is the record for pitches with
no authored spelling, where the pre-pass would otherwise re-infer.

Three mutations verified. One of them, S2, SURVIVED the first version of the
enharmonic test and exposed it as a false lock: I had spelled a C#4 pitch as
"C#", so the authored nominal coincided with the pitch's own, and re-inferring
from the pitch gave the same answer. The test proved nothing about keeping the
author's choice. Rewritten around B#3-sounding-C4, where moving the nominal
gives F##4 and re-inference gives G, it now fails under S2 as it must.

Gate: fmt clean, clippy 0, 30 targets / 990 passed / 0 failed, docs 0 under
-D warnings, conformance 8/8, zero golden churn, catalog rebuilds clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 16:40:06 -04:00
..
epiphany-bundle Phase B follow-up: real acceleration-snapshot path + base role bound 2026-07-07 16:54:06 -04:00
epiphany-core A transposition moves the authored spelling; recording Propagated is not enough 2026-07-09 16:40:06 -04:00
epiphany-determinism P12-I2: wire the ratified MUSCLOID layout-object id derivation 2026-06-27 12:46:19 -04:00
epiphany-editor-core TransposeInterval: the faithful transpose, and the frozen one it replaces 2026-07-09 15:46:43 -04:00
epiphany-editor-gui TransposeInterval: the faithful transpose, and the frozen one it replaces 2026-07-09 15:46:43 -04:00
epiphany-engrave P13-I2: Staff::default_clef is the fallback, not decoration 2026-07-09 14:47:42 -04:00
epiphany-layout-ir P13-I3: delete the hand-written notehead anchors; teach the extractor 2026-07-09 14:53:47 -04:00
epiphany-ops A transposition moves the authored spelling; recording Propagated is not enough 2026-07-09 16:40:06 -04:00
epiphany-render-svg P13-I3: delete the hand-written notehead anchors; teach the extractor 2026-07-09 14:53:47 -04:00
epiphany-testkit Stop the conformance suite from authoring the frozen operation 2026-07-09 15:50:22 -04:00