Skip to content

api: segno and coda suport#203

Merged
webern merged 1 commit into
mainfrom
coda-segno
Jun 17, 2026
Merged

api: segno and coda suport#203
webern merged 1 commit into
mainfrom
coda-segno

Conversation

@webern

@webern webern commented Jun 17, 2026

Copy link
Copy Markdown
Owner

Summary

mx::api exposed SegnoData/CodaData but support was partial: the reader only captured position
and color (and even then never set isColorSpecified, so color was dropped), and the writer emitted
nothing for segno or coda, silently losing them on write.

This widens both data classes to the full <segno>/<coda> attribute surface and makes the trip
lossless in both directions:

  • Added fontData, smufl (+ isSmuflSpecified), and id (+ isIdSpecified) to SegnoData and
    CodaData. Position and halign/valign already ride along in positionData.
  • DirectionReader::parseSegno/parseCoda now read font, smufl, id, and set isColorSpecified.
  • DirectionWriter now writes segno and coda (position, font, color, smufl, id), replacing the
    lossy MX_UNUSED stub proposed in the superseded PR.

Note: positionData carries a placement member that does not apply to <segno>/<coda>
(placement lives on the parent <direction>). The read/write helpers are attribute-tolerant
(if constexpr (requires ...)), so this is inert, not a data bug. Documented in the headers.

Testing

  • New impl round-trip test segnoAndCodaRoundTrip_DirectionWriter: builds a segno and a coda
    with every field set, writes via DirectionWriter, reads back via DirectionReader, asserts
    equality. Passes (8 assertions in 2 test cases with the existing ottava test).
  • make dev builds clean; make fmt applied.
  • Full make test deferred to CI.

TODO (planned, not done in this PR)

References

Widen mx::api SegnoData and CodaData to carry font, smufl, and
id in addition to position and color, and add the writer path
so segno and coda now survive an api round-trip.

The reader set colorData but never isColorSpecified, so color
was dropped; the writer emitted nothing for segno or coda.
@webern webern added feature new feature request non-breaking fixes or implementation that do not require breaking changes area/mx::api area/mx::impl ai Issues opened by, or through, a coding agent. labels Jun 17, 2026
@github-actions

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 711beff9b90591806b14f870563027242bf34185.

@github-actions

Copy link
Copy Markdown

Coverage report

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

Metric Coverage Covered / Total
Lines 77.9% 28539 / 36620
Functions 74.4% 6360 / 8548
Branches 50.7% 22672 / 44725

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

Metric Coverage Covered / Total
Lines 71.4% 5181 / 7260
Functions 59.9% 1815 / 3029
Branches 42.5% 4322 / 10169

Core HTML report | API HTML report

Commit 711beff9b90591806b14f870563027242bf34185.

@webern webern changed the title feat: full-fidelity segno and coda read/write api: segno and coda suport Jun 17, 2026
@webern webern merged commit 9802fd3 into main Jun 17, 2026
7 checks passed
@webern webern deleted the coda-segno branch June 17, 2026 15:09
webern added a commit that referenced this pull request Jun 20, 2026
Fixes #205 and closes #134.

`DirectionWriter` was missing a write path for `RehearsalData`, causing
rehearsal marks to be silently dropped on output. Add a loop over
`directionData.rehearsals` that emits `<rehearsal>` elements, mirroring
the segno/coda pattern from PR #203.

While wiring up the round-trip test, also fix two gaps in
`DirectionReader::parseRehearsal`: it was not reading `fontData` (calling
`getFontData`) and was not setting `isColorSpecified` before copying color
attributes, so those fields were always lost on the read path.

Tests added:
- `rehearsalRoundTrip` in `DirectionWriterTest.cpp`: api → core → api
  round-trip at the impl layer, covering text, position, font, color,
  and enclosure.
- `RehearsalSyntheticFileRead` in `DirectionDataTest.cpp`: loads
  `data/synthetic/rehearsal.3.1.xml` and asserts the read path surfaces
  text and enclosure.
- `RehearsalRoundTripXml` in `DirectionDataTest.cpp`: full MusicXML
  serialization/deserialization round-trip via `mxtest::roundTrip`
  covering text, enclosure, and font weight.
webern added a commit that referenced this pull request Jun 20, 2026
## Summary

`DirectionWriter` had no write path for `RehearsalData`, so rehearsal
marks were silently dropped whenever a score was serialized. This adds a
loop over `directionData.rehearsals` that emits `<rehearsal>` elements,
mirroring the segno/coda pattern from #203.

While wiring up the round-trip test, two gaps in
`DirectionReader::parseRehearsal` were also found and fixed: it was not
calling `getFontData`, and it was not setting `isColorSpecified` before
copying color attributes, so both fields were always lost on the read
path. The `isColorSpecified` gap is the same bug class described in #207
(which covers the same pattern in `parseWords` — left for a separate
PR).

