Skip to content

Progression.Parse silently drops beat slashes after a Chord@n/d cell: "4/4 C@1/2 / / | G" parses as C for 2 beats with G on beat 3 #328

Description

@matt-edmondson

What's wrong

In the chart format, each whole-token / extends the current chord by one beat (design spec docs/superpowers/specs/2026-07-02-music-type-safe-factories-design.md §Progression). Progression.TryReadChordEvents (Semantics.Music/Progression.Parse.cs:117-125) increments currentBeats for every /. But when the chord cell carried an explicit @n/d duration, FlushChord (Progression.Parse.cs:169) uses explicitDuration ?? Duration.Create(currentBeats, beatUnit), so every slash after it is counted and then thrown away. The input is accepted and its timing is changed without any error.

Reproduction

Progression.Parse("4/4 C@1/2 / / | G").ToString()  ->  "4/4  C / G"

The input puts G on the downbeat of bar 2. The parsed progression puts it on beat 3 of bar 1, and TotalDuration is 3/4 rather than the 5/4 the text reads as. The same path is reached through Section.Parse and Arrangement.Parse, which parse their chart lines with Progression.TryParse.

Related to this: the spec says Parse "treats | as validation", but the loop skips | tokens unconditionally (Progression.Parse.cs:111-114). A bar line in the wrong place is therefore never caught, and this timing shift goes unnoticed as well.

Suggested fix / acceptance criteria

  • Reject a / token that follows a Chord@n/d cell, so TryParse returns false and Parse throws FormatException. The alternative is to define and document additive semantics (explicit duration plus N beats). Rejecting is the smaller change and keeps ToString()→Parse total, because ToString never emits a slash after an @ cell.
  • Optionally, as the spec describes, validate that each | lands on a bar boundary for whole-beat content.
  • Tests: "4/4 C@1/2 / | G" is rejected (or parses to the documented duration), and the existing ProgressionRoundTripTests still pass.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions