Skip to content

Chord.ToString() writes non-standard symbols: G9 → "G79", Gmaj9 → "Gmaj79", G13 → "G713", G7sus4 → "Gsus47", C6/9 → "C6add9" #358

Closed

Description

@matt-edmondson

What's wrong

AppendQualityAndSeventh writes 7/maj7 first (Chord.cs#L590-L624). AppendTensions then appends the natural extension number after it (Chord.cs#L645-L688). The resulting "canonical symbol" is not something any chart uses:

Parsed from ToString()
C9 / Cm9 / Cmaj9 / Caug9 C79 / Cm79 / Cmaj79 / Caug79
C11 / C13 / Cmaj13 C711 / C713 / Cmaj713
C7sus4 / C9sus4 Csus47 / Csus479
C6/9 / Cm6/9 C6add9 / Cm6add9

Progression.Parse("4/4 Dm9 | G13 | Cmaj9 | G7sus4").ToString() gives "4/4 Dm79 G713 Cmaj79 Gsus47". Section.ToString() and Arrangement.ToString() inherit the same output.

Parse(ToString()) still round-trips, and the round-trip corpus (ChordRoundTripTests.cs) compares only the parsed structure. Because no test pins the text, this was never caught. The type-safe factories spec calls the output a "canonical symbol (e.g. Cmaj7, C/G)" (spec L95-L153).`` A chart format meant for people should print what a musician writes.

Suggested fix

  • When a natural extension number is emitted for a seventh chord, let it replace the 7: dominant 7+9 becomes 9, and maj7+9 becomes maj9.
  • Put sus after the number: 7sus4, 9sus4.
  • Write a 6 with an added 9 as 6/9, which Chord.Parse already accepts.

Coordinate with #300, which reworks the same AppendTensions branch for 7add13. That issue is about losing the round-trip; this one is the ordinary C9 → C79 case.

Acceptance criteria

  • ToString() returns C9, Cm9, Cmaj9, C11, C13, Cmaj13, C7sus4, C9sus4, C6/9 and Cm6/9 for the inputs in the table.
  • The round-trip corpus gains a text assertion, Parse(s).ToString() == s for canonical inputs, alongside the structural one.

Activity

  1. matt-edmondson commented on Sep 30, 2026

    @matt-edmondson
    ContributorAuthor

    Covered by #360, which redesigns this bug cluster as a whole. Implement it through that issue rather than individually.


    Generated by Claude Code

  2. matt-edmondson commented on Oct 5, 2026

    @matt-edmondson
    ContributorAuthor

    Triage

    Recommended next step: Check on main that Chord.Parse("C9").ToString() == "C9" (and the rest of the acceptance table), then close this issue and its siblings as completed, referencing #362.


    Generated by Claude Code

  3. matt-edmondson commented on Oct 26, 2026

    @matt-edmondson
    ContributorAuthor

    This was fixed by d6116b6, which only closed the first issue it named. Checked on main at 7c693f4: ToString() writes G9, Gmaj9, G13, G7sus4 and C6/9. The old spellings (C79, Csus47, C6add9) still parse through the legacy reader. CanonicalExtensionSymbolsRoundTripWithTones pins this. Closing.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions