Skip to content

Validator Rule Reference ​

This page is the flat index of all 60 validator rules. Use the Counterpoint Course to learn the musical ideas; use this page when you see a rule ID in an error, log, or event-debugging session and need to jump straight to its explanation.

How to read a rule ID

A rule ID names a specific musical contract that failed in the current validation pass. The same passage may violate several contracts at once. The validator accumulates those failures instead of stopping at the first one, and reports each with the span it blames.

Rule layers ​

The validator protects different layers of the composition. A local note rule and a form identity rule are both failures, but they need different context to understand.

The layers the validator protectsNine rule layers drawn as bars, ordered by how much of the score a rule in that layer has to look at. The shortest need two voices at one beat or two notes in one voice; the longest need the whole form layout and the provenance record of every authored span. Below, the three FailKind values a failure can carry: MusicalFail, StructuralFail and ConfigFail.rule layerhow much of the score the rule has to seethe context a failure needsLocal vertical soundtwo voices at one beatMelodic plausibilitythe previous and current note in one voiceVoice independencetwo voices across two points in timePhysical boundsthe voice range and the instrument compassPhrase structurephrase metadata and the meterTonal syntaxthe harmonic plan and the phrase positionFugal structurethe declared material and its entry spansForm identitymaterial carriers and the whole form layoutDeclaration integrityprovenance records and every authored spanevery failure also carries a FailKindMusicalFaila counterpoint or harmony contract — the defaultStructuralFailthe form's structural promise was brokenConfigFailan invalid request, reported before composingReading a rule ID starts with its layer: a local note rule and a form identity rule are both failures, but they need different evidence to explain.
LayerWhat it protectsTypical context needed
Local vertical soundStable intervals and chord membershipTwo voices at one beat
Melodic plausibilityNatural movement inside one voicePrevious and current notes in one voice
Voice independenceSeparate readable linesTwo voices across two time points
Tonal syntaxCadences, applied dominants, modulationHarmonic plan and phrase position
Fugal structureSubject, answer, countersubject, imitationDeclared material and entry spans
Phrase structureBar-grid consistencyPhrase metadata and meter
Form identityFixed grounds, cantus firmus, figuration rolesMaterial carriers and form layout
Physical boundsPlayable range and instrument compassVoice range, pedal range, instrument profile
Declaration integrityEmitted notes match what the form declaredProvenance records and authored spans

