Phase 4 — remove edit-state flags from domain objects:
- ast-parser.js: drop isDirty from buildInstrument, buildBar, buildStemNote
- store.js: add resetEditState()
- PaneCP.js: use resetEditState() on import; drop flags arg from patchScore
- PaneFO.js: isDirty -> _modified for linked instruments; no per-node dirty tracking
- PaneSubObjects.js: _spliceNode helper; deletion via splice; _isNew on new bars
- exporter.js: on-demand traversal; absence from model means deleted
Phase 5 — article parser and exporter:
- ast-parser.js: _buildArticleEntry replaces _mergeArticleEntry; stage.article and
voice.article dispatch; article properties carry scope and overwritten flag
- exporter.js: _buildArticlesBlock emits -important: list for overwrites scope
Phase 6 — stem note dead fields:
- ast-parser.js: parse weight and articulatory on stem notes; flatten
article.definite properties onto stem note model sibling to pitch/chain