A post-review fix also adds `RehearsalEnclosure::unspecified` as the new
default for `RehearsalData::enclosure`. Previously the default was
`rectangle`, so any rehearsal with no `enclosure` attribute in the
source XML would silently gain `enclosure="rectangle"` on write-back.

## Changes

- `RehearsalData.h` — added `RehearsalEnclosure::unspecified`; changed
`RehearsalData` default enclosure from `rectangle` to `unspecified`.
- `DirectionWriter::getDirectionLikeThings` — new loop over `rehearsals`
emitting `<rehearsal>` with text, position, font, color, and enclosure
(skipped when `unspecified`).
- `DirectionReader::parseRehearsal` — now reads `fontData` via
`getFontData` and correctly gates `colorData` behind `isColorSpecified`.

## Testing

- `rehearsalRoundTrip` (`DirectionWriterTest.cpp`) — api → core → api at
the impl layer; covers text, position, font, color, and enclosure
shapes. Red before the fix, green after.
- `RehearsalSyntheticFileRead` (`DirectionDataTest.cpp`) — loads
`data/synthetic/rehearsal.3.1.xml` and asserts the read path surfaces
text and enclosure. Pins the core → api direction.
- `RehearsalRoundTripXml` (`DirectionDataTest.cpp`) — full MusicXML
serialization/deserialization round-trip; covers text, enclosure, and
font weight.
- `RehearsalUnspecifiedEnclosureNoPhantomAttribute`
(`DirectionDataTest.cpp`) — asserts that `enclosure="rectangle"` does
not appear in serialized XML when enclosure is unspecified, and that the
field round-trips as `unspecified`.
- Full suite: 4101 assertions in 269 test cases, all pass.
- `make test-api-roundtrip` baseline (1 pinned file): still passes.
- `make check` (fmt-check): passes.

## References

- Closes #205
- Closes #134
- Partially addresses #207 (fixes the `parseRehearsal`
`isColorSpecified` gap; the `parseWords` half of #207 is left for a
separate PR)
- Related to #203 (segno/coda writer; rehearsal was scoped out of that
PR)
webern added a commit that referenced this pull request Jun 23, 2026
Closes #204.

PR #203 added segno/coda support with impl-layer round-trip tests but
deferred api-level coverage. This adds it through the public
`DocumentManager` path, in two commits.

## Commit 1 — file-walking load coverage
Registers the audit fixtures `segno.{3.0,3.1}.xml` and
`coda.{3.0,3.1}.xml` (under `data/synthetic/`) in
`MxFileRepository::initializeNameSubdirectoryMap()` so the api
file-walking suite (`ApiLoadSurvivalTest`) exercises the public read
path (`createFromFile -> getData`) over them. The 3.1 variants
additionally carry `id` and `smufl`; all four load and yield a part.

## Commit 2 — strict read→write→read gate
The synthetic probes cannot serve a strict DOM-equal gate: I dumped
expected-vs-actual and confirmed the `<segno>`/`<coda>` elements
round-trip byte-identically, but the probes also carry editorial
`part-group`/`direction` children (`footnote`/`level`/`voice`) the api
omits and have no notes (so the api synthesizes `<divisions>`) —
divergences unrelated to segno/coda. The value-only `Fixer` can't patch
structural diffs, and the existing real-world files (`testDalSegno.xml`,
`testDCalCoda.xml`) fail on an unrelated `encoding-date` ordering issue.

So this adds two dedicated minimal fixtures that isolate the segno/coda
surface (3.0 base attributes; 3.1 adds `id` + `smufl`) in a score that
round-trips losslessly:

- `data/custom/segno_coda_roundtrip.3.0.xml`
- `data/custom/segno_coda_roundtrip.3.1.xml`

They are pinned in `roundtrip-baseline.txt` so the `test-api-roundtrip`
CI gate enforces strict `createFromFile -> getData -> createFromScore ->
writeToStream` DOM-equality for segno and coda, registered in
`MxFileRepository`, and carry their audit `*.features.xml` sidecars.

## Testing
- `test-api-roundtrip` regression gate: **34 passed, 0 failed** (incl.
both new fixtures).
- Full `mxtest`: **4268 assertions in 307 test cases, all pass**.
- `clang-format --dry-run --Werror` clean; audit sidecars generated via
`python3 -m audit files` (no `corpus.xml` churn).

## References
- Closes #204
- Follows #203 (segno/coda support)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---
_Generated by [Claude
Code](https://claude.ai/code/session_0163ZKdf1FtkiVkpXG2K9C1s)_
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. area/mx::api area/mx::impl feature new feature request non-breaking fixes or implementation that do not require breaking changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement segno reading

1 participant