Every failure also carries a FailKind: MusicalFail (counterpoint/harmony contract, the default), StructuralFail (the form's structural promise — immutable carriers and malformed cadence layouts), or ConfigFail (invalid request, reported before composition).

Blocking failures vs informational findings

The final-score pass audits the emitted notes, authored material included. For findings handled by the counterpoint observation recorder, a final-score finding is informational when every operand has valid authored context: a Compose note counts as composer-authored, a Material note must still match its declaration, and an Ornament note must remain inside its declared carrier with its realization marker. Otherwise that recorder routes the finding to the blocking-failure list with an actionable span. During generation, the recorder counts a finding as exempted when every operand is an immutable Material or Ornament source; otherwise it gates the finding (a Compose operand therefore makes it gated). Direct checks such as voice crossing, suspension validation, cadence validation, and declaration-integrity validation append failures themselves and remain blocking regardless of authored context. A per-form budget then promotes any matched vertical rule that is closed for that form to one blocking MusicalFail with a null span. The current public generation path aborts on blocking failures; it does not repair the score or retry generation. getDiagnostic() reports the blocking failures, not informational findings.

Geometry, routing, and form budgets ​

The generated score records counterpoint matches before routing them to failures or informational evidence. geometry is linear for a succession inside one voice and vertical for a relation between sounding voices or between a voice and the harmonic plan. unclassified is reserved for a rule ID that has no geometry-table entry. total counts matches before routing; gated counts findings sent to the blocking-failure list; exempted counts generation-pass findings suppressed because every operand is an immutable Material or Ornament source. For findings handled by this recorder, a final-score finding whose authored context is valid is informational, so total - gated - exempted is the number represented as informational evidence. Standalone informational rules can have no observation tally.

Only vertical rules participate in the form budget. An entry in the budget table is still open for that form: the match remains measured in counterpoint_observations and does not itself stop generation. Source rows marked Unresolved record outstanding repair work; rows marked Accepted record a measured tradeoff or a form constraint. Both are open rows, and the gate uses row presence rather than the reason. A vertical rule absent from the form's table is closed; any positive observation total appends one blocking MusicalFail with span_id: null. Linear rules are outside this budget and are routed by the normal material or authored-context rules above. The source budget table is authoritative and defines the open (form, rule_id) pairs for all ten forms.

The budget table is a measured compatibility surface, not a claim that an open rule is musically desirable. Removing an entry closes that rule for the form; adding an entry reopens it.

Voice motion and independence ​

Rule IDCourse chapterHow to read it
parallel_fifth2. MotionBoth voices move in the same direction, and both the previous and current vertical intervals reduce to perfect fifths.
parallel_octave2. MotionBoth voices move in the same direction, and both the previous and current intervals reduce to a unison or octave.
anti_parallel_perfect2. MotionContrary motion leaves and enters the same perfect interval class: a perfect fifth or a unison/octave.
battuta2. MotionContrary motion arrives at a new unison/octave, with the upper line at the arrival leaping down by more than a whole tone.
hidden_parallel_fifth2. MotionSame-direction motion enters a perfect fifth from a different previous interval, and the conventionally upper line leaps more than a whole tone (>2 semitones).
hidden_parallel_octave2. MotionThe same hidden-perfect test enters a unison/octave. It is checked at shared sounding ticks, not only in an upper pair or on a strong beat.
voice_crossing2. MotionThe conventionally upper, lower-indexed voice sounds below the higher-indexed lower voice. Trio Sonata may allow a momentary exchange between its two upper voices, but sustained crossing still fails and their overall registers must overlap.
spacing_adjacent_voices_within_octave2. MotionAdjacent upper voices are spaced more than an octave apart in a 3+ voice texture.
invertible_at_octave2. MotionAn adjacent upper-voice pair creates parallel octaves on a structural accent, which would invert to parallel unisons; the bottom pair is excluded.

When the current lower-part note in a sounding pair carries the CadenceCellCommitted provenance bit, the validator skips parallel_fifth, parallel_octave, hidden_parallel_fifth, hidden_parallel_octave, anti_parallel_perfect, and battuta for that tick. This cadence-cell exemption does not blanket-exempt voice crossing, spacing, or other checks.

Dissonance treatment ​

Rule IDCourse chapterHow to read it
strong_beat_dissonance3. DissonanceA note on a structural accent is outside the active chord tones. A declared chordal seventh counts as a chord tone.
vertical_dissonance3. DissonanceSimultaneous voices form an unsupported dissonant interval on a strong beat.
unprepared_dissonance3. DissonanceA non-triad tone on a weak beat is not approached and left by step (at most two semitones).
suspension_preparation3. DissonanceA suspension's preparation is not consonant against the lowest sounding partner.
suspension_preparation_duration3. DissonanceThe preparation is shorter than the suspension it prepares.
suspension_metrical_accent3. DissonanceThe suspension does not land on a stronger beat than its preparation.
suspension_resolution_step_down3. DissonanceA suspension fails to resolve by step in its prescribed direction (down for 4-3/7-6/9-8; the engine's Sus2_3 is upward). Historical lower-voice 2-3 suspensions are commonly described with downward resolution; see Open Music Theory.
suspension_interval3. DissonanceThe intervals between the suspended voice and the lowest sounding other voice do not match the declared type (4-3, 7-6, 9-8, 2-3); for 2-3, the suspended voice is the bass and the interval is measured upward from it.
suspension_seventh_sixth3. DissonanceA declared 7-6 suspension does not form a genuine seventh resolving to a genuine sixth over the bass.

Melodic rules ​

Rule IDCourse chapterHow to read it
augmented_melodic4. MelodyA voice moves by an augmented melodic interval (exempt in secondary-dominant regions).
diminished_melodic4. MelodyA voice moves by a diminished melodic interval (same exemption).
tritone_melodic4. MelodyA voice leaps a tritone (same exemption).
consecutive_leaps4. MelodyTwo consecutive large leaps (a fifth or more each, in any direction).
leading_tone_resolution4. MelodyA marked leading tone does not step up to the tonic.
voice_range_integrity4. MelodyA note falls outside its voice's declared MIDI range.

Tonal syntax ​

Rule IDCourse chapterHow to read it
cadence_voice_leading5. TonalityThe cadential voices do not match the declared cadence type (perfect, imperfect authentic, plagal, half, deceptive, Phrygian, Picardy). StructuralFail only when no voice reaches the cadence or the cadence is declared before the first beat; a one-voice form is checked as a melodic cadence. The voice-leading mismatch itself is MusicalFail.
doubling_no_leading_tone5. TonalityThe leading tone is doubled in a chord that contains it.
doubling_no_seventh5. TonalityA chordal seventh is doubled.
cross_relation5. TonalityVoices sound the same scale degree in the local key at the later onset with different inflections, either simultaneously or at adjacent note onsets with no intervening onset in either voice. Natural semitone pairs between different degrees are excluded.
secondary_dominant_resolution5. TonalityAn applied dominant is not followed by its target degree.
modulation_pivot_chord_required5. TonalityA pivot modulation's pivot chord is not diatonic in both keys.

Fugal structure ​

Rule IDCourse chapterHow to read it
tonal_answer_dominant_mapping6. FugueA tonal answer's head does not map the subject's opening pitch class I↔V.
countersubject_continuous6. FugueThe countersubject falls silent during the answer's window.
episode_motif_derived6. FugueEpisode notes do not equal the declared motif transform of the declared source slice.
sequence_pattern_consistency6. FugueA sequence step is not an exact transposition of the seed by the declared offset.
imitation_entry_match6. FugueA follower entry misses the declared time distance or interval from the leader.
imitation_entry_realization6. FugueThe emitted notes do not actually realize the declared leader/follower entry in the carrier voices.
countersubject_invertible6. FugueA countersubject forms a perfect fifth against the subject on a strong beat, so the pair does not invert at the octave. Informational only — free-style countersubjects do this legitimately, so it never blocks a run.
middle_entry_in_related_key6. FugueA development entry is not in V/vi/IV/ii, or strays from that key's scale.
stretto_overlap_valid6. FugueStretto entries do not overlap, or the follower is not an exact transposition.
pedal_point_tonic_or_dominant6. FugueA pedal point sits on a degree other than tonic or dominant.

Phrase, texture, and physical bounds ​

Rule IDCourse chapterHow to read it
phrase_periodicity_4_or_8_bar7. FormDeclared phrase starts are not a whole number of bars from 3 through 8 apart. The stable rule ID retains its older 4-or-8 wording.
anacrusis_consistent7. FormUpbeat metadata and phrase-start metadata disagree.
pedal_range_soft_penalty7. FormAn organ pedal note leaves the playable compass (MIDI 12–62).
voice_independence_threshold7. FormTrio-sonata voices score below 0.6 pairwise independence.
trio_upper_register_overlap7. FormThe two trio-sonata upper voices never share a register, so they read as separate manuals rather than one exchanging pair.
section_contrast_required7. FormAdjacent fantasia sections do not contrast in density or register.

Form identity ​

Rule IDCourse chapterHow to read it
ground_bass_immutable7. FormA chaconne replay changes the canonical ground's bar-head pitch skeleton at the same cycle-relative position. Offbeat subdivisions are not compared. StructuralFail.
passacaglia_ground_immutable7. FormA passacaglia replay changes the 8-bar ground's bar-head pitch skeleton at the same cycle-relative position. Offbeat subdivisions are not compared. StructuralFail.
cantus_firmus_immutable7. FormA chorale-prelude downbeat does not restate the declared skeleton tone. StructuralFail.
goldberg_aria_bass_immutable7. FormA Goldberg variation block does not replay every declared aria-bass onset with the same cycle-relative onset, duration, and pitch. A terminal CodaCarrier tonic cadence may replace the final block window. StructuralFail.
variation_role_ornament_constraint7. FormA ground-role variation subdivides below quarter notes.
figuration_harmonic_consistency7. FormA figuration bar opens on a non-chord tone.
toccata_archetype_compatible7. FormThe toccata's sectional archetype conflicts with the declared character.
implicit_voice_counterpoint7. FormA solo-string arpeggio's implied bass/top streams break the melodic rules.
arpeggio_no_parallel_perfect7. FormImplied streams move in parallel perfect intervals across cells.

Declaration integrity ​

These checks use the emitted score and its declarations rather than a musical contract. The provenance checks run only in the final-score pass; declared_doubling_integrity also validates a declared doubling before the validator honors it. They are all StructuralFail: seeing one means the output does not match a declaration, so inspect the declaration and emitted notes before retrying.

Rule IDCourse chapterHow to read it
note_provenance_alignment--The note list and the provenance list have different lengths, so no note can be attributed.
carrier_declaration_integrity7. FormA note claiming an authored carrier does not match that carrier's declared start, duration, or pitch.
ornament_declaration_integrity7. FormThe same mismatch for an ornament note against the carrier it decorates.
ornament_group_integrity7. FormAn ornament expansion does not cover its authored carrier exactly: a gap, an overlap, or an ending on something other than the main tone.
declared_doubling_integrity7. FormA declared doubling must name two distinct voices and a valid, nonempty half-open window containing a lead note; inside it, the emitted note count, onsets, durations, and pitch transposition must match. StructuralFail.

Debugging checklist ​

  1. Identify the rule ID and its FailKind.
  2. Check whether the offending note is source: "material", "compose", or "ornament" in the event JSON.
  3. For local rules, inspect the previous and current note pair.
  4. For structural rules, inspect the declared form, material span, phrase span, or harmonic plan.
  5. If the rule is musical rather than API-level, read the linked course chapter.

Useful mental model

The form director declares what kind of musical object is being built. By default, material carriers replay every authored span; the scored branch is used only by opt-in free counterpoint. The validator reports every detected breach of the declared musical contract, and the public generation path aborts on blocking failures.

Dual-licensed: AGPL-3.0 · commercial licensing available. Generated MIDI is yours to use freely.