Skip to content

fix: suppress spurious implied-default element injection in api round-trip (#228)#241

Merged
webern merged 4 commits into
mainfrom
claude/focused-cori-voxmb0
Jun 26, 2026
Merged

fix: suppress spurious implied-default element injection in api round-trip (#228)#241
webern merged 4 commits into
mainfrom
claude/focused-cori-voxmb0

Conversation

@webern

@webern webern commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Summary

Three commits, one per element family from #228.

add:typeDurationData::isDurationNameSpecified

The writer was always emitting <type> even when the source note had none. Added bool isDurationNameSpecified (default true) to DurationData. The reader sets it false when the source lacks <type>; the writer skips the element when false. durationName is still derived from tick length on read so consumers always have something to work with — the flag only controls write-side emission.

add:lineClefData::isLineSpecified

MeasureReader::importClef was fabricating a default line number from the clef symbol when <line> was absent. Added bool isLineSpecified (default true) to ClefData. The reader sets it false in the else-branch; PropertiesWriter::writeClef now gates <line> emission on the flag instead of >= 0.

add:voiceNoteWriter::setStaffAndVoice

The writer was unconditionally emitting <voice> whenever myCursor.voiceIndex >= 0, which is always true. The fix honors the existing TODO comment ("only show voice number if it is needed") by tracking voice count per staff (numVoices, passed from MeasureWriter::writeVoices). Voice is now emitted when any of these is true:

  • the source note had an explicit <voice> (userRequestedVoiceNumber != -1), or
  • the note is in a non-default voice group (voiceIndex > 0), or
  • the staff has multiple voices (numVoices > 1) — labels all voices unambiguously for authored multi-voice scores.

Testing

  • 4 corpus files newly pass for add:type: ly41d, ly41f, ly45d, ly45e
  • 1 corpus file newly passes for add:line: ly12a
  • 3 corpus files newly pass for add:voice: ChordDirectionPlacement, hello_timewise, key-accidental.3.0
  • Pinned round-trip baseline: 46 pass, 0 fail (was 42)
  • Full test suite: 4268 assertions in 307 test cases, all pass

References

webern added 3 commits June 25, 2026 06:17
Add DurationData::isDurationNameSpecified (default true). The reader sets
it false when the source note omits <type>; the writer emits <type> only
when the flag is set. The existing derive-on-read (for consumer convenience)
is preserved -- callers still get a durationName even when the source had
none -- but it is no longer re-emitted on the write path.

Pin 4 newly passing corpus files.
@github-actions

Copy link
Copy Markdown

gen-quality gen/

(no report produced)

Commit df88775049018e283ec5e8bbbc6a191c31ffcddb.

@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 e826966bebc917ac65c04c83fae65dea5bffaf28.

@github-actions

Copy link
Copy Markdown

Coverage report

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

Metric Coverage Covered / Total
Lines 77.8% 28487 / 36624
Functions 74.3% 6349 / 8550
Branches 50.6% 22632 / 44725

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

Metric Coverage Covered / Total
Lines 78.2% 5887 / 7529
Functions 62.1% 1962 / 3159
Branches 47.6% 4965 / 10441

Core HTML report | API HTML report

Commit e826966bebc917ac65c04c83fae65dea5bffaf28.

@webern webern merged commit adca48f into main Jun 26, 2026
7 checks passed
@webern webern deleted the claude/focused-cori-voxmb0 branch June 26, 2026 05:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

api: round-trip injects implied default elements: <type> <line> <voice> <staff>

1 participant