Skip to content

Move hasLyrics/hasVocals/hasForcedNotes from ParsedChart to ScannedChart (state-derived) - #67

Merged
elicwhite merged 1 commit into
masterfrom
derived-flags-to-scanned
Apr 21, 2026
Merged

Move hasLyrics/hasVocals/hasForcedNotes from ParsedChart to ScannedChart (state-derived)#67
elicwhite merged 1 commit into
masterfrom
derived-flags-to-scanned

Conversation

@elicwhite

Copy link
Copy Markdown
Owner

The three derived boolean flags on ParsedChart (hasLyrics, hasVocals,
hasForcedNotes) were parse-time snapshots that went stale whenever
consumers mutated chart data post-parse. Remove them from ParsedChart
entirely; scanChart derives all three at scan time from the current
chart state, piggybacking on its existing single note-walk (no extra
iterations).

  • hasLyrics / hasVocals: computed from parsedChart.vocalTracks.parts —
    constant-time existence check.

  • hasForcedNotes: inverts resolveFretModifiers. A note is 'forced' iff
    its resolved flag disagrees with the natural HOPO state the parser
    would pick without any force events, or it carries the tap flag
    (tap can only come from explicit forceTap). Inlined helpers for
    isNaturalHopo, isFretChord, isSameFretNote, isInFretNote,
    computeHopoThresholdTicks in chart-scanner.ts (duplicated from
    notes-parser.ts; a follow-up can extract to a shared helper).

Semantic change to note: under the new definition, redundantly-applied
force events (e.g. explicit forceHopo on a naturally-HOPO note) no
longer contribute to hasForcedNotes — the chart plays identically with
or without them, so state-derived detection correctly says false. This
eliminates the need for any 'hasForcedNotes backstop' in writers since
the flag round-trips naturally: the writer emits force events exactly
when a flag disagrees with natural state, and the scanner detects
those same disagreements on re-parse.

ScannedChart.notesData's shape is unchanged (hasLyrics / hasVocals /
hasForcedNotes still present); only the population source changes.

Consumers that previously read parsedChart.hasLyrics /
parsedChart.hasVocals / parsedChart.hasForcedNotes must switch to
scanChart output.

@elicwhite
elicwhite changed the base branch from metadata-consolidation to graphite-base/67 April 20, 2026 04:16
@elicwhite
elicwhite force-pushed the derived-flags-to-scanned branch from e103858 to 5f09fa9 Compare April 20, 2026 04:16
@elicwhite
elicwhite marked this pull request as ready for review April 20, 2026 04:16
@graphite-app
graphite-app Bot changed the base branch from graphite-base/67 to master April 20, 2026 04:16
@elicwhite
elicwhite force-pushed the derived-flags-to-scanned branch 3 times, most recently from 72171f8 to a876247 Compare April 20, 2026 04:45
…art (state-derived)

The three derived boolean flags on ParsedChart (hasLyrics, hasVocals,
hasForcedNotes) were parse-time snapshots that went stale whenever
consumers mutated chart data post-parse. Remove them from ParsedChart
entirely; scanChart derives all three at scan time from the current
chart state, piggybacking on its existing single note-walk (no extra
iterations).

- hasLyrics / hasVocals: computed from parsedChart.vocalTracks.parts —
  constant-time existence check.

- hasForcedNotes: inverts resolveFretModifiers. A note is 'forced' iff
  its resolved flag disagrees with the natural HOPO state the parser
  would pick without any force events, or it carries the tap flag
  (tap can only come from explicit forceTap). Inlined helpers for
  isNaturalHopo, isFretChord, isSameFretNote, isInFretNote,
  computeHopoThresholdTicks in chart-scanner.ts (duplicated from
  notes-parser.ts; a follow-up can extract to a shared helper).

Semantic change to note: under the new definition, redundantly-applied
force events (e.g. explicit forceHopo on a naturally-HOPO note) no
longer contribute to hasForcedNotes — the chart plays identically with
or without them, so state-derived detection correctly says false. This
eliminates the need for any 'hasForcedNotes backstop' in writers since
the flag round-trips naturally: the writer emits force events exactly
when a flag disagrees with natural state, and the scanner detects
those same disagreements on re-parse.

ScannedChart.notesData's shape is unchanged (hasLyrics / hasVocals /
hasForcedNotes still present); only the population source changes.

Consumers that previously read parsedChart.hasLyrics /
parsedChart.hasVocals / parsedChart.hasForcedNotes must switch to
scanChart output.
@elicwhite
elicwhite force-pushed the derived-flags-to-scanned branch from a876247 to 7be766d Compare April 21, 2026 04:29
@elicwhite
elicwhite merged commit 0efb1b3 into master Apr 21, 2026
@elicwhite
elicwhite deleted the derived-flags-to-scanned branch April 21, 2026 04:55
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.

1 participant