moonbit-counterpoint

    Explainable counterpoint rule engine for MoonBit

    music
    counterpoint
    rule-engine
    education
    composition
    Download zip
    Version
    0.3.2
    License
    Apache-2.0
    Last updated
    2 months ago
    Downloads
    44

    No dependencies

    #moonbit-counterpoint

    An explainable counterpoint analysis toolkit for MoonBit. It turns species counterpoint rules into typed findings that can be shown to a learner, consumed by a composition assistant, or exported by a command-line workflow.

    #Project positioning

    The library focuses on the analysis layer between a note sequence and a music editor. It does not attempt to replace MIDI playback or notation rendering. Its boundary is deliberately small: represent notes, validate timelines, analyze counterpoint, summarize findings, and produce machine-readable or human-readable reports.

    #Core capabilities

    • First through fifth species rhythm-shape checks.
    • Parallel and hidden perfect consonance checks.
    • Voice crossing and dissonance placement diagnostics.
    • Melodic span, leap, recovery, cadence, and suspension guidance.
    • Classroom, strict, Renaissance, and custom rule profiles.
    • Timeline validation for empty, overlapping, duplicate, non-monotonic, and excessively gapped input.
    • Pitch-class, register, voice-range, histogram, and transposition helpers.
    • Stable summaries with pass/review/fail grades and deterministic scores.
    • CSV and Markdown reports suitable for CLI output or editor integrations.
    • End-to-end pipeline output with quality gates, scorecards, practice plans, profile comparison, history tracking, and batch variant reports.
    • Dependency-free interchange helpers for note rows, TSV, manifests, and stable sequence fingerprints.

    #Quick start

    Install MoonBit stable, clone the repository, and run:

    moon check --target all moon test --target all moon run cmd/main

    Minimal library usage:

    ///|
    test {
    let cantus = [
    Note::new(midi=60, onset=0, duration=2, label="C"),
    Note::new(midi=62, onset=2, duration=2, label="D"),
    Note::new(midi=64, onset=4, duration=2, label="E"),
    Note::new(midi=65, onset=6, duration=2, label="F"),
    Note::new(midi=67, onset=8, duration=2, label="G"),
    ]
    let counter = [
    Note::new(midi=67, onset=0, duration=2, label="G"),
    Note::new(midi=65, onset=2, duration=2, label="F"),
    Note::new(midi=72, onset=4, duration=2, label="C"),
    Note::new(midi=81, onset=6, duration=2, label="A"),
    Note::new(midi=79, onset=8, duration=2, label="G"),
    ]
    let result = validate_pair(cantus, counter, RuleProfileConfig::classroom())
    inspect(result.passed(), content="true")
    }

    #CLI

    The example executable in cmd/main analyzes a small first-species exercise and prints the structured findings. It is intentionally dependency-free so it can serve as a smoke test for a fresh MoonBit installation.

    The library APIs can be composed into an application-specific CLI:

    • analyze_counterpoint returns the full typed report.
    • summarize returns counts, score, grade, and rule-family totals.
    • analysis_csv and analysis_markdown export reports.
    • sequence_report validates note timing before analysis.
    • validate_pair combines input validation, analysis, and profile metadata.

    #Architecture

    ModuleResponsibility
    types.mbtPublic note, rule, finding, species, and option types
    intervals.mbtMelodic/harmonic interval and motion primitives
    melody.mbtRange, leap, and recovery diagnostics
    harmony.mbtVertical sonority, parallels, hidden perfects, and cadence
    species.mbtSpecies rhythm and suspension-shape rules
    profiles.mbtReusable rule policy presets and classification helpers
    timeline.mbtSequence validation and note-time utilities
    pitch.mbt / voices.mbtPitch classes, registers, voice ranges, and alignment
    metrics.mbt / reports.mbtScores, summaries, CSV, and Markdown output
    workflow.mbtEnd-to-end pair validation facade
    rhythm.mbt / contour.mbt / statistics.mbtMeter, contour, distribution, and motion statistics
    candidates.mbt / phrase_planner.mbtBounded candidate generation and phrase planning
    phrase_windows.mbt / candidate_evidence.mbtLocal phrase partitioning and explainable candidate constraints
    analysis_triage.mbt / repair_suggestions.mbtRepair prioritization and bounded single-event edits
    harmony_tools.mbt / voice_leading.mbtSonority profiles and motion constraints
    rule_catalog.mbt / exercise_catalog.mbt / teaching.mbtExplainable rule and practice content
    pipeline.mbt / quality_gate.mbt / scorecards.mbtProduction analysis orchestration and quality gates
    interchange.mbt / report_sections.mbt / analysis_exports.mbtInterchange and composable report artifacts

    All public domain types are owned by the root package. The implementation is pure and deterministic, which keeps it suitable for teaching tools, snapshot tests, and future MIDI/MusicXML adapters.

    #Benchmarks

    The repository includes a reproducible benchmark record in benchmarks/RESULTS.md. It reports the measured MoonBit commands and a 1,000-note analysis workload. Re-run the commands from the repository root when comparing toolchain versions.

    #Testing

    The test suite contains rule examples, report checks, production API checks, and a boundary matrix. It exercises malformed timelines, extreme registers, zero and varied durations, duplicate onsets, transposition, scaling, pitch histograms, and voice-range calculations.

    moon fmt --check moon check --target all moon test --target all moon coverage report -f summary moon coverage analyze

    #CI

    GitHub Actions runs on Ubuntu, macOS, and Windows. It installs the current MoonBit stable toolchain, enforces the supported compiler floor, checks all targets, runs all tests, verifies formatting and generated interfaces, and publishes only through an explicit manual workflow.

    #License

    Apache-2.0. See LICENSE.

    Analysis

    pub(all) struct Analysis {
    species : Species
    findings : Array[Finding]
    } derive(Eq, ToJson,
    Debug
    )

    Analysis::is_clean

    fn Analysis::is_clean(self : Analysis) -> Bool

    AnalysisExport

    pub(all) struct AnalysisExport {
    title : String
    profile : String
    summary : AnalysisSummary
    findings : Array[String]
    recommendations : Array[String]
    fingerprint : String
    } derive(Eq, ToJson,
    Debug
    )

    AnalysisHistory

    pub(all) struct AnalysisHistory {
    snapshots : Array[AnalysisSnapshot]
    best_score : Int
    latest_score : Int
    improvement : Int
    } derive(Eq, ToJson,
    Debug
    )

    AnalysisOptions

    pub(all) struct AnalysisOptions {
    species : Species
    strict_cadence : Bool
    max_melody_span : Int
    max_leap : Int
    } derive(Eq, ToJson,
    Debug
    )

    AnalysisOptions::default

    fn AnalysisOptions::default(species~ : Species) -> AnalysisOptions

    AnalysisSnapshot

    pub(all) struct AnalysisSnapshot {
    label : String
    score : Int
    errors : Int
    warnings : Int
    notes : Int
    profile : String
    } derive(Eq, ToJson,
    Debug
    )

    AnalysisSummary

    pub(all) struct AnalysisSummary {
    total : Int
    errors : Int
    warnings : Int
    infos : Int
    structural : Int
    harmonic : Int
    score : Int
    } derive(Eq, ToJson,
    Debug
    )

    AnalysisSummary::grade

    fn AnalysisSummary::grade(self : AnalysisSummary) -> String

    AnalysisSummary::passed

    fn AnalysisSummary::passed(self : AnalysisSummary) -> Bool

    AnalysisSummary::severity_total

    fn AnalysisSummary::severity_total(self : AnalysisSummary) -> Int

    AnalysisTriage

    pub(all) struct AnalysisTriage {
    band : TriageBand
    items : Array[TriageItem]
    total_findings : Int
    repair_score : Int
    } derive(Eq, ToJson,
    Debug
    )

    BatchReport

    pub(all) struct BatchReport {
    labels : Array[String]
    summaries : Array[AnalysisSummary]
    best_index : Int
    best_score : Int
    } derive(Eq, ToJson,
    Debug
    )

    BeatPoint

    pub(all) struct BeatPoint {
    index : Int
    time : Int
    measure : Int
    beat : Int
    strength : BeatStrength
    } derive(Eq, ToJson,
    Debug
    )

    BeatStrength

    pub(all) enum BeatStrength {
    Downbeat
    Strong
    Weak
    Offbeat
    } derive(Eq, ToJson,
    Debug
    )

    CadencePlan

    pub(all) struct CadencePlan {
    penultimate : Int
    final_pitch : Int
    final_interval : Int
    approach : Direction
    valid : Bool
    message : String
    } derive(Eq, ToJson,
    Debug
    )

    CandidateBatch

    pub(all) struct CandidateBatch {
    source : Note
    candidates : Array[PitchCandidate]
    accepted : Int
    rejected : Int
    } derive(Eq, ToJson,
    Debug
    )

    CandidateConstraint

    pub(all) enum CandidateConstraint {
    Range
    Consonance
    Leap
    Motion
    } derive(Eq, ToJson,
    Debug
    )

    CandidateEvaluation

    pub(all) struct CandidateEvaluation {
    candidate : PitchCandidate
    constraints : Array[ConstraintEvidence]
    score : Int
    accepted : Bool
    } derive(Eq, ToJson,
    Debug
    )

    CandidatePolicy

    pub(all) struct CandidatePolicy {
    low : Int
    high : Int
    max_leap : Int
    require_consonance : Bool
    prefer_contrary : Bool
    avoid_repetition : Bool
    } derive(Eq, ToJson,
    Debug
    )

    CandidatePolicy::default

    CandidatePolicy::is_valid

    fn CandidatePolicy::is_valid(self : CandidatePolicy) -> Bool

    CandidatePolicy::strict

    ConsonanceClass

    pub(all) enum ConsonanceClass {
    Perfect
    Imperfect
    Dissonant
    } derive(Eq, ToJson,
    Debug
    )

    ConstraintEvidence

    pub(all) struct ConstraintEvidence {
    constraint : CandidateConstraint
    passed : Bool
    score : Int
    detail : String
    } derive(Eq, ToJson,
    Debug
    )

    ContourStep

    pub(all) enum ContourStep {
    Rising
    Falling
    Repeated
    LeapUp
    LeapDown
    } derive(Eq, ToJson,
    Debug
    )

    ContourSummary

    pub(all) struct ContourSummary {
    notes : Int
    rising : Int
    falling : Int
    repeated : Int
    leaps : Int
    turning_points : Int
    first_pitch : Int
    last_pitch : Int
    range : Int
    } derive(Eq, ToJson,
    Debug
    )

    Direction

    pub(all) enum Direction {
    Up
    Down
    Same
    } derive(Eq, ToJson,
    Debug
    )

    ExerciseSpec

    pub(all) struct ExerciseSpec {
    id : String
    rule : RuleKind
    species : Species
    title : String
    objective : String
    prompt : String
    target : String
    level : String
    notes : Int
    } derive(Eq, ToJson,
    Debug
    )

    Finding

    pub(all) struct Finding {
    rule : RuleKind
    severity : Severity
    index : Int
    message : String
    } derive(Eq, ToJson,
    Debug
    )

    Finding::error

    fn Finding::error(rule~ : RuleKind, index~ : Int, message~ : String) -> Finding

    Finding::warning

    fn Finding::warning(rule~ : RuleKind, index~ : Int, message~ : String) -> Finding

    GateStatus

    pub(all) enum GateStatus {
    Pass
    Review
    Fail
    } derive(Eq, ToJson,
    Debug
    )

    HarmonySummary

    pub(all) struct HarmonySummary {
    events : Int
    perfect : Int
    imperfect : Int
    dissonant : Int
    crossings : Int
    highest : Int
    lowest : Int
    } derive(Eq, ToJson,
    Debug
    )

    IntervalSize

    pub(all) enum IntervalSize {
    Unison
    Step
    Third
    Fourth
    Fifth
    Sixth
    Seventh
    Octave
    Compound
    } derive(Eq, ToJson,
    Debug
    )

    IntervalStatistics

    pub(all) struct IntervalStatistics {
    count : Int
    minimum : Int
    maximum : Int
    mean : Int
    steps : Int
    leaps : Int
    repeated : Int
    } derive(Eq, ToJson,
    Debug
    )

    LessonStage

    pub(all) enum LessonStage {
    Listen
    Identify
    Repair
    Compose
    Reflect
    } derive(Eq, ToJson,
    Debug
    )

    LessonStep

    pub(all) struct LessonStep {
    index : Int
    stage : LessonStage
    title : String
    prompt : String
    expected_rule : RuleKind?
    } derive(Eq, ToJson,
    Debug
    )

    Meter

    pub(all) struct Meter {
    numerator : Int
    denominator : Int
    subdivision : Int
    } derive(Eq, ToJson,
    Debug
    )

    Meter::beat_length

    fn Meter::beat_length(self : Meter) -> Int

    Meter::beats_per_measure

    fn Meter::beats_per_measure(self : Meter) -> Int

    Meter::is_valid

    fn Meter::is_valid(self : Meter) -> Bool

    Meter::measure_length

    fn Meter::measure_length(self : Meter) -> Int

    Meter::new

    fn Meter::new(numerator~ : Int, denominator~ : Int, subdivision? : Int) -> Meter

    MotionConstraint

    pub(all) struct MotionConstraint {
    name : String
    allow_parallel : Bool
    allow_similar : Bool
    allow_contrary : Bool
    allow_oblique : Bool
    max_leap : Int
    } derive(Eq, ToJson,
    Debug
    )

    MotionConstraint::allows

    fn MotionConstraint::allows(self : MotionConstraint, motion_value : MotionKind) -> Bool

    MotionConstraint::classroom

    MotionConstraint::strict

    MotionKind

    pub(all) enum MotionKind {
    Parallel
    Similar
    Contrary
    Oblique
    Static
    } derive(Eq, ToJson,
    Debug
    )

    MotionResult

    pub(all) struct MotionResult {
    motion : MotionKind
    accepted : Bool
    cost : Int
    message : String
    } derive(Eq, ToJson,
    Debug
    )

    Note

    pub(all) struct Note {
    midi : Int
    onset : Int
    duration : Int
    tied_from_previous : Bool
    label : String
    } derive(Eq, ToJson,
    Debug
    )

    Note::new

    fn Note::new(midi~ : Int, onset~ : Int, duration~ : Int, tied_from_previous? : Bool, label? : String) -> Note

    NoteRow

    pub(all) struct NoteRow {
    midi : Int
    onset : Int
    duration : Int
    tied : Bool
    label : String
    } derive(Eq, ToJson,
    Debug
    )

    NoteRow::from_note

    fn NoteRow::from_note(note : Note) -> NoteRow

    NoteRow::to_note

    fn NoteRow::to_note(self : NoteRow) -> Note

    PairStatistics

    pub(all) struct PairStatistics {
    aligned : Int
    contrary : Int
    parallel : Int
    similar : Int
    oblique : Int
    static_motion : Int
    average_vertical : Int
    } derive(Eq, ToJson,
    Debug
    )

    PairValidation

    pub(all) struct PairValidation {
    cantus : SequenceReport
    counterpoint : SequenceReport
    analysis : Analysis
    summary : AnalysisSummary
    profile : String
    } derive(Eq, ToJson,
    Debug
    )

    PairValidation::markdown

    fn PairValidation::markdown(self : PairValidation) -> String

    PairValidation::passed

    fn PairValidation::passed(self : PairValidation) -> Bool

    PairValidation::quality_score

    fn PairValidation::quality_score(self : PairValidation) -> Int

    PhrasePartition

    pub(all) struct PhrasePartition {
    windows : Array[PhraseWindow]
    total_notes : Int
    total_duration : Int
    window_duration : Int
    } derive(Eq, ToJson,
    Debug
    )

    PhrasePlan

    pub(all) struct PhrasePlan {
    segments : Array[PhraseSegment]
    cadence : CadencePlan
    total_notes : Int
    balanced : Bool
    } derive(Eq, ToJson,
    Debug
    )

    PhraseRole

    pub(all) enum PhraseRole {
    Opening
    Continuation
    Preparation
    Cadence
    Extension
    } derive(Eq, ToJson,
    Debug
    )

    PhraseRole::label

    fn PhraseRole::label(self : PhraseRole) -> String

    PhraseSegment

    pub(all) struct PhraseSegment {
    start : Int
    end : Int
    role : PhraseRole
    notes : Int
    pitch_range : Int
    density : Int
    } derive(Eq, ToJson,
    Debug
    )

    PhraseWindow

    pub(all) struct PhraseWindow {
    index : Int
    start_index : Int
    end_index : Int
    start_time : Int
    end_time : Int
    note_count : Int
    pitch_range : Int
    density : Int
    anchor_beat : String
    } derive(Eq, ToJson,
    Debug
    )

    PipelineInput

    pub(all) struct PipelineInput {
    cantus : Array[Note]
    counterpoint : Array[Note]
    meter : Meter
    profile : RuleProfileConfig
    } derive(Eq, ToJson,
    Debug
    )

    PipelineInput::new

    fn PipelineInput::new(cantus~ : Array[Note], counterpoint~ : Array[Note], meter~ : Meter, profile~ : RuleProfileConfig) -> PipelineInput

    PipelineOutput

    pub(all) struct PipelineOutput {
    validation : PairValidation
    rhythm : RhythmSummary
    contour : ContourSummary
    harmony : HarmonySummary
    motion : VoiceLeadingSummary
    report : ReportDocument
    recommendations : Array[Recommendation]
    } derive(Eq, ToJson,
    Debug
    )

    PitchCandidate

    pub(all) struct PitchCandidate {
    note : Note
    vertical_interval : Int
    melodic_interval : Int
    consonant : Bool
    motion : MotionKind
    score : Int
    } derive(Eq, ToJson,
    Debug
    )

    PitchClass

    pub(all) enum PitchClass {
    C
    Cs
    D
    Ds
    E
    F
    Fs
    G
    Gs
    A
    As
    B
    } derive(Eq, ToJson,
    Debug
    )

    PitchStatistics

    pub(all) struct PitchStatistics {
    count : Int
    minimum : Int
    maximum : Int
    mean : Int
    median : Int
    range : Int
    distinct : Int
    } derive(Eq, ToJson,
    Debug
    )

    PracticePlan

    pub(all) struct PracticePlan {
    title : String
    objective : String
    steps : Array[LessonStep]
    estimated_minutes : Int
    difficulty : String
    } derive(Eq, ToJson,
    Debug
    )

    PracticeResult

    pub(all) struct PracticeResult {
    completed : Int
    total : Int
    score : Int
    next_stage : LessonStage
    feedback : String
    } derive(Eq, ToJson,
    Debug
    )

    ProfileResult

    pub(all) struct ProfileResult {
    profile : String
    score : Int
    grade : String
    findings : Int
    passed : Bool
    } derive(Eq, ToJson,
    Debug
    )

    QualityGate

    pub(all) struct QualityGate {
    name : String
    status : GateStatus
    score : Int
    evidence : String
    action : String
    } derive(Eq, ToJson,
    Debug
    )

    QualityGateReport

    pub(all) struct QualityGateReport {
    status : GateStatus
    gates : Array[QualityGate]
    score : Int
    } derive(Eq, ToJson,
    Debug
    )

    Recommendation

    pub(all) struct Recommendation {
    code : String
    priority : Int
    title : String
    action : String
    evidence : String
    } derive(Eq, ToJson,
    Debug
    )

    RegisterBand

    pub(all) struct RegisterBand {
    low : Int
    high : Int
    count : Int
    percentage : Int
    } derive(Eq, ToJson,
    Debug
    )

    RepairKind

    pub(all) enum RepairKind {
    StepUp
    StepDown
    ReduceLeap
    MoveIntoRange
    PreserveCadence
    } derive(Eq, ToJson,
    Debug
    )

    RepairSuggestion

    pub(all) struct RepairSuggestion {
    index : Int
    kind : RepairKind
    replacement_midi : Int
    score : Int
    rationale : String
    } derive(Eq, ToJson,
    Debug
    )

    ReportDocument

    pub(all) struct ReportDocument {
    title : String
    sections : Array[ReportSection]
    format : String
    } derive(Eq, ToJson,
    Debug
    )

    ReportSection

    pub(all) struct ReportSection {
    id : String
    title : String
    body : String
    priority : Int
    } derive(Eq, ToJson,
    Debug
    )

    ReportSection::new

    fn ReportSection::new(id~ : String, title~ : String, body~ : String, priority~ : Int) -> ReportSection

    RhythmSummary

    pub(all) struct RhythmSummary {
    notes : Int
    measures : Int
    downbeats : Int
    offbeats : Int
    syncopations : Int
    tied_notes : Int
    total_duration : Int
    } derive(Eq, ToJson,
    Debug
    )

    RuleCard

    pub(all) struct RuleCard {
    code : String
    rule : RuleKind
    topic : String
    level : String
    title : String
    rationale : String
    remedy : String
    example : String
    } derive(Eq, ToJson,
    Debug
    )

    RuleKind

    pub(all) enum RuleKind {
    ParallelPerfect
    HiddenPerfect
    VoiceCrossing
    DissonancePlacement
    MelodyRange
    LargeLeap
    LeapRecovery
    SpeciesRhythm
    CadenceShape
    } derive(Eq, ToJson,
    Debug
    )

    RuleProfile

    pub(all) enum RuleProfile {
    Classroom
    Strict
    Renaissance
    Custom
    } derive(Eq, ToJson,
    Debug
    )

    RuleProfileConfig

    pub(all) struct RuleProfileConfig {
    profile : RuleProfile
    allow_hidden_perfect : Bool
    allow_weak_beat_dissonance : Bool
    require_cadence : Bool
    max_span : Int
    max_leap : Int
    max_consecutive_perfect : Int
    } derive(Eq, ToJson,
    Debug
    )

    RuleProfileConfig::classroom

    RuleProfileConfig::custom

    fn RuleProfileConfig::custom(allow_hidden_perfect~ : Bool, allow_weak_beat_dissonance~ : Bool, require_cadence~ : Bool, max_span~ : Int, max_leap~ : Int, max_consecutive_perfect~ : Int) -> RuleProfileConfig

    RuleProfileConfig::is_valid

    fn RuleProfileConfig::is_valid(self : RuleProfileConfig) -> Bool

    RuleProfileConfig::label

    fn RuleProfileConfig::label(self : RuleProfileConfig) -> String

    RuleProfileConfig::renaissance

    RuleProfileConfig::strict

    RuleProfileConfig::with_profile

    fn RuleProfileConfig::with_profile(self : RuleProfileConfig, profile : RuleProfile) -> RuleProfileConfig

    RuleTopic

    pub(all) enum RuleTopic {
    Harmony
    Melody
    Rhythm
    Cadence
    VoiceLeading
    } derive(Eq, ToJson,
    Debug
    )

    Scorecard

    pub(all) struct Scorecard {
    title : String
    technical : Int
    melodic : Int
    harmonic : Int
    rhythmic : Int
    explainability : Int
    total : Int
    grade : String
    } derive(Eq, ToJson,
    Debug
    )

    SequenceEnvelope

    pub(all) struct SequenceEnvelope {
    name : String
    meter : Meter
    notes : Array[NoteRow]
    version : String
    } derive(Eq, ToJson,
    Debug
    )

    SequenceIssue

    pub(all) enum SequenceIssue {
    EmptySequence
    NegativePitch(index~ : Int)
    InvalidDuration(index~ : Int)
    NonMonotonicOnset(index~ : Int)
    Overlap(index~ : Int)
    DuplicateOnset(index~ : Int)
    ExcessiveGap(index~ : Int)
    } derive(Eq, ToJson,
    Debug
    )

    SequenceReport

    pub(all) struct SequenceReport {
    note_count : Int
    duration : Int
    issues : Array[SequenceIssue]
    } derive(Eq, ToJson,
    Debug
    )

    SequenceReport::error_count

    fn SequenceReport::error_count(self : SequenceReport) -> Int

    SequenceReport::is_valid

    fn SequenceReport::is_valid(self : SequenceReport) -> Bool

    Severity

    pub(all) enum Severity {
    Error
    Warning
    Info
    } derive(Eq, ToJson,
    Debug
    )

    Species

    pub(all) enum Species {
    First
    Second
    Third
    Fourth
    Fifth
    } derive(Eq, ToJson,
    Debug
    )

    TeachingLevel

    pub(all) enum TeachingLevel {
    Foundation
    Intermediate
    Advanced
    } derive(Eq, ToJson,
    Debug
    )

    Transformation

    pub(all) struct Transformation {
    kind : TransformationKind
    amount : Int
    description : String
    } derive(Eq, ToJson,
    Debug
    )

    TransformationKind

    pub(all) enum TransformationKind {
    Transpose
    Invert
    Retrograde
    Stretch
    Compress
    Rotate
    } derive(Eq, ToJson,
    Debug
    )

    TriageBand

    pub(all) enum TriageBand {
    Critical
    Attention
    Healthy
    } derive(Eq, ToJson,
    Debug
    )

    TriageItem

    pub(all) struct TriageItem {
    rule : RuleKind
    count : Int
    errors : Int
    warnings : Int
    infos : Int
    priority : Int
    band : TriageBand
    action : String
    } derive(Eq, ToJson,
    Debug
    )

    TurningPoint

    pub(all) struct TurningPoint {
    index : Int
    pitch : Int
    before : Direction
    after : Direction
    } derive(Eq, ToJson,
    Debug
    )

    VerticalEvent

    pub(all) struct VerticalEvent {
    index : Int
    lower : Int
    upper : Int
    semitones : Int
    interval_class : Int
    class : ConsonanceClass
    inversion : Bool
    } derive(Eq, ToJson,
    Debug
    )

    VoiceAssessment

    pub(all) struct VoiceAssessment {
    role : VoiceRole
    range : VoiceRange
    notes : Int
    violations : Int
    lowest : Int
    highest : Int
    } derive(Eq, ToJson,
    Debug
    )

    VoiceAssessment::passed

    fn VoiceAssessment::passed(self : VoiceAssessment) -> Bool

    VoiceAssessment::span

    fn VoiceAssessment::span(self : VoiceAssessment) -> Int

    VoiceLeadingSummary

    pub(all) struct VoiceLeadingSummary {
    transitions : Int
    accepted : Int
    rejected : Int
    contrary : Int
    parallel : Int
    similar : Int
    oblique : Int
    total_cost : Int
    } derive(Eq, ToJson,
    Debug
    )

    VoiceRange

    pub(all) enum VoiceRange {
    Soprano
    Alto
    Tenor
    Bass
    CustomRange(low~ : Int, high~ : Int)
    } derive(Eq, ToJson,
    Debug
    )

    VoiceRange::contains

    fn VoiceRange::contains(self : VoiceRange, midi : Int) -> Bool

    VoiceRange::high

    fn VoiceRange::high(self : VoiceRange) -> Int

    VoiceRange::low

    fn VoiceRange::low(self : VoiceRange) -> Int

    VoiceRange::width

    fn VoiceRange::width(self : VoiceRange) -> Int

    VoiceRole

    pub(all) enum VoiceRole {
    Cantus
    Counterpoint
    Upper
    Lower
    } derive(Eq, ToJson,
    Debug
    )

    absolute_melodic_interval

    fn absolute_melodic_interval(a : Note, b : Note) -> Int

    active_at

    fn active_at(notes : Array[Note], time : Int) -> Array[Note]

    add_snapshot

    fn add_snapshot(history : AnalysisHistory, value : AnalysisSnapshot) -> AnalysisHistory

    aligned_pairs

    fn aligned_pairs(lower : Array[Note], upper : Array[Note]) -> Int

    analysis_csv

    fn analysis_csv(analysis : Analysis) -> String

    analysis_fingerprint

    fn analysis_fingerprint(analysis : Analysis) -> String

    analysis_has_rule

    fn analysis_has_rule(analysis : Analysis, rule : RuleKind) -> Bool

    analysis_indices

    fn analysis_indices(analysis : Analysis) -> Array[Int]

    analysis_is_empty

    fn analysis_is_empty(analysis : Analysis) -> Bool

    analysis_manifest

    fn analysis_manifest(analysis : Analysis) -> Array[String]

    analysis_manifest_text

    fn analysis_manifest_text(analysis : Analysis) -> String

    analysis_markdown

    fn analysis_markdown(analysis : Analysis) -> String

    analysis_title

    fn analysis_title(analysis : Analysis) -> String

    analyze_batch

    fn analyze_batch(cantus : Array[Note], variants : Array[Array[Note]], profile : RuleProfileConfig) -> Array[AnalysisSummary]

    analyze_counterpoint

    fn analyze_counterpoint(cantus : Array[Note], counter : Array[Note], options? : AnalysisOptions) -> Analysis

    analyze_harmony

    fn analyze_harmony(cantus : Array[Note], counter : Array[Note], options : AnalysisOptions) -> Array[Finding]

    analyze_melody

    fn analyze_melody(notes : Array[Note], options : AnalysisOptions) -> Array[Finding]

    analyze_species_shape

    fn analyze_species_shape(cantus : Array[Note], counter : Array[Note], options : AnalysisOptions) -> Array[Finding]

    analyze_with_profile

    fn analyze_with_profile(cantus : Array[Note], counter : Array[Note], profile : RuleProfileConfig) -> Analysis

    api_health

    fn api_health(notes : Array[Note], meter : Meter) -> Bool

    api_health_message

    fn api_health_message(notes : Array[Note], meter : Meter) -> String

    append_report_section

    fn append_report_section(document : ReportDocument, section : ReportSection) -> ReportDocument

    apply_repair_suggestion

    fn apply_repair_suggestion(notes : Array[Note], suggestion : RepairSuggestion) -> Array[Note]

    apply_transformation

    fn apply_transformation(notes : Array[Note], transformation : Transformation) -> Array[Note]

    assess_voice

    fn assess_voice(notes : Array[Note], role : VoiceRole, range : VoiceRange) -> VoiceAssessment

    average_interval

    fn average_interval(notes : Array[Note]) -> Int

    average_pitch

    fn average_pitch(notes : Array[Note]) -> Int

    batch_average

    fn batch_average(report : BatchReport) -> Int

    batch_best_label

    fn batch_best_label(report : BatchReport) -> String?

    batch_count

    fn batch_count(report : BatchReport) -> Int

    batch_csv

    fn batch_csv(report : BatchReport) -> String

    batch_failure_count

    fn batch_failure_count(report : BatchReport) -> Int

    batch_improvement

    fn batch_improvement(report : BatchReport) -> Int

    batch_is_better_than

    fn batch_is_better_than(report : BatchReport, baseline : Int) -> Bool

    batch_manifest

    fn batch_manifest(report : BatchReport) -> Array[String]

    batch_markdown

    fn batch_markdown(report : BatchReport) -> String

    batch_pass_count

    fn batch_pass_count(report : BatchReport) -> Int

    batch_quality

    fn batch_quality(report : BatchReport) -> String

    batch_report

    fn batch_report(cantus : Array[Note], variants : Array[Array[Note]], labels : Array[String], profile : RuleProfileConfig) -> BatchReport

    batch_scores

    fn batch_scores(report : BatchReport) -> Array[Int]

    beat_label

    fn beat_label(point : BeatPoint) -> String

    beat_of

    fn beat_of(meter : Meter, time : Int) -> Int

    beat_point

    fn beat_point(meter : Meter, time : Int, index : Int) -> BeatPoint

    beat_points

    fn beat_points(meter : Meter, notes : Array[Note]) -> Array[BeatPoint]

    beat_strength

    fn beat_strength(meter : Meter, beat : Int) -> BeatStrength

    best_candidate

    fn best_candidate(candidates : Array[PitchCandidate]) -> PitchCandidate?

    best_candidates

    fn best_candidates(candidates : Array[PitchCandidate], limit : Int) -> Array[PitchCandidate]

    best_evaluation

    fn best_evaluation(evaluations : Array[CandidateEvaluation]) -> CandidateEvaluation?

    best_pipeline

    fn best_pipeline(input : PipelineInput) -> PipelineOutput

    best_profile_result

    fn best_profile_result(results : Array[ProfileResult]) -> ProfileResult?

    best_repair_suggestion

    fn best_repair_suggestion(suggestions : Array[RepairSuggestion]) -> RepairSuggestion?

    best_variant

    fn best_variant(cantus : Array[Note], variants : Array[Array[Note]], profile : RuleProfileConfig) -> Array[Note]?

    cadence_candidates

    fn cadence_candidates(cantus : Note, final_pitch : Int, policy : CandidatePolicy) -> Array[PitchCandidate]

    cadence_distance

    fn cadence_distance(notes : Array[Note], target : Int) -> Int

    cadence_message

    fn cadence_message(plan : PhrasePlan) -> String

    cadence_plan

    fn cadence_plan(cantus : Array[Note], counter : Array[Note]) -> CadencePlan

    candidate_constraint_name

    fn candidate_constraint_name(constraint : CandidateConstraint) -> String

    candidate_count_in_range

    fn candidate_count_in_range(candidates : Array[PitchCandidate], low : Int, high : Int) -> Int

    candidate_evaluation_count

    fn candidate_evaluation_count(evaluation : CandidateEvaluation) -> Int

    candidate_evaluation_failed

    fn candidate_evaluation_failed(evaluation : CandidateEvaluation) -> Array[CandidateConstraint]

    candidate_evaluation_has

    fn candidate_evaluation_has(evaluation : CandidateEvaluation, constraint : CandidateConstraint) -> Bool

    candidate_evaluation_markdown

    fn candidate_evaluation_markdown(evaluation : CandidateEvaluation) -> String

    candidate_evaluation_passes

    fn candidate_evaluation_passes(evaluation : CandidateEvaluation, constraint : CandidateConstraint) -> Bool

    candidate_evaluation_summary

    fn candidate_evaluation_summary(evaluation : CandidateEvaluation) -> String

    candidate_has_rule

    fn candidate_has_rule(candidate : PitchCandidate, rule : RuleKind) -> Bool

    candidate_is_allowed

    fn candidate_is_allowed(cantus : Note, previous : Note?, candidate : Note, policy : CandidatePolicy) -> Bool

    candidate_motion

    fn candidate_motion(cantus_before : Note, cantus_after : Note, counter_before : Note, counter_after : Note) -> MotionKind

    candidate_motion_name

    fn candidate_motion_name(motion_value : MotionKind) -> String

    candidate_note

    fn candidate_note(source : Note, midi : Int) -> Note

    candidate_range

    fn candidate_range(candidates : Array[PitchCandidate]) -> Int

    candidate_score

    fn candidate_score(vertical : Int, melodic : Int, motion_value : MotionKind, policy : CandidatePolicy) -> Int

    candidate_scores

    fn candidate_scores(candidates : Array[PitchCandidate]) -> Array[Int]

    cap_quality

    fn cap_quality(value : Int) -> Int

    cards_for_level

    fn cards_for_level(level : String) -> Array[RuleCard]

    cards_for_rule

    fn cards_for_rule(rule : RuleKind) -> Array[RuleCard]

    cards_for_topic

    fn cards_for_topic(topic : String) -> Array[RuleCard]

    catalog_levels

    fn catalog_levels() -> Array[String]

    catalog_topics

    fn catalog_topics() -> Array[String]

    compact_report

    fn compact_report(analysis : Analysis) -> String

    compact_report_document

    fn compact_report_document(document : ReportDocument) -> String

    compare_contours

    fn compare_contours(left : Array[Note], right : Array[Note]) -> Int

    compare_pitch_statistics

    fn compare_pitch_statistics(left : Array[Note], right : Array[Note]) -> Int

    compare_profiles

    fn compare_profiles(cantus : Array[Note], counter : Array[Note]) -> Array[AnalysisSummary]

    compare_scores

    fn compare_scores(left : Analysis, right : Analysis, profile : RuleProfileConfig) -> Int

    compress_sequence

    fn compress_sequence(notes : Array[Note], factor : Int) -> Array[Note]

    consecutive_perfects

    fn consecutive_perfects(lower : Array[Note], upper : Array[Note]) -> Array[Int]

    consonance_class

    fn consonance_class(semitones : Int) -> ConsonanceClass

    consonance_class_name

    fn consonance_class_name(value : ConsonanceClass) -> String

    constrained_quality

    fn constrained_quality(lower : Array[Note], upper : Array[Note], constraint : MotionConstraint) -> Int

    contour_balance

    fn contour_balance(notes : Array[Note]) -> Int

    contour_label

    fn contour_label(step : ContourStep) -> String

    contour_preserved_after_transpose

    fn contour_preserved_after_transpose(notes : Array[Note], semitones : Int) -> Bool

    contour_range

    fn contour_range(notes : Array[Note]) -> Int

    contour_section

    fn contour_section(notes : Array[Note]) -> ReportSection

    contour_step

    fn contour_step(left : Note, right : Note) -> ContourStep

    contour_steps

    fn contour_steps(notes : Array[Note]) -> Array[ContourStep]

    contour_summary

    fn contour_summary(notes : Array[Note]) -> ContourSummary

    contrary_motion_count

    fn contrary_motion_count(cantus : Array[Note], counter : Array[Note]) -> Int

    contrary_motion_ratio

    fn contrary_motion_ratio(lower : Array[Note], upper : Array[Note]) -> Int

    count_contour

    fn count_contour(notes : Array[Note], step : ContourStep) -> Int

    count_direction

    fn count_direction(notes : Array[Note], direction_value : Direction) -> Int

    count_duration

    fn count_duration(notes : Array[Note], duration : Int) -> Int

    crossing_count

    fn crossing_count(lower : Array[Note], upper : Array[Note]) -> Int

    default_practice_plan

    fn default_practice_plan(rule : RuleKind) -> PracticePlan

    density_by_measure

    fn density_by_measure(meter : Meter, notes : Array[Note]) -> Array[Int]

    direction

    fn direction(a : Note, b : Note) -> Direction

    direction_name

    fn direction_name(value : Direction) -> String

    dissonance_ratio

    fn dissonance_ratio(lower : Array[Note], upper : Array[Note]) -> Int

    duration_between

    fn duration_between(notes : Array[Note], start : Int, end : Int) -> Int

    duration_histogram

    fn duration_histogram(notes : Array[Note]) -> Array[Int]

    duration_ratio

    fn duration_ratio(notes : Array[Note], duration : Int) -> Int

    edit_distance

    fn edit_distance(left : Array[Note], right : Array[Note]) -> Int

    empty_history

    fn empty_history() -> AnalysisHistory

    envelope

    fn envelope(name : String, meter : Meter, notes : Array[Note]) -> SequenceEnvelope

    envelope_notes

    fn envelope_notes(value : SequenceEnvelope) -> Array[Note]

    envelope_summary

    fn envelope_summary(value : SequenceEnvelope) -> String

    evaluate_candidate

    fn evaluate_candidate(cantus_before : Note, cantus_after : Note, counter_before : Note, counter_after : Note, candidate : Note, policy : CandidatePolicy) -> CandidateEvaluation

    Evaluate a candidate as transparent constraint evidence instead of one opaque score.

    evaluate_candidates

    fn evaluate_candidates(cantus_before : Note, cantus_after : Note, counter_before : Note, counter_after : Note, candidates : Array[Note], policy : CandidatePolicy) -> Array[CandidateEvaluation]

    evaluate_motion

    fn evaluate_motion(lower_before : Note, lower_after : Note, upper_before : Note, upper_after : Note, constraint : MotionConstraint) -> MotionResult

    evaluate_practice

    fn evaluate_practice(plan : PracticePlan, completed : Int, score : Int) -> PracticeResult

    evaluate_voice_leading

    fn evaluate_voice_leading(lower : Array[Note], upper : Array[Note], constraint : MotionConstraint) -> Array[MotionResult]

    event_count_between

    fn event_count_between(notes : Array[Note], start : Int, end : Int) -> Int

    exercise

    fn exercise(id : String) -> ExerciseSpec?

    exercise_catalog

    fn exercise_catalog() -> Array[ExerciseSpec]

    The curriculum is intentionally small and curated: each item names a distinct musical task.

    exercise_catalog_markdown

    fn exercise_catalog_markdown(rule : RuleKind) -> String

    exercise_count

    fn exercise_count() -> Int

    exercise_minutes

    fn exercise_minutes(item : ExerciseSpec) -> Int

    exercise_objective

    fn exercise_objective(item : ExerciseSpec) -> String

    exercise_prompt

    fn exercise_prompt(item : ExerciseSpec) -> String

    exercise_summary

    fn exercise_summary(item : ExerciseSpec) -> String

    exercise_target

    fn exercise_target(item : ExerciseSpec) -> String

    exercises_for_level

    fn exercises_for_level(level : String) -> Array[ExerciseSpec]

    exercises_for_rule

    fn exercises_for_rule(rule : RuleKind) -> Array[ExerciseSpec]

    exercises_for_species

    fn exercises_for_species(species : Species) -> Array[ExerciseSpec]

    export_csv

    fn export_csv(value : AnalysisExport) -> String

    export_findings_count

    fn export_findings_count(value : AnalysisExport) -> Int

    export_findings_for

    fn export_findings_for(value : AnalysisExport, rule : RuleKind) -> Array[String]

    export_grade

    fn export_grade(value : AnalysisExport) -> String

    export_has_fingerprint

    fn export_has_fingerprint(value : AnalysisExport, fingerprint : String) -> Bool

    export_is_clean

    fn export_is_clean(value : AnalysisExport) -> Bool

    export_line_count

    fn export_line_count(value : AnalysisExport) -> Int

    export_markdown

    fn export_markdown(value : AnalysisExport) -> String

    export_profile

    fn export_profile(value : AnalysisExport) -> String

    export_recommendation_count

    fn export_recommendation_count(value : AnalysisExport) -> Int

    export_score

    fn export_score(value : AnalysisExport) -> Int

    export_summary_line

    fn export_summary_line(value : AnalysisExport) -> String

    export_to_sections

    fn export_to_sections(value : AnalysisExport) -> Array[ReportSection]

    feature_count

    fn feature_count() -> Int

    filter_by_beat

    fn filter_by_beat(meter : Meter, notes : Array[Note], strength : BeatStrength) -> Array[Note]

    filter_by_duration

    fn filter_by_duration(notes : Array[Note], duration : Int) -> Array[Note]

    filter_by_range

    fn filter_by_range(notes : Array[Note], low : Int, high : Int) -> Array[Note]

    final_sonority_is_valid

    fn final_sonority_is_valid(lower : Array[Note], upper : Array[Note]) -> Bool

    finding_count

    fn finding_count(analysis : Analysis, rule : RuleKind) -> Int

    finding_csv

    fn finding_csv(finding : Finding) -> String

    findings_for

    fn findings_for(analysis : Analysis, severity : Severity) -> Array[Finding]

    findings_for_rule

    fn findings_for_rule(analysis : Analysis, rule : RuleKind) -> Array[Finding]

    findings_section

    fn findings_section(analysis : Analysis) -> ReportSection

    first_dissonance

    fn first_dissonance(lower : Array[Note], upper : Array[Note]) -> Int?

    first_pitch

    fn first_pitch(notes : Array[Note]) -> Int?

    format_analysis

    fn format_analysis(analysis : Analysis) -> String

    format_finding

    fn format_finding(finding : Finding) -> String

    format_note_row

    fn format_note_row(row : NoteRow) -> String

    format_sequence

    fn format_sequence(notes : Array[Note]) -> String

    gap_count

    fn gap_count(notes : Array[Note]) -> Int

    gate_count

    fn gate_count(report : QualityGateReport, status : GateStatus) -> Int

    gate_for_motion

    fn gate_for_motion(summary : VoiceLeadingSummary) -> QualityGate

    gate_for_sequence

    fn gate_for_sequence(report : SequenceReport, name : String) -> QualityGate

    gate_for_summary

    fn gate_for_summary(summary : AnalysisSummary) -> QualityGate

    gate_status_name

    fn gate_status_name(status : GateStatus) -> String

    generate_candidates

    fn generate_candidates(cantus : Note, previous : Note?, policy : CandidatePolicy) -> Array[PitchCandidate]

    generate_voice_candidates

    fn generate_voice_candidates(cantus_before : Note, cantus_after : Note, counter_before : Note?, policy : CandidatePolicy) -> CandidateBatch

    harmonic_interval

    fn harmonic_interval(lower : Note, upper : Note) -> Int

    harmonic_motion_count

    fn harmonic_motion_count(lower : Array[Note], upper : Array[Note], label : String) -> Int

    harmonic_motion_labels

    fn harmonic_motion_labels(lower : Array[Note], upper : Array[Note]) -> Array[String]

    harmonic_signature

    fn harmonic_signature(lower : Array[Note], upper : Array[Note]) -> String

    harmony_section

    fn harmony_section(lower : Array[Note], upper : Array[Note]) -> ReportSection

    harmony_summary

    fn harmony_summary(lower : Array[Note], upper : Array[Note]) -> HarmonySummary

    has_feature

    fn has_feature(name : String) -> Bool

    health_summary

    fn health_summary() -> String

    hidden_perfect_indices

    fn hidden_perfect_indices(lower : Array[Note], upper : Array[Note]) -> Array[Int]

    highest_severity

    fn highest_severity(analysis : Analysis) -> Severity?

    history_average

    fn history_average(history : AnalysisHistory) -> Int

    history_best

    fn history_best(history : AnalysisHistory) -> AnalysisSnapshot?

    history_delta

    fn history_delta(history : AnalysisHistory, first : Int, second : Int) -> Int?

    history_errors

    fn history_errors(history : AnalysisHistory) -> Int

    history_fingerprint

    fn history_fingerprint(history : AnalysisHistory) -> String

    history_from_validations

    fn history_from_validations(labels : Array[String], validations : Array[PairValidation]) -> AnalysisHistory

    history_is_improving

    fn history_is_improving(history : AnalysisHistory) -> Bool

    history_latest

    fn history_latest(history : AnalysisHistory) -> AnalysisSnapshot?

    history_markdown

    fn history_markdown(history : AnalysisHistory) -> String

    history_scores

    fn history_scores(history : AnalysisHistory) -> Array[Int]

    history_warnings

    fn history_warnings(history : AnalysisHistory) -> Int

    interval_class

    fn interval_class(semitones : Int) -> Int

    interval_class_name

    fn interval_class_name(value : Int) -> String

    interval_is_stable

    fn interval_is_stable(value : Int) -> Bool

    interval_profile

    fn interval_profile(notes : Array[Note]) -> Array[Int]

    interval_size

    fn interval_size(semitones : Int) -> IntervalSize

    interval_size_name

    fn interval_size_name(value : IntervalSize) -> String

    interval_statistics

    fn interval_statistics(notes : Array[Note]) -> IntervalStatistics

    interval_tension

    fn interval_tension(value : Int) -> Int

    invert_sequence

    fn invert_sequence(notes : Array[Note], axis : Int) -> Array[Note]

    is_accented

    fn is_accented(point : BeatPoint) -> Bool

    is_arch_shape

    fn is_arch_shape(notes : Array[Note]) -> Bool

    is_black_key

    fn is_black_key(midi : Int) -> Bool

    is_consonance

    fn is_consonance(semitones : Int) -> Bool

    is_dissonance

    fn is_dissonance(semitones : Int) -> Bool

    is_extreme_register

    fn is_extreme_register(midi : Int) -> Bool

    is_imperfect_consonance

    fn is_imperfect_consonance(semitones : Int) -> Bool

    is_leap

    fn is_leap(semitones : Int) -> Bool

    is_measure_boundary

    fn is_measure_boundary(meter : Meter, time : Int) -> Bool

    is_perfect_consonance

    fn is_perfect_consonance(semitones : Int) -> Bool

    is_step

    fn is_step(semitones : Int) -> Bool

    is_valley_shape

    fn is_valley_shape(notes : Array[Note]) -> Bool

    is_weak

    fn is_weak(point : BeatPoint) -> Bool

    labels_text

    fn labels_text(notes : Array[Note]) -> String

    largest_repeated_run

    fn largest_repeated_run(notes : Array[Note]) -> Int

    last_dissonance

    fn last_dissonance(lower : Array[Note], upper : Array[Note]) -> Int?

    last_pitch

    fn last_pitch(notes : Array[Note]) -> Int?

    learning_objective

    fn learning_objective(rule : RuleKind) -> String

    lesson_prompts

    fn lesson_prompts(stage : LessonStage) -> Array[String]

    lesson_stage_index

    fn lesson_stage_index(stage : LessonStage) -> Int

    lesson_stage_name

    fn lesson_stage_name(stage : LessonStage) -> String

    lesson_stage_order

    fn lesson_stage_order() -> Array[LessonStage]

    lesson_step

    fn lesson_step(index : Int, stage : LessonStage, title : String, prompt : String, rule : RuleKind?) -> LessonStep

    library_name

    fn library_name() -> String

    library_version

    fn library_version() -> String

    make_analysis_export

    fn make_analysis_export(title : String, profile : RuleProfileConfig, analysis : Analysis) -> AnalysisExport

    make_scorecard

    fn make_scorecard(output : PipelineOutput) -> Scorecard

    make_segment

    fn make_segment(notes : Array[Note], start : Int, end : Int, role : PhraseRole) -> PhraseSegment

    manifest

    fn manifest(profile : RuleProfileConfig, meter : Meter) -> Array[String]

    manifest_text

    fn manifest_text(profile : RuleProfileConfig, meter : Meter) -> String

    maximum_density

    fn maximum_density(meter : Meter, notes : Array[Note]) -> Int

    measure_of

    fn measure_of(meter : Meter, time : Int) -> Int

    melodic_interval

    fn melodic_interval(a : Note, b : Note) -> Int

    melodic_interval_histogram

    fn melodic_interval_histogram(notes : Array[Note]) -> Array[Int]

    merge_sequences

    fn merge_sequences(left : Array[Note], right : Array[Note]) -> Array[Note]

    motion

    fn motion(cantus_a : Note, cantus_b : Note, counter_a : Note, counter_b : Note) -> MotionKind

    motion_acceptance_rate

    fn motion_acceptance_rate(summary : VoiceLeadingSummary) -> Int

    motion_cost

    fn motion_cost(value : MotionKind) -> Int

    motion_rejection_indices

    fn motion_rejection_indices(lower : Array[Note], upper : Array[Note], constraint : MotionConstraint) -> Array[Int]

    next_exercise

    fn next_exercise(rule : RuleKind, completed : Array[String]) -> ExerciseSpec?

    next_lesson_stage

    fn next_lesson_stage(stage : LessonStage) -> LessonStage

    normalize_onsets

    fn normalize_onsets(notes : Array[Note]) -> Array[Note]

    normalize_phrase

    fn normalize_phrase(notes : Array[Note], low : Int, high : Int) -> Array[Note]

    normalize_pitch

    fn normalize_pitch(midi : Int, low : Int, high : Int) -> Int

    note_at_index

    fn note_at_index(notes : Array[Note], index : Int) -> Note?

    note_end

    fn note_end(note : Note) -> Int

    note_indices

    fn note_indices(notes : Array[Note]) -> Array[Int]

    note_name

    fn note_name(note : Note) -> String

    note_row_header

    fn note_row_header() -> String

    note_row_to_line

    fn note_row_to_line(row : NoteRow) -> String

    note_with_pitch

    fn note_with_pitch(note : Note, midi : Int) -> Note

    notes_at

    fn notes_at(notes : Array[Note], onset : Int) -> Array[Note]

    notes_from_pitches

    fn notes_from_pitches(pitches_value : Array[Int], duration : Int) -> Array[Note]

    notes_from_rows

    fn notes_from_rows(rows : Array[NoteRow]) -> Array[Note]

    notes_to_lines

    fn notes_to_lines(notes : Array[Note]) -> Array[String]

    notes_to_pitches

    fn notes_to_pitches(notes : Array[Note]) -> Array[Int]

    notes_to_tsv

    fn notes_to_tsv(notes : Array[Note]) -> String

    notes_with_labels

    fn notes_with_labels(notes : Array[Note]) -> Array[String]

    octave_number

    fn octave_number(midi : Int) -> Int

    onset_histogram

    fn onset_histogram(notes : Array[Note], period : Int) -> Array[Int]

    onset_span

    fn onset_span(notes : Array[Note]) -> Int

    package_ready

    fn package_ready() -> Bool

    pair_statistics

    fn pair_statistics(cantus : Array[Note], counter : Array[Note]) -> PairStatistics

    parallel_perfect_indices

    fn parallel_perfect_indices(lower : Array[Note], upper : Array[Note]) -> Array[Int]

    partition_phrases

    fn partition_phrases(notes : Array[Note], meter : Meter, measures_per_window : Int) -> PhrasePartition

    Divide a sequence into deterministic measure-sized windows for local analysis.

    perfect_ratio

    fn perfect_ratio(lower : Array[Note], upper : Array[Note]) -> Int

    phrase_is_cadential

    fn phrase_is_cadential(plan : PhrasePlan) -> Bool

    phrase_length

    fn phrase_length(plan : PhrasePlan) -> Int

    phrase_partition_boundaries

    fn phrase_partition_boundaries(partition : PhrasePartition) -> Array[Int]

    phrase_partition_for_meter

    fn phrase_partition_for_meter(notes : Array[Note], meter : Meter) -> PhrasePartition

    phrase_partition_markdown

    fn phrase_partition_markdown(partition : PhrasePartition) -> String

    phrase_partition_summary

    fn phrase_partition_summary(partition : PhrasePartition) -> String

    phrase_role_counts

    fn phrase_role_counts(plan : PhrasePlan) -> Array[Int]

    phrase_window

    fn phrase_window(partition : PhrasePartition, index : Int) -> PhraseWindow?

    phrase_window_contains

    fn phrase_window_contains(window : PhraseWindow, note_index : Int) -> Bool

    phrase_window_count

    fn phrase_window_count(partition : PhrasePartition) -> Int

    phrase_window_duration

    fn phrase_window_duration(window : PhraseWindow) -> Int

    phrase_window_is_dense

    fn phrase_window_is_dense(window : PhraseWindow, threshold : Int) -> Bool

    phrase_window_summary

    fn phrase_window_summary(window : PhraseWindow) -> String

    pipeline_compare

    fn pipeline_compare(left : PipelineOutput, right : PipelineOutput) -> Int

    pipeline_grade

    fn pipeline_grade(output : PipelineOutput) -> String

    pipeline_has_quality_flag

    fn pipeline_has_quality_flag(output : PipelineOutput, flag : String) -> Bool

    pipeline_has_rule

    fn pipeline_has_rule(output : PipelineOutput, rule : RuleKind) -> Bool

    pipeline_is_explainable

    fn pipeline_is_explainable(output : PipelineOutput) -> Bool

    pipeline_manifest

    fn pipeline_manifest(output : PipelineOutput) -> Array[String]

    pipeline_manifest_text

    fn pipeline_manifest_text(output : PipelineOutput) -> String

    pipeline_markdown

    fn pipeline_markdown(output : PipelineOutput) -> String

    pipeline_passed

    fn pipeline_passed(output : PipelineOutput) -> Bool

    pipeline_profile

    fn pipeline_profile(output : PipelineOutput) -> String

    pipeline_profiles

    fn pipeline_profiles(input : PipelineInput) -> Array[PipelineOutput]

    pipeline_quality_flags

    fn pipeline_quality_flags(output : PipelineOutput) -> Array[String]

    pipeline_recommendation_count

    fn pipeline_recommendation_count(output : PipelineOutput) -> Int

    pipeline_report_section_count

    fn pipeline_report_section_count(output : PipelineOutput) -> Int

    pipeline_rule_count

    fn pipeline_rule_count(output : PipelineOutput, rule : RuleKind) -> Int

    pipeline_score

    fn pipeline_score(output : PipelineOutput) -> Int

    pipeline_summary

    fn pipeline_summary(output : PipelineOutput) -> String

    pipeline_with_profile

    fn pipeline_with_profile(input : PipelineInput, profile : RuleProfileConfig) -> PipelineOutput

    pitch_class

    fn pitch_class(midi : Int) -> PitchClass

    pitch_class_name

    fn pitch_class_name(pitch : PitchClass) -> String

    pitch_edit_distance

    fn pitch_edit_distance(left : Array[Note], right : Array[Note]) -> Int

    pitch_histogram

    fn pitch_histogram(notes : Array[Note]) -> Array[Int]

    pitch_label

    fn pitch_label(midi : Int) -> String

    pitch_rows

    fn pitch_rows(low : Int, high : Int, onset : Int, duration : Int) -> Array[NoteRow]

    pitch_statistics

    fn pitch_statistics(notes : Array[Note]) -> PitchStatistics

    pitch_variance_proxy

    fn pitch_variance_proxy(notes : Array[Note]) -> Int

    pitches

    fn pitches(notes : Array[Note]) -> Array[Int]

    plan_for_analysis

    fn plan_for_analysis(analysis : Analysis) -> PracticePlan

    plan_is_complete

    fn plan_is_complete(result : PracticeResult) -> Bool

    plan_markdown

    fn plan_markdown(plan : PracticePlan) -> String

    plan_phrase

    fn plan_phrase(cantus : Array[Note], counter : Array[Note], segment_size : Int) -> PhrasePlan

    plan_progress

    fn plan_progress(result : PracticeResult) -> Int

    plan_step

    fn plan_step(plan : PracticePlan, index : Int) -> LessonStep?

    practice_section

    fn practice_section(analysis : Analysis) -> ReportSection

    production_features

    fn production_features() -> Array[String]

    profile_config

    fn profile_config(profile : RuleProfile) -> RuleProfileConfig

    profile_improvement

    fn profile_improvement(results : Array[ProfileResult]) -> Int

    profile_labels

    fn profile_labels() -> Array[String]

    profile_result

    fn profile_result(profile : RuleProfileConfig, analysis : Analysis) -> ProfileResult

    profile_result_markdown

    fn profile_result_markdown(results : Array[ProfileResult]) -> String

    profile_result_table

    fn profile_result_table(results : Array[ProfileResult]) -> String

    profile_results

    fn profile_results(cantus : Array[Note], counter : Array[Note]) -> Array[ProfileResult]

    quality_gate_actions

    fn quality_gate_actions(report : QualityGateReport) -> Array[String]

    quality_gate_markdown

    fn quality_gate_markdown(report : QualityGateReport) -> String

    quality_gate_passed

    fn quality_gate_passed(report : QualityGateReport) -> Bool

    quality_gate_report

    fn quality_gate_report(validation : PairValidation, motion : VoiceLeadingSummary) -> QualityGateReport

    quality_gate_score

    fn quality_gate_score(report : QualityGateReport) -> Int

    quantize_note

    fn quantize_note(note : Note, grid : Int) -> Note

    quantize_sequence

    fn quantize_sequence(notes : Array[Note], grid : Int) -> Array[Note]

    quantize_time

    fn quantize_time(time : Int, grid : Int) -> Int

    ready_message

    fn ready_message() -> String

    recommendation_count_for_rule

    fn recommendation_count_for_rule(analysis : Analysis, rule : RuleKind) -> Int

    recommendation_for_finding

    fn recommendation_for_finding(finding : Finding) -> Recommendation

    recommendation_markdown

    fn recommendation_markdown(recommendation : Recommendation) -> String

    recommendation_section

    fn recommendation_section(analysis : Analysis) -> ReportSection

    recommendations

    fn recommendations(analysis : Analysis) -> Array[Recommendation]

    recommendations_markdown

    fn recommendations_markdown(analysis : Analysis) -> String

    register_bands

    fn register_bands(notes : Array[Note], width : Int) -> Array[RegisterBand]

    register_distance

    fn register_distance(notes : Array[Note], target : Int) -> Int

    render_document

    fn render_document(document : ReportDocument) -> String

    render_section

    fn render_section(section : ReportSection) -> String

    repair_kind_name

    fn repair_kind_name(kind : RepairKind) -> String

    repair_suggestion_all_in_range

    fn repair_suggestion_all_in_range(suggestions : Array[RepairSuggestion], low : Int, high : Int) -> Bool

    repair_suggestion_average_score

    fn repair_suggestion_average_score(suggestions : Array[RepairSuggestion]) -> Int

    repair_suggestion_count

    fn repair_suggestion_count(suggestions : Array[RepairSuggestion]) -> Int

    repair_suggestion_for_index

    fn repair_suggestion_for_index(suggestions : Array[RepairSuggestion], index : Int) -> Array[RepairSuggestion]

    repair_suggestion_kinds

    fn repair_suggestion_kinds(suggestions : Array[RepairSuggestion]) -> Array[String]

    repair_suggestion_markdown

    fn repair_suggestion_markdown(suggestions : Array[RepairSuggestion]) -> String

    repair_suggestion_summary

    fn repair_suggestion_summary(suggestion : RepairSuggestion) -> String

    repair_suggestions

    fn repair_suggestions(finding : Finding, notes : Array[Note], max_leap : Int, low : Int, high : Int) -> Array[RepairSuggestion]

    Produce bounded single-event edits that can be reviewed before applying them.

    repeated_run_lengths

    fn repeated_run_lengths(notes : Array[Note]) -> Array[Int]

    replace_note

    fn replace_note(notes : Array[Note], index : Int, replacement : Note) -> Array[Note]

    replace_pitch

    fn replace_pitch(notes : Array[Note], index : Int, midi : Int) -> Array[Note]

    report_contains

    fn report_contains(document : ReportDocument, id : String) -> Bool

    report_document

    fn report_document(title : String, analysis : Analysis, meter : Meter, cantus : Array[Note], counter : Array[Note]) -> ReportDocument

    report_line_count

    fn report_line_count(analysis : Analysis) -> Int

    report_quality_score

    fn report_quality_score(document : ReportDocument, analysis : Analysis) -> Int

    report_section_count

    fn report_section_count(document : ReportDocument) -> Int

    report_section_ids

    fn report_section_ids(document : ReportDocument) -> Array[String]

    report_with_manifest

    fn report_with_manifest(document : ReportDocument, profile : RuleProfileConfig, meter : Meter) -> ReportDocument

    report_word_count

    fn report_word_count(document : ReportDocument) -> Int

    retrograde_sequence

    fn retrograde_sequence(notes : Array[Note]) -> Array[Note]

    rhythm_density

    fn rhythm_density(meter : Meter, notes : Array[Note]) -> Int

    rhythm_section

    fn rhythm_section(meter : Meter, notes : Array[Note]) -> ReportSection

    role_for_segment

    fn role_for_segment(index : Int, total : Int) -> PhraseRole

    rotate_sequence

    fn rotate_sequence(notes : Array[Note], amount : Int) -> Array[Note]

    rows_from_notes

    fn rows_from_notes(notes : Array[Note]) -> Array[NoteRow]

    rule_card

    fn rule_card(rule : RuleKind, index : Int) -> RuleCard?

    rule_card_count

    fn rule_card_count() -> Int

    rule_cards

    fn rule_cards() -> Array[RuleCard]

    Each card documents one analyzer rule with an actionable domain-specific repair.

    rule_explanation

    fn rule_explanation(rule : RuleKind) -> String

    rule_family

    fn rule_family(rule : RuleKind) -> String

    rule_is_harmonic

    fn rule_is_harmonic(rule : RuleKind) -> Bool

    rule_is_structural

    fn rule_is_structural(rule : RuleKind) -> Bool

    rule_learning_level

    fn rule_learning_level(rule : RuleKind) -> String

    rule_remedy

    fn rule_remedy(rule : RuleKind) -> String

    rule_topic_name

    fn rule_topic_name(topic : RuleTopic) -> String

    run_pipeline

    fn run_pipeline(input : PipelineInput) -> PipelineOutput

    safe_transformations

    fn safe_transformations() -> Array[Transformation]

    same_interval_profile

    fn same_interval_profile(left : Array[Note], right : Array[Note]) -> Bool

    same_sequence

    fn same_sequence(left : Array[Note], right : Array[Note]) -> Bool

    scale_time

    fn scale_time(notes : Array[Note], factor : Int) -> Array[Note]

    score_for

    fn score_for(analysis : Analysis, profile : RuleProfileConfig) -> Int

    scorecard_action

    fn scorecard_action(scorecard : Scorecard) -> String

    scorecard_compare

    fn scorecard_compare(left : Scorecard, right : Scorecard) -> Int

    scorecard_csv

    fn scorecard_csv(scorecard : Scorecard) -> String

    scorecard_dimensions

    fn scorecard_dimensions(scorecard : Scorecard) -> Array[Int]

    scorecard_grade

    fn scorecard_grade(scorecard : Scorecard) -> String

    scorecard_markdown

    fn scorecard_markdown(scorecard : Scorecard) -> String

    scorecard_passed

    fn scorecard_passed(scorecard : Scorecard) -> Bool

    section_by_id

    fn section_by_id(document : ReportDocument, id : String) -> ReportSection?

    sections_by_priority

    fn sections_by_priority(document : ReportDocument, minimum : Int) -> Array[ReportSection]

    sections_for_analysis

    fn sections_for_analysis(analysis : Analysis, meter : Meter, cantus : Array[Note], counter : Array[Note]) -> Array[ReportSection]

    segment_phrase

    fn segment_phrase(notes : Array[Note], target : Int) -> Array[PhraseSegment]

    semitone_distance

    fn semitone_distance(left : PitchClass, right : PitchClass) -> Int

    sequence_end

    fn sequence_end(notes : Array[Note]) -> Int

    sequence_fingerprint

    fn sequence_fingerprint(notes : Array[Note]) -> String

    sequence_markdown

    fn sequence_markdown(report : SequenceReport) -> String

    sequence_report

    fn sequence_report(notes : Array[Note]) -> SequenceReport

    severity_rank

    fn severity_rank(severity : Severity) -> Int

    shift_onsets

    fn shift_onsets(notes : Array[Note], delta : Int) -> Array[Note]

    snapshot

    fn snapshot(label : String, validation : PairValidation) -> AnalysisSnapshot

    species_count

    fn species_count() -> Int

    split_points

    fn split_points(notes : Array[Note], target : Int) -> Array[Int]

    stable_event_indices

    fn stable_event_indices(lower : Array[Note], upper : Array[Note]) -> Array[Int]

    stretch_sequence

    fn stretch_sequence(notes : Array[Note], factor : Int) -> Array[Note]

    summarize

    fn summarize(analysis : Analysis) -> AnalysisSummary

    summarize_rhythm

    fn summarize_rhythm(meter : Meter, notes : Array[Note]) -> RhythmSummary

    summarize_voice_leading

    fn summarize_voice_leading(lower : Array[Note], upper : Array[Note], constraint : MotionConstraint) -> VoiceLeadingSummary

    summary_csv

    fn summary_csv(summary : AnalysisSummary) -> String

    summary_section

    fn summary_section(analysis : Analysis) -> ReportSection

    supported_profile_count

    fn supported_profile_count() -> Int

    supported_rule_count

    fn supported_rule_count() -> Int

    supported_species

    fn supported_species() -> Array[Species]

    syncopation_count

    fn syncopation_count(meter : Meter, notes : Array[Note]) -> Int

    teaching_level_name

    fn teaching_level_name(level : TeachingLevel) -> String

    tension_profile

    fn tension_profile(lower : Array[Note], upper : Array[Note]) -> Array[Int]

    tied_count

    fn tied_count(notes : Array[Note]) -> Int

    top_recommendations

    fn top_recommendations(analysis : Analysis, limit : Int) -> Array[Recommendation]

    total_sounding_duration

    fn total_sounding_duration(notes : Array[Note]) -> Int

    total_tension

    fn total_tension(lower : Array[Note], upper : Array[Note]) -> Int

    transformation_catalog

    fn transformation_catalog() -> Array[Transformation]

    transformation_count

    fn transformation_count() -> Int

    transformation_description

    fn transformation_description(value : Transformation) -> String

    transformation_examples

    fn transformation_examples(notes : Array[Note]) -> Array[String]

    transformation_is_safe

    fn transformation_is_safe(transformation : Transformation) -> Bool

    transformation_name

    fn transformation_name(kind : TransformationKind) -> String

    transformation_round_trip

    fn transformation_round_trip(notes : Array[Note], semitones : Int) -> Bool

    transpose

    fn transpose(notes : Array[Note], semitones : Int) -> Array[Note]

    transpose_pitch_class

    fn transpose_pitch_class(pitch : PitchClass, semitones : Int) -> PitchClass

    transpose_sequence

    fn transpose_sequence(notes : Array[Note], semitones : Int) -> Array[Note]

    triage_actions

    fn triage_actions(triage : AnalysisTriage) -> Array[String]

    triage_analysis

    fn triage_analysis(analysis : Analysis) -> AnalysisTriage

    Convert raw findings into a stable repair queue for editors and teaching tools.

    triage_band

    fn triage_band(analysis : Analysis) -> TriageBand

    triage_band_name

    fn triage_band_name(band : TriageBand) -> String

    triage_compare

    fn triage_compare(left : AnalysisTriage, right : AnalysisTriage) -> Int

    triage_csv

    fn triage_csv(triage : AnalysisTriage) -> String

    triage_is_actionable

    fn triage_is_actionable(triage : AnalysisTriage) -> Bool

    triage_item

    fn triage_item(triage : AnalysisTriage, index : Int) -> TriageItem?

    triage_item_count

    fn triage_item_count(triage : AnalysisTriage) -> Int

    triage_item_summary

    fn triage_item_summary(item : TriageItem) -> String

    triage_markdown

    fn triage_markdown(triage : AnalysisTriage) -> String

    triage_priority_for_rule

    fn triage_priority_for_rule(triage : AnalysisTriage, rule : RuleKind) -> Int

    triage_rule_count

    fn triage_rule_count(triage : AnalysisTriage, rule : RuleKind) -> Int

    triage_rule_order

    fn triage_rule_order(triage : AnalysisTriage) -> Array[RuleKind]

    triage_summary

    fn triage_summary(triage : AnalysisTriage) -> String

    trim_after

    fn trim_after(notes : Array[Note], time : Int) -> Array[Note]

    trim_before

    fn trim_before(notes : Array[Note], time : Int) -> Array[Note]

    turning_points

    fn turning_points(notes : Array[Note]) -> Array[TurningPoint]

    unescape_field

    fn unescape_field(value : String) -> String

    unstable_event_indices

    fn unstable_event_indices(lower : Array[Note], upper : Array[Note]) -> Array[Int]

    valid_profiles

    fn valid_profiles() -> Array[RuleProfileConfig]

    validate_pair

    fn validate_pair(cantus : Array[Note], counter : Array[Note], profile : RuleProfileConfig) -> PairValidation

    vertical_event

    fn vertical_event(lower : Note, upper : Note, index : Int) -> VerticalEvent

    vertical_events

    fn vertical_events(lower : Array[Note], upper : Array[Note]) -> Array[VerticalEvent]

    voice_assessment_is_extreme

    fn voice_assessment_is_extreme(assessment : VoiceAssessment) -> Bool

    voice_assessment_markdown

    fn voice_assessment_markdown(assessment : VoiceAssessment) -> String

    voice_assessment_pitch_center

    fn voice_assessment_pitch_center(assessment : VoiceAssessment) -> Int

    voice_assessment_repair_distance

    fn voice_assessment_repair_distance(assessment : VoiceAssessment) -> Int

    voice_assessment_status

    fn voice_assessment_status(assessment : VoiceAssessment) -> String

    voice_assessment_summary

    fn voice_assessment_summary(assessment : VoiceAssessment) -> String

    voice_assessment_violation_rate

    fn voice_assessment_violation_rate(assessment : VoiceAssessment) -> Int

    voice_crossing_at

    fn voice_crossing_at(lower : Note, upper : Note) -> Bool

    voice_leading_quality

    fn voice_leading_quality(lower : Array[Note], upper : Array[Note]) -> Int

    voice_order_is_stable

    fn voice_order_is_stable(lower : Array[Note], upper : Array[Note]) -> Bool

    voice_range_name

    fn voice_range_name(range : VoiceRange) -> String

    voice_role_name

    fn voice_role_name(role : VoiceRole) -> String

    voices_fit

    fn voices_fit(lower : Array[Note], upper : Array[Note], lower_range : VoiceRange, upper_range : VoiceRange) -> Bool

    weakest_dimension

    fn weakest_dimension(scorecard : Scorecard) -> String

    weighted_pitch_center

    fn weighted_pitch_center(notes : Array[Note]) -> Int