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
Remove ImportDialog and all manual credential management. The browser
handles 401 challenges natively for same-origin fetch requests — it
shows its own credential prompt, retries, and caches the result for
the session. No JS-level auth code is needed.
- api.js: remove authHeader() and all credentials parameters
- store.js: remove credentials field
- ImportDialog.js: deleted
- AppShell.js: remove showImport/openImport/onMounted dialog machinery;
pass importOnLoad through to PaneCP
- PaneCP.js: inline doImport() (was in ImportDialog); auto-triggers on
mount when importOnLoad is true; shows inline import error on failure
- StatusPoller.js: remove credentials arg from fetchStatus()
- style.css: remove .se-import-dialog and .se-overlay blocks
- patchScore() now accepts articles[] and returns { text, log } instead
of a plain string. Dirty articles are re-serialized into the articles:
block (block style, replacing any existing flow-style entries). Clean
articles bypass the patcher entirely.
- article.isDirty is set on direct property edits so the exporter can
distinguish directly changed entities from propagated dirty state.
- patchScore() log collects { level:'changed', path } for each patched
article/instrument/bar, and a { level:'info', message } entry for the
count of bar documents passed through unchanged.
- CP pane shows the export log above the status poller after each export.
- Article scope toggle replaced with Bootstrap form-check form-switch;
hand-rolled .se-toggle CSS removed.
- Test suite updated for { text, log } return; 11 new assertions (188 total).
Article entries in the CP path list now show the article label
(letter/extension) instead of just "article", with a property count
in the meta column. In the FO pane, each property is rendered as an
editable row: key input, value input (coerced via ast-parser.coerce),
scope toggle, morphing default/overwrite label, and per-row remove
button. A "+ add property" button appends a blank defaults entry.
Every edit marks the score dirty.
`coerce` is now exported from ast-parser.js so the FO pane can apply
the same type-inference rules to user input as the parser does to
AST values.
- Use file_accomplished (not frozen+!error) to gate audio player
- Use errors field (was .error — wrong name, always falsy)
- Render <audio controls> instead of bare download link
- Add audiowidget.tmpl.stub for server-side customization
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".
PaneCP: replace horizontal breadcrumb with vertical list of short views
for each node in the focus path (type tag + label/identifier). Clicking
any item above current navigates up.
PaneFO: show score info fields (title, composer, source, encrypter) as
editable DL when at score level instead of 'Nothing selected'.
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).