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
Bars in the BA sub-objects pane are now visually grouped by the
P\d+L\d+ fragment extracted from their opaque IDs (e.g. P1L1, P2L3).
Each group renders as a row of compact inline-block chips; groups are
separated by a line break. Fallback: if an ID contains no P?L?
pattern, trailing digits are stripped instead, yielding singleton rows.
The grouping is a display-only heuristic — no semantic meaning is
derived from the ID. Chips are clickable, highlight when focused.
The bottom handle bar is now dynamic. Fixed CP + FO handles, then one
handle per kind of sub-object the focused node has. "Kind" is the SLOT
part of the AST's SLOT.SUBTYPE namespace: sub-objects sharing a SLOT
(e.g. `line.stem_note` + `line.motif`, or `articles.<subtypeA>` +
`articles.<subtypeB>`) collapse into one pane; different SLOTs split.
Score-level kinds emit, in this order: TU (tuning), ST (stage cone +
voices), IN (instruments — linked ones listed read-only), AR (articles),
BA (bars). info metadata is folded into the FO pane (was previously
listed as a sub-object).
Handles are 2-letter labels for now, intended as alt-text for icons in
a later release.
- `subobject-kinds.js` new: `getKindGroups(node)` returns ordered
`[{ kind, items }]`; `KIND_LABEL` maps kind -> 2-letter label.
- `PaneSubObjects.js` now parameterized by `kind` prop; renders one group.
- `AppShell.js` builds the handle bar from `getKindGroups(focusedNode)`;
drops back to FO when the active sub-pane disappears after a focus change.
- `ObjectShort.js` accepts a `readOnly` flag (used for linked instruments).
Numeric dependsOn values (merge-type variations) are RFC edge values,
not ATTR names. Display them as the number, not as "ATTR: N" or
"subvariation N".
AppShell already wraps each component in div.se-pane; the inner se-pane
had display:none without .active, hiding all content.
Also drop stale movement/part/line/measure bar fields (bar IDs are opaque).