You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Chord.Parse drops everything after the slash-bass note: "C/Gm", "C/E/G" and "C/Bb7" parse as "C/G", "C/E" and "C/A#" #344
After a /, Chord.TryParse reads the bass note with TryParseRoot (Semantics.Music/Chord.cs:108-116, 213-225). TryParseRoot reads one letter plus any accidentals and stops there. Nothing then checks that the rest of the bass text was used.
The leftover-text check added for #280 (Chord.cs:80-86, IsQualityVocabulary) only looks at the text before the slash. Anything after the bass note is therefore dropped without an error.
PitchClass.TryParse already has the missing check: at PitchClass.cs:141-144 it returns false when index != text.Length.
Reproduced
These results come from running each input through the built library at 7167117:
Input
Result today
Expected
C/Gm
C/G
reject
C/E/G
C/E
reject
Am/G/F
Am/G
reject
C7/G#m7b5
C7/G#
reject
C/Bb7
C/A#
reject
C/Gxyz
C/G
reject
Progression.Parse, ChordEvent.Parse and Section/Arrangement parsing all go through Chord.TryParse. A typo in a chart is therefore accepted silently instead of failing.
Suggested fix
Parse the bass with PitchClass.TryParse(symbol[(slash + 1)..], …), or require bassIndex == bassText.Length. A bass that does not parse cleanly must still fall through to the existing 6/9 rewrite, so that C6/9 and C6/9/G keep working.
Acceptance criteria
Every input in the table is rejected.
C/G, Dm7/G, C6/9, Cm6/9, C6/9/G and Db/Cb still parse.
Priority: Medium. Malformed slash chords are accepted as a different chord with no error, and every chart parser (Progression, ChordEvent, Section, Arrangement) inherits this. The inputs are typos rather than common valid spellings, so the impact is mostly lost validation.
Area / suggested assignment:Semantics.Music/Chord.cs, the slash-bass branch of TryParse (lines 108-116 and TryParseRoot at 213-225). Reuse the end-of-input check from PitchClass.TryParse (PitchClass.cs:141-144).
Activity
matt-edmondson commentedon Sep 30, 2026
Triage
Progression,ChordEvent,Section,Arrangement) inherits this. The inputs are typos rather than common valid spellings, so the impact is mostly lost validation.Semantics.Music/Chord.cs, the slash-bass branch ofTryParse(lines 108-116 andTryParseRootat 213-225). Reuse the end-of-input check fromPitchClass.TryParse(PitchClass.cs:141-144).Chord.Parsevalidation cluster with Chord.Parse accepts quality characters in any order and any number: "C7M", "C57", "C77" and "C7m" all parse as C7 #346 and Chord.Parse reads "-"/"+" alteration signs as chord quality: "C7-9" becomes Cm9, "C7-5" becomes Cm7, "Cmaj7-5" becomes CmMaj7, "C7+9" becomes Caug9 #345 (filed alongside this one), Chord.Parse reads "Cm7#5", "Cm#5" and "Cm+" as augmented chords with a major third (Cm7#5 comes back as Caug7) #340, Chord.Parse stacks the natural 9th/11th under an altered one: "C13#11" sounds both F and F#, "C13b9" both Db and D #341, Chord.Parse reads "CM9", "CM11" and "CM13" as dominant chords (Bb, not B), and "CmM9" as a plain Cm9 #322 and Chord round-trip breaks for a seventh with add11/add13: "C7add13" prints as "C713", which reparses as C13 with a 9th and 11th #300. Follows up the leftover-text check from Chord.Parse turns "C69", "Cadd11" and "Cadd13" into dominant-seventh chords with an extra b7 instead of rejecting them #280, which only covers the text before the slash. Chord.ToString() writes an altered tension straight after the root: "C(#11)" prints as "C#11" and reparses as a C# dominant eleventh #336 is the related ToString round-trip issue.C6/9andC6/9/Gstill parse. Add every row of the table, plus the listed positive cases, toChordTests. The Chord.Parse drops everything after the slash-bass note: "C/Gm", "C/E/G" and "C/Bb7" parse as "C/G", "C/E" and "C/A#" #344/Chord.Parse reads "-"/"+" alteration signs as chord quality: "C7-9" becomes Cm9, "C7-5" becomes Cm7, "Cmaj7-5" becomes CmMaj7, "C7+9" becomes Caug9 #345/Chord.Parse accepts quality characters in any order and any number: "C7M", "C57", "C77" and "C7m" all parse as C7 #346 fixes all touchTryParseand the leftover check, so they would conflict less as one PR or done in sequence.Generated by Claude Code
matt-edmondson commentedon Sep 30, 2026
Covered by #360, which redesigns this bug cluster as a whole. Implement it through that issue rather than individually.
Generated by Claude Code
[minor] Redesign chord symbols; fixes #300, #322, #336, #340, #341, #344