Skip to content

docs: explain the direction/voice/staff round-trip drop cluster - #325

Merged
webern merged 1 commit into
mainfrom
clarify-direction-drops
Jul 7, 2026
Merged

docs: explain the direction/voice/staff round-trip drop cluster#325
webern merged 1 commit into
mainfrom
clarify-direction-drops

Conversation

@webern

@webern webern commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Human Summary

Hmmm, ok, well this adds a couple of stateful comments around directions that are currently unsupported. Seems harmless and perhaps it will help the LLM understand what's going on in the future. Seems like a bit of a cop out from the agent instead of supporting the missing features, but oh well. It opened an issue that likely words what is needed in a way it can understand more clearly.

Summary

#278 and #280 asked whether the round-trip classifier's drop:voice / drop:staff /
drop:direction / drop:direction-type signatures (co-occurring on ~60 corpus files) are a genuine
impl bug or an audit-correction. Investigated with make dump-api-roundtrip +
make classify-api-roundtrip and by diffing individual dumped files; this is neither -- it's one
already-understood, already-correctly-audited gap wearing four signatures:

  • DirectionReader dispatches every direction-type choice, but eleven of them (harp-pedals,
    damp, damp-all, eyeglasses, string-mute, scordatura, image, principal-voice,
    accordion-registration, percussion, other-direction) are no-op stubs. A <direction>
    containing only one of these produces an empty DirectionData, which is correctly left
    unwritten -- MusicXML requires at least one direction-type child, so there is no schema-valid
    way to keep the <direction> (and its <voice>/<staff>) without modeling what it actually
    says. data/api.features.xml already correctly audits each of these subtypes as
    support="none" (only the parent direction/direction-type container, which does work, is
    full) -- so there's no audit to correct either.
  • The remaining <voice>/<staff> drops are <forward>/<backup>'s own optional children, which
    mx::api does not read: forward/backup are pure wire cursor mechanics with no api representation
    (the writer regenerates whatever the tick math requires), so there's nothing to carry a source's
    forward/backup voice/staff value from.
  • Also found the same shape of gap in DirectionReader::parsePedal: sostenuto/change/
    continue/discontinue/resume are unmodeled, only start/stop (lysuite/ly33a_Spanners.xml).

No code behavior changes -- this adds comments at each stub/gap pointing at the finding (and #324,
opened to track actually implementing this worklist) so it doesn't get re-investigated from
scratch.

Testing

  • make test: all pass (4724 assertions in 378 test cases, plus the three examples) --
    comments only, no behavior change
  • make fmt / make check: clean

References

Investigated why round-trip discovery reports drop:voice / drop:staff /
drop:direction / drop:direction-type together on ~60 corpus files.

DirectionReader already dispatches every direction-type choice, but eleven
of them (harp-pedals, damp, damp-all, eyeglasses, string-mute, scordatura,
image, principal-voice, accordion-registration, percussion, other-direction)
are no-op stubs. When a <direction> contains only one of these, the
resulting DirectionData carries no content and is correctly left unwritten
-- MusicXML requires at least one direction-type child, so there is no
schema-valid way to keep the <direction> (and its <voice>/<staff>) without
modeling what it actually says. This is one gap (unmodeled content), not
four; data/api.features.xml already correctly audits each of these
subtypes as support="none" (only the parent direction/direction-type
container, which does work, is full).

The remaining <voice>/<staff> drops trace to <forward>/<backup>'s own
optional voice/staff children, which mx::api does not read: forward/backup
are pure wire cursor mechanics with no api representation (the writer
regenerates whatever the tick math requires), so there is nothing to carry
a source's forward/backup voice/staff value from.

Also documented the same shape of gap in DirectionReader::parsePedal:
sostenuto/change/continue/discontinue/resume are unmodeled, only
start/stop.

Filed #324 to track implementing the unmodeled direction-type subtypes
and pedal states; no code behavior changes here, just comments pointing at
the finding so it isn't re-investigated from scratch.

Closes #278
Closes #280
@webern webern added bug software defect non-breaking fixes or implementation that do not require breaking changes api Affects the mx::api layer impl Affects the mx::impl layer ai Issues opened by, or through, a coding agent. labels Jul 7, 2026 — with Claude
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

Coverage report

Core-dev coverage src/private/mx/core/

Metric Coverage Covered / Total
Lines 77.8% 28513 / 36640
Functions 74.3% 6352 / 8551
Branches 50.7% 22678 / 44751

API coverage src/private/mx/{api,impl,utility}/

Metric Coverage Covered / Total
Lines 80.8% 6391 / 7913
Functions 67.7% 2217 / 3275
Branches 49.5% 5476 / 11052

Core HTML report | API HTML report

Commit c27714bde8571269365216540fa9a435b9cb517a.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

gen-quality gen/

gen-quality: 84.5 / 100   (floor 84.5, +0.0)

  structure     86.5  x0.50   [fn 90.5 / file 82.6]
  cyclomatic    88.4  x0.25
  cognitive     76.6  x0.25

  409 functions across 31 files, 7702 lines (largest file 1044)
  max cc 56  max cognitive 44  max fn loc 152

Worst offenders (top 5 per axis; full lists in score.json):
  cyclomatic gen/xsd/analyze.py:311     report                             56
  cyclomatic gen/plates/build.py:956    _validate_config_against_ir        35
  cyclomatic gen/press/context.py:145   plate_context                      34
  cyclomatic gen/__main__.py:46         _ir                                23
  cyclomatic gen/tests/test_ir.py:102   _check_references                  20
  cognitive  gen/xsd/analyze.py:311     report                             44
  cognitive  gen/ir/resolve.py:119      flat_elements                      40
  cognitive  gen/tests/test_ir.py:102   _check_references                  38
  cognitive  gen/press/context.py:145   plate_context                      37
  cognitive  gen/xsd/analyze.py:207     _sccs                              37
  size       gen/xsd/analyze.py:311     report                             152
  size       gen/press/context.py:145   plate_context                      96
  size       gen/plates/build.py:533    _value_plate                       89
  size       gen/plates/build.py:956    _validate_config_against_ir        89
  size       gen/ir/resolve.py:119      flat_elements                      78

Commit c27714bde8571269365216540fa9a435b9cb517a.

@webern
webern merged commit 102bbbb into main Jul 7, 2026
10 checks passed
@webern
webern deleted the clarify-direction-drops branch July 7, 2026 09:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai Issues opened by, or through, a coding agent. api Affects the mx::api layer bug software defect impl Affects the mx::impl layer non-breaking fixes or implementation that do not require breaking changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

api: round-trip drops direction api: round-trip drops voice

1 participant