Journal
Sections
Reading settings
No voice for this language in this browser.
More voices
Code and English terms
Off: the page’s voice reads everything, with no pause between two voices.
No voice for this language in this browser.
More voices
More voices: Microsoft Edge has natural online voices, and Windows (Settings › Time & language › Speech), macOS and Android install others.
Progress
Section titled “Progress”- Course program: .NET 10, built against GA’s
GA.Domain.Coreat a pinned commit - CI: every lesson’s output compared with its expected file on three OSes
- Lesson 1: notes, pitch classes and the fretboard
- Lesson 2: scales, modes and 12-bit scale ids
- Lesson 3: chords, symbols, inversions and voicings
- Lesson 4: set classes, interval vectors and the Z-relation
- Diagrams: bracelets, chord grids, fretboard and circles of fifths drawn by the course program, checked by CI
- Lesson 5: keys, key signatures and the circle of fifths
- Lesson 6: the chords of a key
- Lesson 7: cadences, ii–V–I and the key of a progression
- Lesson 8: the ukulele and the bass
- Appendix A: every instrument in GA’s catalogue
- Appendix B: the OPTIC hierarchy
- Appendix C: a verdict on every
DIFFrow of lessons 1 to 7 - Lesson 9: voice leading and common tones
- Lesson 10: substitutions and modal mixture
- Lesson 11: modes in depth
- Lesson 12: symmetry and modes of limited transposition
- Lesson 13: extended and altered chords
- Lesson 14: guitar voicings, shells, drop 2 and drop 3
- Lesson 15: the fretboard, CAGED, fingering and playability
- Lesson 16: arpeggios, chord–scale theory and improvisation
- Lesson 17 (see the outline on the mission page)
The forty divergences between this course’s arithmetic and Guitar Alchemist’s, the nineteen defects they collapse into and the verdict on each are in Appendix C; sixteen of them were merged upstream in GA #711, and three stay as documented design limits. This table is what the appendix does not cover: findings outside the executable comparison of lessons 1 to 7. The BraceletNotation row was read rather than run, and says so; the rows of lessons 9 to 12 come from their programs, which compile GA’s files, copy its functions as they are, or rewrite them, and each row says which.
| Expected | What happens | Where | Measure | Status |
|---|---|---|---|---|
getAllInstruments() returns the instruments the YAML holds |
It returns one, and two tunings, falling back to hard-coded guitar values without an error or a log line | InstrumentsYaml/InstrumentsConfig, GA.Business.Config at a826864 |
The file holds 122 instruments and 280 tunings; the loader returned 1 and 2. Seven of the 280 are not pitches at all: two pedal steel entries begin with their tuning’s name, one with the word Tuning, one with the instrument’s name, one keeps part of its name |
Fixed upstream by #734, merged 2026-09-24: the file is read as a mapping, 122 instruments and 280 tunings, and a failure now says so on stderr instead of silently answering with the built-in guitar. Nine tunings were restored from Tunings.txt; the two harp guitar entries keep their ` |
Tuning.BuildPitchArray numbers the strings of any tuning correctly |
It decides which end is string 1 by comparing the first pitch with the last one only, so a re-entrant tuning comes out backwards | Tuning.BuildPitchArray at a826864 |
GA’s own two 5-string banjo tunings, whose drone string is written first and sounds higher than the last, are numbered the wrong way round — contradicting Str’s own comment that string 1 is the highest |
Fixed upstream by #734: the direction is decided by counting rising against falling steps between adjacent strings, so both banjo tunings number string 1 as the highest 2026-09-15, 2026-09-24 |
Fretboard.GetNote’s documented parameter matches its indexing |
The comment says “Zero-based string index (0 = lowest string)” and the code indexes Tuning[stringIndex + 1], where string 1 is the highest |
Fretboard.GetNote at a826864 |
The comment is wrong, the code is right | Reproduced, documentation only 2026-09-15 |
The MCP server’s ga_chord_to_set spells the chord it was given |
It takes its pitch classes from an F# closure that keeps one interval per extension and drops the alterations, so the spelling and the Forte number are wrong | DomainClosures.fs#L85-L98, GA’s MCP server |
Cm7b5 gives {C, Eb, G, Bb} and 4-26, where 4-27 with G♭ is right; Cdim7 gives 4-27 and “Scale: Major Seventh”, where 4-28 is right |
Fixed upstream by #681, merged 2026-09-23. Re-run on 27a1257: Cm7b5 gives {C, Eb, F#, Bb} and 4-27, Cdim7 gives 4-28 2026-09-14, 2026-09-24 |
ga_set_class_subs groups the chords it lists under the right quality |
Every chord falls under [maj], because the test is c.EndsWith(""), which is true of every string |
ChordAtonalTool.cs#L187-L190 |
The lists themselves are right; only the grouping is not | Fixed upstream by #681. Re-run on 27a1257: the major triads under [maj], the minor ones under [m] 2026-09-14, 2026-09-24 |
ga_scale_by_id and ga_scale_by_name answer for a scale GA knows |
ga_scale_by_id(2741) returns Major with Forte Number: Some(n/a) where 7-35 is expected, and ga_scale_by_name("Dorian") is not found at all |
GA’s MCP server | One wrong field, one missing lookup | Fixed upstream by #681. Re-run on 27a1257: Forte Number: 7-35, and Dorian found as id 1709 2026-09-14, 2026-09-24 |
| Every MCP tool that takes a chord or a key answers | Several return the string “An error occurred” rather than an MCP error | GA’s MCP server | get_chord_voicings("C", maxFret 3), get_neighboring_keys and get_diatonic_chords("A minor") all answer that way; ga_search_voicings("C major open chord") ignored the “open” constraint and returned 8-8-x-x-7-x |
Reproduced; the server’s build commit was never confirmed, so these are not pinned to a826864 2026-09-14. On 27a1257, get_neighboring_keys("Key of C") answers F, C, G; the other three need GaApi running and were not re-run 2026-09-24 |
ga_key_from_progression and ga_analyze_progression find the key a cadence establishes |
They scored chord roots against the natural minor scale and preferred the first chord’s root: Dm7 G7 Cmaj7 gave D minor, Am Dm E7 Am gave A major |
GuitaristProblemTools.cs#L157-L223, DomainClosures.fs#L255-L336 |
On 27a1257: Dm7 G7 Cmaj7 gives C major, ii V I; Am Dm E7 Am gives A minor, with E7 labelled v and counted outside the key; Am F C G still puts A minor first, tied 4/4 with C major, against the tool’s own description |
Fixed upstream by #625, merged 2026-09-24, for the two cadences; the numeral and the description remain, not reported 2026-09-15, 2026-09-24 |
BraceletNotation.tsx places its dots on its own spokes |
The dots are placed at angle − 90° while the spokes use cos(angle) with no offset, a quarter turn apart; findSymmetryAxes also misses the axes that fall between two notes and counts each axis twice |
GA’s ReactComponents/ga-react-components |
Read in the source, never run | Reproduced by #733’s test, and fixed by it, merged 2026-09-24 2026-09-15, 2026-09-24 |
ga_common_tones and the chatbot’s CommonTones skill name every note two chords share |
Both call the F# closure domain.commonTones, which builds each chord from its quality’s triad plus one interval per extension, from a six-entry table, and drops the alterations |
DomainClosures.fs#L85-L98, #L488-L531 |
The server running on 2026-09-30 (version not reported): 5 of 7 pairs lose one note — F from Bm7b5/G7, B from Cmaj9/Em7, A from Cdim7/F7 and from C6/Am7, B♭ from C9/Gm7 | Fixed on GA’s main by #681, whose chordTones now feeds domain.commonTones too: read on 5c3a52a, not run against a server built after it 2026-09-30 |
VoiceLeadingSkill returns the smallest voice leading, as its answer says (“This is the optimal pitch-class assignment”) |
It makes the chords the same size by always repeating the smaller chord’s root | VoiceLeadingSkill.cs#L131, #L185-L194 |
G → Cmaj7: 5 semitones where 3 exist, with B doubled. 1,260 of the 2,880 triad → seventh pairs miss the minimum, by up to 4 semitones, and as many in the other direction | Reproduced by rewriting the rule in the course program; the chatbot itself was not run; not reported 2026-09-30 |
| The skill’s ten example prompts are read by its own pattern | “voice leading C major to G major” does not match: the pattern wants a chord symbol right before “to”. The skill is picked by meaning (CanHandle returns false), so it would receive that prompt and answer “Ask about voice leading between two chords” |
VoiceLeadingSkill.cs#L35-L57 |
1 example of 10 | Reproduced with the pattern copied as it is; the chatbot itself was not run; not reported 2026-09-30 |
ga_voice_leading_pair pairs the shorter voicing “against its nearest neighbors”, as its comment says |
It sorts both voicings, pairs them from the bottom and charges 3 semitones per note left over, so an added or dropped bass shifts every voice | CompositionTools.cs#L312-L336 |
Open G → open C: 28 where 10 exists; open G7 → open C: 28 where 8 exists; xx2010 → x32010: 19 where 3 exists. Its live answer for G7 → C ranks first voicings whose extra notes are on top, where pairing from the bottom is right |
Reproduced with the function copied as it is; not reported 2026-09-30 |
VoiceLeadingSpace with transposition but without octave equivalence gives the same distance both ways |
It only tries upward transpositions of 0 to 11 semitones | VoiceLeadingSpace.cs#L46-L61 |
C4 major → B3 major 0, B3 major → C4 major 3; C4 major → C5 major 36, C5 major → C4 major 3, where 0 is right for all four. With octave equivalence, the cyclic-shift shortcut is exact on every pair of 3- and 4-note sets | Reproduced with GA’s file compiled as it is; only tests call the class at a826864; not reported 2026-09-30 |
SetClassOpticIndex.Distance between two set classes of the same size is a voice-leading distance, like the article it cites |
Its comment picks “the nearest-neighbor sum approach (approximation)”: each note goes to the nearest note of the other class, so several voices may share one | SetClassOpticIndex.cs#L53-L76, #L167-L224 |
Over the 144 ordered pairs of the 12 trichord classes: 35 below the one-to-one minimum, 0 above, 70 that change when swapped; (012) → (048) gives 2, (048) → (012) 6, one-to-one 6 | Reproduced with GA’s file compiled as it is; its only caller outside the tests, ShapeGraphBuilder, uses it when VoiceLeadingWeight is above 0, and it defaults to 0; not reported 2026-09-30 |
The citation in SetClassOpticIndex leads to Callender, Quinn and Tymoczko’s article |
It gives Music Theory Online 14(3) and an mtosmt.org link that redirects to the journal’s error page; the article is in Science 320 (2008), doi:10.1126/science.1153021 |
SetClassOpticIndex.cs#L15-L18 |
Link followed on 2026-09-30 | Reproduced, documentation only; not reported 2026-09-30 |
The MCP server’s ga_chord_substitutions ranks a chord’s diatonic substitutes in the key it is given, or in the chord’s own key, as its description shows |
Without a key, the F# closure takes the root’s letter, drops the accidental and assumes major; the example in the tool’s description is wrong on all three chords | DomainClosures.fs#L558, GaDslTool.cs#L212 |
Am is compared with A major, which comes first; F♯m with F major; E♭ with E major. For Am in C major the description says C ★★★, Em ★★, F ★, where the closure gives C ★★, F ★★, Dm ★, Em ★ | Reproduced by rewriting the closure in the course program; the server itself was not run. Unchanged on main (5c3a52a); not reported 2026-10-01 |
| The same closure builds altered and extended chords with all their notes | It reads the quality and the extensions only, from the six-entry table of lesson 9’s ga_common_tones row |
DomainClosures.fs#L85-L98, #L603-L609 |
Bm7♭5 is B D F♯ A, so Dm shares 2 notes with it instead of 3; G9 and G13 are built without their seventh, so they get no tritone substitute | Fixed on GA’s main by #681: the closure takes its notes from chordTones (#L663 at 5c3a52a); read, not run 2026-10-01 |
ChordSubstitutionSkill calls a chord a secondary dominant when it can be one |
The test compares the roots only: a fifth apart is enough | ChordSubstitutionSkill.cs#L262 |
Dm → G and F♯ → Bdim are labelled “Secondary Dominant”, though Dm is minor and a diminished triad cannot be tonicized | Reproduced with the test copied as it is; the chatbot itself was not run. Unchanged on main; not reported 2026-10-01 |
| The skill’s one-chord list ranks substitutes by harmonic closeness, D♭7 among those of G7, as its description promises | Every chord with the same interval-class vector ties at distance 1, because GrothendieckDelta.FromIcVs turns a zero difference into a one, and the stable sort leaves them in 12-bit order: the list is the five smallest numbers of the chord’s set class |
GrothendieckDelta.cs#L125-L131, ChordSubstitutionSkill.cs#L164-L174 |
G7: Dm7♭5, A♭7, F7, D7, E♭m7♭5; D♭7 is 19th of 155. Dm7♭5 comes first for all 12 dominant sevenths; Em7 and Am7 are not listed for Cmaj7. The same zero-to-one makes C “ICV Neighbor (L1 = 1)” of itself. GaApi serves this logic as its own ga_chord_substitutions |
Reproduced with GA’s GrothendieckService compiled as it is and the skill’s selection copied; the chatbot itself was not run. Unchanged on main; not reported 2026-10-01 |
| The skill’s twelve example prompts reach the path they illustrate | “Alternative chord for F major in C” compares F with C; “Borrow a chord from parallel minor” has no chord symbol, and the skill answers “Could not identify a chord symbol in your message.” | ChordSubstitutionSkill.cs#L35-L55, #L144-L160 |
2 examples of 12 | Reproduced with the pattern copied as it is; the chatbot itself was not run; not reported 2026-10-01 |
get_borrowed_chords spells and labels borrowed chords as the textbook does |
It finds the course’s 18 chords for C major, but spells every black-key root with a sharp, writes the numerals without ♭ and credits each chord to the first mode of its loop | ContextualChordService.cs#L93-L109, #L137, #L157-L170 |
D♯ “III”, A♯ “VII”, G♯ “VI”; C♯ and D both “II”; C minor spelled C D♯ G; B♭ and G minor credited to Dorian, the parallel minor left with D diminished | Reproduced with the service compiled as it is; neither the MCP tool nor GaApi was run. Unchanged on main; not reported 2026-10-01 |
ModalInterchange.yaml names the borrowed chords right |
4 of its 13 spelled chords and 3 of its 6 chromatic numerals are wrong, and its text reaches YamlKnowledgeLoader, whose entries YamlKnowledgeSyncService would store with embeddings if any host registered it |
ModalInterchange.yaml#L271-L362, #L616-L619, #L826-L875, YamlKnowledgeLoader.fs#L128-L140, YamlKnowledgeSyncService.cs#L8-L25 |
VI F major, VII G major and III C major are A minor’s own chords, not borrowed from A major; “bii°, Bb diminished” is not in A Phrygian; ♭VI+, iv+ and melodic minor’s vii°7 are not in their modes. The loader returns the file’s 8 entries with those strings | Reproduced, the loader compiled as it is; at a826864 no host registers the sync service and no code reads the collection; not reported 2026-10-01 |
YamlKnowledgeLoader loads every content YAML of the configuration directory |
It skips SpecializedTunings.yaml, which does not parse, and says so on standard error only |
YamlKnowledgeLoader.fs#L116-L118 |
“While parsing a flow sequence, did not find expected ‘,’ or ‘]’.” | Seen in the course program’s run; the file itself was not examined 2026-10-01; GA PR #808 makes it parse, and the loader reads 21 entries from it 2026-10-04 |
Modes.yaml declares the interval-class vector of each family |
9 of the 18 declared vectors are not the vector of the family’s notes, and GetAllModes gives every mode its family’s declared vector |
Modes.yaml#L201-L202, #L248-L249, ModesConfig.fs#L281 |
Harmonic minor declares <2 4 3 5 4 3> for <3 3 5 4 4 2>, melodic minor <2 4 5 3 6 2> for <2 5 4 4 4 2>, chromatic <11 11 11 11 11 6> for <12 12 12 12 12 6>; also major pentatonic, whole tone, diminished, blues, augmented triad and major seventh chord |
Reproduced with ModesConfig compiled as it is 2026-10-01. On main 75959835, 2 of the 18 still differed; GA PR #818, not merged yet, corrects the Augmented Triad family’s and leaves the Major Seventh Chord family’s 2026-10-04 |
The members of a Modes.yaml family are the rotations of its first mode |
60 of the 134 members do not have its vector | Modes.yaml, #L242-L247, #L465-L466 |
Whole families: Major Seventh Chord 7 of 7 (seven kinds of seventh chord), All Interval Tetrachord 15 of 15, Hungarian Major 6 of 6, In Sen 4 of 4. The Diminished Triad’s “first inversion”, C E A, is A minor; the Ultralocrian is spelled like the altered scale, with B♭ for B♭♭ | Reproduced 2026-10-01. On main 75959835, 26 of the 134; GA PR #818, not merged yet, gives each triad inversion the notes of its name and leaves 22, without touching the Major Seventh Chord and All Interval Tetrachord families 2026-10-04 |
ModesConfig returns the names Modes.yaml writes |
An unquoted name loses everything from “ #“, which YAML reads as the start of a comment | Modes.yaml#L631, #L639, #L655, #L663-L681 |
8 of 165 names. 7 names then belong to more than one mode, and a lookup by name returns the first: “Lydian” is always the major scale’s, never “Lydian #2 #6” or “Lydian #6” | Reproduced by a test added after the first run, in 13e7607 2026-10-01; fix proposed in GA PR #818, not merged yet 2026-10-04 |
TryGetModeByName, behind get_mode_info, finds a mode by its alternate names, as its code tries to |
It runs on GetAllModes, which sets every mode’s alternate names to None |
ModesConfig.fs#L284, #L413-L441 |
0 of 165 modes keep them, where GetModalFamilies keeps 104: “Altered bb7”, “Locrian Natural 6”, “Super Locrian”, “Acoustic Scale” and “Spanish Phrygian” are not found. Three of the names of GA’s own mode classes, “Locrian Natural 2”, “Dorian Sharp 4” and “Lydian Sharp 2”, are not in the file at all, and “Ionian Augmented” finds the Double Harmonic Family’s cut “Ionian Augmented #2”, C D♯ E F G♯ A B |
Reproduced with ModesConfig compiled as it is; the MCP tool was not run 2026-10-01; fix proposed in GA PR #818, not merged yet 2026-10-04 |
TryGetModeByIntervalClassVector, behind the “Scale:” line of ga_chord_to_set and the names of ga_icv_neighbors, names the set it is given |
It returns the first mode whose family declares the vector, so a wrong declaration hides a scale, and a family’s vector always names its first mode | ModesConfig.fs#L443-L458, ChordAtonalTool.cs#L112, #L249 |
Harmonic minor, melodic minor and Cmaj7: nothing. G7 and Bm7♭5: “Major Seventh”. Cm: “Major Triad” | Reproduced with ModesConfig compiled as it is; the MCP tools were not run 2026-10-01. GA PR #818, not merged yet, corrects the Augmented Triad family’s vector, so ga_chord_to_set("Caug") gets the line “Augmented Triad”; the lookup itself is unchanged 2026-10-04 |
IScaleDegreeNaming.ToShortName follows one convention |
Three: degree numbers for major and harmonic major, triad numerals for the minor scales, and iv#4 and IV7 for the fourth degree of harmonic and melodic minor |
MajorScaleDegree.cs#L64-L74, HarmonicMinorScaleDegree.cs#L67-L77, MelodicMinorScaleDegree.cs#L64-L74, HarmonicMajorScaleDegree.cs#L67-L77 |
11 of 35 short names differ from the triad on their degree | Reproduced with GA’s degree types; nothing in GA calls the method at a826864; not reported 2026-10-01 |
PitchClassSet.StepBrightness “measures brightness based on the preponderance of large steps” |
The steps of a set always add up to 12, so the value is 2/n, a function of the number of notes | PitchClassSet.cs#L262-L283, ModalVectorService.cs#L157 |
0.2857 for the 21 modes of major, melodic minor and harmonic minor; 11 values over the 4096 sets, one per size, 4 notes sharing 0.5 with 0 and 1 | Reproduced; it feeds one embedding dimension; not reported 2026-10-01 |
| A brightness measure ranks Lydian above Locrian | IcvBrightness, dimension 21 of the structure vector (index 27 of the full embedding), reads the interval-class vector, which all the modes of a scale share |
TheoryVectorService.cs#L159-L172 |
0.642857 for every mode of major, 0.595238 for melodic minor, 0.571429 for harmonic minor | Reproduced with the method copied as it is; by design, since its comment says it is derived from the vector; not reported 2026-10-01 |
UnifiedModeService.RankByBrightness ranks the modes of a scale |
For harmonic minor it ranks 14 sets, harmonic major’s modes included, because a ModalFamily groups sets by vector |
UnifiedModeService.cs#L228-L242, ModalFamily.cs#L108-L131 |
Harmonic major’s Lydian augmented ♯2 first, with 41; major and melodic minor as the course | Reproduced with the service compiled as it is; only GA’s tests call it at a826864. The cause is Appendix C’s defect 6, a known design 2026-10-01 |
UnifiedModeService.Describe names Messiaen’s mode of a set that is one |
IdentifyMessiaenMode compares the prime form’s id with ids that, for modes 4 to 7, are not prime forms; mode 6’s id is a form of mode 4 |
UnifiedModeService.cs#L136, #L277-L347, UnifiedModeAdvancedTests.cs#L87-L119 |
Modes 1 to 3 found, 4 to 7 not: GA tests 2535, 2275, 3315 and 3055 where the prime forms are 975, 455, 1495 and 2015. GA’s tests for modes 5 to 7 accept Is.Null |
Reproduced with the service compiled as it is; not reported 2026-10-01 |
| GA’s three symmetric mode classes list each distinct mode once, as their comments count them | Items holds one mode per degree, 6, 8 and 6, for 1, 2 and 2 distinct sets; the comments promise two modes for the whole-tone scale and four for the augmented scale |
WholeToneScaleMode.cs#L12, AugmentedScaleMode.cs#L12, ModalCharacteristicIntervalService.cs#L114-L148 |
20 modes, 5 distinct sets. TranspositionCount is right, 2, 3 and 4. ModalCharacteristicIntervalService stores them at overlapping indices, 208 to 215 written twice (read, not run) |
Reproduced with GA’s classes; not reported 2026-10-01 |
DiminishedScaleDegree.ToName names the two diminished scales by their first step |
Scale.Diminished starts with a whole step, and degree 1 is named “Half-whole diminished” |
DiminishedScaleDegree.cs#L47-L52, Scale.cs#L62 |
Degrees 1 and 2 swapped; DiminishedScaleMode.HalfWhole is the whole-half scale. Modes.yaml names the same spellings right |
Reproduced 2026-10-01; fix proposed in GA PR #810, not merged yet 2026-10-04 |
Scale.Tritone is the tritone scale, the notes of the Petrushka chord |
It has A where the tritone scale has B♭, and TritoneScaleMode’s comment describes neither |
Scale.cs#L67, TritoneScaleMode.cs#L11-L14 |
6-Z50 with 12 transpositions and 6 modes, where 6-30 has 6 and 3; GA’s own IsSymmetricSet says False. The comment’s “alternating half steps and minor thirds” is the augmented scale, and its “two distinct modes” fits neither |
Reproduced 2026-10-01; fix proposed in GA PR #810, not merged yet 2026-10-04 |
PitchClassSet.IsMonomodal and the atonal catalog’s IsSymmetric find symmetric sets, as their comments and the embedding dimension “Is Symmetric/Monomodal” say |
Both test a single-member modal family | PitchClassSet.cs#L186-L189, ModalVectorService.cs#L132, Program.cs#L249-L253 |
IsMonomodal: 29 sets, 12 of them single notes, 59 limited sets missed, the octatonic scale of its own comment among them. IsSymmetric: 6 of 200 families, the single note included, 10 limited families missed |
Reproduced; not reported 2026-10-01 |
AtonalChordAnalysisService.IsSymmetricalSet checks “equal divisions of the octave” |
It compares the gaps between sorted pitch classes without closing the circle | AtonalChordAnalysisService.cs#L217-L233, #L151-L183 |
156 sets, all 66 dyads among them, 140 not limited; C D E True, B♭ C D False; 60 limited sets missed. The naming branch that uses it is unreachable, SetClass.IsModal being true for all 4096 sets |
Reproduced with the service compiled as it is, the private method called by reflection 2026-10-01; fix proposed in GA PR #810, not merged yet 2026-10-04 |
ModesSkill lists the modes of limited transposition when asked |
It lists the six IsSymmetric families with a confidence of 1.0, with ProgrammaticForteCatalog’s ordinals as Forte numbers |
ModesSkill.cs#L596-L601, #L687-L705, ForteCatalog.cs#L9-L12 |
A single note listed, the octatonic and hexatonic scales it names left out; “Forte 2-1”, “3-1”, “4-1”, “6-1” for 2-6, 3-12, 4-28, 6-35. The file’s labels agree with ForteCatalog for 4 of 200 families, though its comment forbids surfacing them |
Reproduced by rebuilding the answer from its format and GA’s loader; the chatbot itself was not run. The labels are known: GA #436 moved the generator to ForteCatalog before a826864 and left regenerating the file for later; the list is not reported 2026-10-01 |
| GA’s mode catalogs name the symmetric classes | AtonalModalFamilies.yaml takes names from Modes.yaml families that list a set by mistake; the lookup by vector finds Messiaen’s sixth mode under the octatonic scale’s name |
Modes.yaml#L328-L329, #L531, #L725-L726 |
Messiaen’s fourth mode is “Major Bebop Family”, the diminished seventh “Major Seventh Chord Family”; Messiaen’s sixth mode is “Diminished (Half-Whole)”, and the octatonic scale is found nowhere | Reproduced by a test added after the first run, in 6b4039a; the MCP tool was not run; not reported 2026-10-01 |
Chord.FromSymbol reads the chord symbols that textbooks and GA’s own files write |
Its table knows the extended chords, not the altered chords, sus with an extension, add2, slash chords or most spellings; lower-casing turns CM7 into m7 |
Chord.cs#L110-L141 |
14 of 41 symbols right; 28 rejections, the two words among them; CM7 read as C minor seventh |
Reproduced 2026-10-02. GA PR #820, not merged yet, reads a capital M as major, so CM7 is the major seventh of C; the other spellings are still rejected 2026-10-04 |
ChordSymbolParser parses the chord names of GaApi’s voicing search and of the chatbot |
A suffix not in its table falls to a cascade of Contains tests, then to a major triad; English words that start with A to G parse |
ChordSymbolParser.cs#L98-L140, #L176-L188, ChordSymbolParserTests.cs#L33-L40 |
17 of 41 right, no rejection; C7alt with a perfect fifth, C7#11 with a major seventh, “Can” C major, “Give” G major. GA’s tests check only that a chord comes back |
Reproduced with the parser compiled as it is 2026-10-02; fix proposed in GA PR #820, not merged yet: 41 of 41 right, “Can” and “Give” rejected 2026-10-04 |
ChordFormula.GetSymbolSuffix names the extended chords |
It writes the quality’s letter then the extension, so the major ninth, eleventh and thirteenth lose their “maj” | ChordFormula.cs#L299-L325 |
8 of 11; BasicChordExtensionsService.GenerateChordName, from the same quality and extension, 11 of 11 |
Reproduced at a826864 2026-10-02; already fixed upstream by GA PR #680, merged on 2026-09-17 2026-10-04 |
ChordAlterationService names altered chords |
Functions come from the semitones modulo 12: ♯9 is read as a third, ♯11 and ♭13 as ♭5 and ♯5; one alteration makes a dominant “7alt”, a semitone makes it a ninth chord | ChordAlterationService.cs#L37-L61, #L87-L102, ChordFunctionExtensions.cs#L13-L22 |
None of GA’s own nine altered chords named back; C7(♯9) has “No alterations”; Cdim, Caug, Cm7♭5 and Cdim7 get a (b5) or (#5) |
Reproduced with the service compiled as it is; not reported 2026-10-02 |
ChordTemplateFactory.GenerateAllPossibleChords yields each template once |
It runs GenerateFromAllModalFamilies, then the same three scale groups again |
ChordTemplateFactory.cs#L37-L62, #L93-L115 |
25,900 templates, the second 12,950 a copy of the first | Reproduced 2026-10-02; fix proposed in GA PR #823, not merged yet: 12,950 templates, each once 2026-10-04 |
ga_polychord’s description and AdvancedHarmony.yaml describe polychords |
B major over C is not the Lydian set, and C major over F♯ major makes six pitch classes, not twelve | ChordAtonalTool.cs#L194-L218, AdvancedHarmony.yaml#L101-L104 |
{C, Eb, E, F#, G, B}, 6-Z19, in Lydian ♯2 only; C/F♯ 6-30, the Petrushka chord, as IconicChords.yaml lists it |
Reproduced with the tool’s code copied and its F# closure replaced; not reported 2026-10-02 |
VoicingHarmonicAnalyzer names drop voicings |
One test: raise the lowest note an octave, and answer “Drop-2” when the notes then fit within an octave, nothing otherwise. Close positions, drop 3s and drop 4s come out “Drop-2”; no voicing is ever “Drop-3” | VoicingHarmonicAnalyzer.cs#L46-L58 |
64 of the course’s 128 voicings “Drop-2”, exactly those with at most one dropped voice; among GA’s 687 four-string seventh chords, “Drop-2” on 15 close, 111 drop-2, 92 drop-3 and 46 drop-4 voicings | Reproduced with the analyzer compiled as it is 2026-10-02; fix proposed in GA PR #819, not merged yet 2026-10-04 |
VoicingCharacteristics.IsRootless and IsOpenVoicing describe a voicing |
Analyze passes intervalSpread > 12 and false |
VoicingHarmonicAnalyzer.cs#L38-L40, VoicingCharacteristics.cs#L10-L12 |
112 of 128 “rootless”, all with their root; 672 of 687; lesson 3’s seven open chords; no voicing open | Reproduced; not reported 2026-10-02 |
VoicingFilters selects drop, rootless, shell, closed and open voicings |
Drop3 and Drop2And4 look for labels nothing produces; Rootless, ClosedPosition and OpenPosition inherit the two fields above |
VoicingFilters.cs#L101-L124 |
On the 687: Drop2 264, Drop3 0, Drop2And4 0, Rootless 672, ClosedPosition 687, OpenPosition 0. VoicingIndexingService applies these filters before indexing |
Reproduced with the filters compiled as they are 2026-10-02. GA PR #819, not merged yet, fixes the three drop filters: on the 687, Drop2 111, Drop3 92, Drop2And4 143; Rootless, ClosedPosition and OpenPosition are unchanged 2026-10-04 |
| GA recognizes shells, root, third and seventh | Three rules, none on the chord tones: three or four strings; “rootless” with three pitch classes; “rootless” with three notes | VoicingPhysicalAnalyzer.cs#L126-L131, ChordClassificationEngine.cs#L169-L173, VoicingFilters.cs#L118-L119 |
The fifth-string shells x323xx, x324xx and x313xx pass only the first; lesson 3’s seven open triads get the engine’s shell-voicing |
Reproduced 2026-10-02; fix proposed in GA PR #819, not merged yet 2026-10-04 |
VoicingAnalyzer.AnalyzeEnhanced records a voicing’s tones and guide tones |
It builds new ToneInventory([], false, [], []) for every voicing |
VoicingAnalyzer.cs#L155 |
711 analyses, HasGuideTones never true; AutoTaggingService’s “Shell” depends on it (read, not run) |
Reproduced; not reported 2026-10-02 |
The GuitarCompingRecipes fingerings play the chords they name |
Read low to high on their string sets, as the file’s conventions say, none does; one has five frets for four strings | ChordProgressions.yaml#L461-L577 |
0 of 15; “Cm(maj9)” is a Cmaj7, “Gsus2” a Gsus4. YamlKnowledgeLoader returns all six recipes for retrieval |
Reproduced through YamlKnowledgeLoader; not reported 2026-10-02 |
PHYSICAL_PLAYABILITY_IMPROVEMENTS.md quotes the 5-fret spans GA computes |
Its three spans and its “71.4% larger” match neither GA’s calculator nor the formula; the document presents them as the output of a test, in a file the test project removes from compilation | PHYSICAL_PLAYABILITY_IMPROVEMENTS.md#L45-L50, #L155-L161, GA.Business.Core.Tests.csproj#L47 |
120.11, 85.42 and 70.09 mm against 162.55, 108.49 and 81.27 mm on 648 mm; the low span 100.0% larger than the high one | Reproduced; not reported 2026-10-02 |
ComfortableReachScaleUnits is a reach of four frets |
It is the distance from the nut to fret 4, compared with the span between fretted notes, which counts one fret space fewer | BiomechanicsConstants.cs#L24-L28, PhysicalCostService.cs#L27-L38 |
Five frets from fret 1, ten from fret 12 | Reproduced; not reported 2026-10-02 |
DetectCagedShape names a voicing’s CAGED shape |
It returns null when the first position is muted, before the A and C tests that need it muted, so it can only answer “E-Shape”; its comments read the first position as string 6, which GA numbers string 1 | VoicingPhysicalAnalyzer.cs#L253-L343, #L27 |
In GA’s order, none of the 11 shapes; reversed, the E shape at 13 of 13 frets and nothing else. The tag e-shape fails VoicingFilterEngine’s test for “E” |
Reproduced; not reported 2026-10-02 |
| GA’s playability measures account for barres and for the player’s hand | PhysicalCostService has no barre term; VoicingPhysicalAnalyzer sees no barre in F and calls open C “Intermediate”; BiomechanicalAnalyzer sees barres on open strings and rates F “Very Easy”; none reads HandSize or MaxComfortableStretchMm |
PhysicalCostService.cs#L17-L142, VoicingPhysicalAnalyzer.cs#L105-L112, BiomechanicalAnalyzer.cs#L10-L12, #L153 |
F costs 0.29, the barre shapes of C 0.21 to 0.24; open C 3.50, “Intermediate”; F 0.92 against 0.82 for open C; the same results for the four hand sizes | Reproduced; not reported 2026-10-02 |
Tunings.toml holds GA’s tunings |
No C# or F# code reads it; it repeats the two octave errors of Instruments.yaml; the React component that names it ignores its tunings and dataUrls properties |
Tunings.toml#L364-L366, #L388-L390, HarmonicNavigator3D.tsx#L128-L131 |
15 of 15 entries as in Instruments.yaml; string 2 lowered by 11 semitones in OpenCMajor, by 10 in OpenAMajor |
Reproduced, the file read as text; not reported 2026-10-02 |
ga_easier_voicings offers playable voicings of the chord asked for |
Two shapes of its table play a note outside their chord; under “no-barre” it offers B7 and B5 for Bm and nothing for B♭; its description’s Fsus2 and C/F are not in the table | GuitaristProblemTools.cs#L506-L562, #L574-L577, #L611-L652 |
Gsus4 310013 plays B♭, C5 x3500x B; neither offer for Bm plays D | Reproduced with the table read as text and the course’s reading of the filter; not reported 2026-10-02 |
ga_arpeggio_suggestions pairs each chord with its arpeggio and a mode that fits it, as its description’s example does |
It appends the table’s suffix to the whole symbol and takes the mode from the degree of the root alone; any key word but “minor” means major | GuitaristProblemTools.cs#L409-L412, #L426-L431, #L448-L485 |
“Amm7”, “Dm7m7”, “G77”; A7 in A major gets Ionian, with G outside; an A major chord in C major gets “Am7” and Aeolian, with C♯ outside; the key “Am” is A major | Reproduced with the tool read as text and the course’s reading of lines 426 to 485; the suffix and the degree fixed upstream by GA #626 on 2026-09-24, the key read as before on main c1416eee (read, not run) 2026-10-07 |
ImprovisationSkill.InferQuality reads the quality a chord symbol names |
It lowercases the suffix, so CM7 is a minor seventh, the regression ChordVocabulary’s remarks say they removed; Cmaj7♯5 reads “major 7”, C7♯11, C7♭13 and C7+5 “dominant 7”; Cm6’s arpeggio is named CmMaj7 |
ImprovisationSkill.cs#L323, #L338-L351, ChordVocabulary.cs#L8-L16 |
7 of 31 symbols get a first scale without one of their notes; CM7 gets Cm7, then Dorian, Aeolian and Phrygian, none with E or B | Reproduced, compiled; InferQuality unchanged on main c1416eee; not reported 2026-10-07 |
OutsideNotesSkill.Classify calls a note a tension or an avoid note as chord–scale theory does |
One rule for all twelve notes, a semitone above a chord tone, with no scale: notes outside every scale that fits the chord become tensions, the ♭9 and ♭13 over a dominant avoid notes; its advice calls the major seventh over a dominant an altered tension | OutsideNotesSkill.cs#L20-L28, #L141-L189 |
Over Cmaj7, B♭ “tension: b7” and E♭ “#9”; F♯ over Cm7 and A over Cm7♭5, all outside ImprovisationSkill’s scales for the chord; over A7, D an avoid note but C, a semitone below C♯, a tension |
Reproduced, compiled; Classify unchanged on main c1416eee; not reported 2026-10-07 |
Experiments
Section titled “Experiments”Questions where a measurement could have gone the other way. The first is the course’s own safety net: its theory was written from published definitions, not from GA, so agreeing with GA over all 4,096 sets is evidence about both.
| Question | Hypothesis | Result | Verdict | Where |
|---|---|---|---|---|
| Does the course’s from-scratch Rahn prime form agree with GA’s minimal-id prime form, over the whole space? | Built from Open Music Theory, Wikipedia and OEIS, independently of GA, so agreement was not guaranteed | They agree for every one of the 4,096 sets. GA’s 224 set classes and 352 transposition classes match OEIS A000029 and A000031. Forte’s packing differs from Rahn’s on 6 set classes and 17 of the 352 transposition classes | Confirmed, with the Forte/Rahn gap quantified separately | 2026-09-15 |
| Does climbing GA’s OPTIC ladder one equivalence at a time on a real fingering reach the textbook counts? | Written in advance: it should land on 4096, 352 and 224 | 4096, 352 and 224 | Confirmed | 2026-09-15 |
Does giving Diagrams.Fretboard a tuning parameter change the guitar diagrams it already produced? |
Written in advance: it should not — the guitar is just one tuning among the new ones | The fourteen existing SVG files are byte-identical after the change | Confirmed | 2026-09-15 |
Does GA’s core find the same common tones as the course on lesson 9’s 13 pairs, Cmaj9, Cdim7 and C6 included? |
Written in advance: agreement on all 13 | 13 of 13 | Confirmed | 2026-09-30, Lesson11.cs#L62-L66 |
How often does repeating the smaller chord’s root, as VoiceLeadingSkill does, miss the smallest voice leading? |
Written in advance: G → Cmaj7 gives 5 where 3 exist; more than 10 % of the 2,880 triad → seventh pairs miss, and fewer from seventh to triad | G → Cmaj7: 5 and 3. 1,260 pairs (43.8 %) miss in each direction, by up to 4 semitones | Confirmed for G → Cmaj7 and the share; refuted for the direction: the triad is the padded chord both ways, and a voice leading costs the same read backwards | 2026-09-30, Lesson11.cs#L388-L402 |
| Does each of the skill’s ten example prompts pass its own pattern? | Written in advance: exactly one fails, “voice leading C major to G major” | That one, and no other | Confirmed | 2026-09-30, Lesson11.cs#L404-L409 |
What does ga_voice_leading_pair’s distance give from open G to open C? |
Written in advance: 28, where leaving out the low G gives 10 | 28 and 10 | Confirmed | 2026-09-30, Lesson11.cs#L411-L424 |
Does ProgressionVoiceLeadingAnalyzer agree with the textbook rule, string by string? |
Written in advance: F → G barre, 3 fifths and 4 octaves; E5 → G5, 1 and 1; open C → G and G7 → C, one octave each on strings 5 and 2; Am → Dm, none | As written, 5 of 5 | Confirmed | 2026-09-30, Lesson11.cs#L426-L438 |
Is VoiceLeadingSpace’s cyclic-shift shortcut exact, and what does it give without octave equivalence? |
Written in advance: no disagreement over every ordered pair of 3- and 4-note sets, OP and OPT; without O, C4 major → B3 major 0 and B3 major → C4 major 3 | 0 of 48,400 and 0 of 245,025, with and without T; 0 and 3 | Confirmed | 2026-09-30, Lesson11.cs#L450-L471 |
Does SetClassOpticIndex fall below the one-to-one minimum and change when its arguments are swapped? |
Written in advance: never above, below and asymmetric on some of the 144 trichord pairs; (012) → (048) 2, back 6, one-to-one 6 | 0 above, 35 below, 70 asymmetric; 2, 6 and 6 | Confirmed | 2026-09-30, Lesson11.cs#L473-L486 |
How does the MCP server’s ga_chord_substitutions rank A minor’s substitutes in C major, and which key does it use when given none? |
Written in advance: C and F with 2 shared notes, then Dm and Em with 1, against the description’s C ★★★, Em ★★, F ★; without a key, A major for Am and B major for B♭7; Bm7♭5 built as B D F♯ A | C 2, F 2, Dm 1, Em 1; A major and B major; Dm and Bdim share 2 notes with Bm7♭5 | Confirmed, on a rewrite of the closure | 2026-10-01, Lesson12.cs#L529-L549 |
| Which chords get the closure’s tritone line? | Written in advance: G7 gets D♭7; G9 and G13 get none | As written | Confirmed, on the rewrite | 2026-10-01, Lesson12.cs#L551-L558 |
Which path does each of ChordSubstitutionSkill’s twelve example prompts take? |
Written in advance: ten list substitutes; “Alternative chord for F major in C” compares F with C; “Borrow a chord from parallel minor” finds no chord | As written | Confirmed | 2026-10-01, Lesson12.cs#L560-L568 |
| What are the skill’s five substitutes for one chord? | Written in advance: every chord with the same vector at cost 0.60 and distance 1, in 12-bit order; for G7 Dm7♭5, A♭7, F7, D7, E♭m7♭5; for Am Cm, C, A♭, D♭m, Fm; for C Cm, A♭, D♭m, Fm, D♭; for Cmaj7 D♭maj7, A♭maj7, Fmaj7, Dmaj7, Amaj7 | The four lists as written; 23, 23, 23 and 11 chords tie, as many as the course counts with the same vector | Confirmed | 2026-10-01, Lesson12.cs#L570-L610 |
| Which labels does the skill give G7 → D♭7, Dm → G, C → C and B♭7 → C? | Written in advance: Tritone Substitution, Set-Class Equivalent and ICV Neighbor (L1 = 1); Secondary Dominant; Set-Class Equivalent and ICV Neighbor (L1 = 1); Backdoor Dominant alone | As written; Dm → G also gets the two set-class labels | Confirmed | 2026-10-01, Lesson12.cs#L612-L616 |
What does get_borrowed_chords return for C major? |
Written in advance: 18 chords credited to the first mode that has them, roots spelled with sharps, numerals without accidentals, each listed by mode | The 18, in that order, with those numerals | Confirmed | 2026-10-01, Lesson12.cs#L618-L641 |
How much of ModalInterchange.yaml is right, and does any GA code read it? |
Written in advance: 9 of 13 spelled chords right, 3 of 6 chromatic numerals wrong; no code reads the file | 9 and 4; 3 of 6; YamlKnowledgeLoader reads it with the other content YAML files, and YamlKnowledgeSyncService would store the entries with embeddings, though no host registers it |
Confirmed for the chords and numerals; refuted for the readers | 2026-10-01, Lesson12.cs#L643-L675 |
Do GA’s ModeFormulas for the seven modes of melodic minor match the course’s? |
Written in advance: 7 of 7, GA’s scale spelled from A | 7 of 7, and the 7 spellings | Confirmed | 2026-10-01, Lesson13.cs#L136 |
| And for harmonic minor, double flat included? | Written in advance: 7 of 7; Lydian ♯2 measured against Ionian, and the seventh of the altered ♭♭7 a diminished seventh | 7 of 7, with >♯2 and >bb7 |
Confirmed | 2026-10-01, Lesson13.cs#L137 |
| How many of the 35 short names of five degree types differ from the triad on their degree? | Written in advance: 11; 4 for major, 5 for harmonic major, 1 each for harmonic and melodic minor, none for natural minor | 11, degree for degree | Confirmed | 2026-10-01, Lesson13.cs#L139-L155 |
Does StepBrightness tell modes apart? |
Written in advance: no; 0.2857 for all 21 modes, and 11 values over the 4096 sets | As written | Confirmed | 2026-10-01, Lesson13.cs#L157-L184 |
Does IcvBrightness tell modes apart? |
Written in advance: no; 0.642857, 0.595238 and 0.571429, one value per scale | As written | Confirmed | 2026-10-01, Lesson13.cs#L157-L172 |
Does RankByBrightness rank the modes of a scale as the course’s sum does? |
Written in advance: yes for major and melodic minor; for harmonic minor 14 sets, Lydian augmented ♯2 first with 41, and three ties in 12-bit order | As written | Confirmed | 2026-10-01, Lesson13.cs#L186-L216 |
How many of the vectors Modes.yaml declares are right, and how many members have their family’s vector? |
Written in advance: 31 families, 165 modes, 9 of 18 declared vectors wrong, 60 of 134 members without it; the Ultralocrian spelled like the altered scale | As written. GA and the course compute the same vector for the notes of 164 of the 165 modes, the chromatic scale aside | Confirmed | 2026-10-01, Lesson13.cs#L218-L259 |
What do ModesConfig’s two lookups find? |
Written in advance: by vector, Ionian for C major, nothing for harmonic minor, melodic minor and Cmaj7, “Major Seventh” for G7 and Bm7♭5, “Major Triad” for C and Cm; by name, 8 of GA’s 14 names and no alternate name | The vectors as written. 9 names: “Ionian Augmented” is found in the Double Harmonic Family, through a name cut by a YAML comment. No alternate name | Confirmed for the vectors and the alternate names; refuted for the number of names found | 2026-10-01, Lesson13.cs#L261-L295 |
How many sets have limited transpositions, and does IsSymmetricSet find them? |
Written in advance: 76 sets in 17 transposition classes, 15 without the empty set and the chromatic scale; Messiaen’s transpositions and modes as his list gives them; agreement on all 4096 sets | 76, 17 and 15, in 14 set classes; 7 of 7 modes; 4096 of 4096 | Confirmed | 2026-10-01, Lesson14.cs#L158-L194 |
| How many distinct modes do GA’s three symmetric mode classes hold? | Written in advance: 6, 8 and 6 modes for 1, 2 and 2 sets on C, with the transpositions right, 2, 3 and 4 | As written | Confirmed | 2026-10-01, Lesson14.cs#L216-L218 |
| Are the names of the two diminished scales the right way round? | Written in advance: swapped, degree 1 being the whole-half scale | Swapped | Confirmed | 2026-10-01, Lesson14.cs#L220-L226 |
Is Scale.Tritone the tritone scale? |
Written in advance: no; 6-Z50 with 12 transpositions and 6 modes, where the tritone scale is 6-30 with 6 and 3 | As written; GA’s IsSymmetricSet False for GA’s scale, True for the tritone scale |
Confirmed | 2026-10-01, Lesson14.cs#L228-L242 |
Which of Messiaen’s modes does IdentifyMessiaenMode name? |
Written in advance: modes 1 to 3 only | Modes 1 to 3 only | Confirmed | 2026-10-01, Lesson14.cs#L196-L212 |
How many sets does IsMonomodal flag, and how many have limited transpositions? |
Written in advance: 29, 17 of them limited, the octatonic scale not among them | As written | Confirmed | 2026-10-01, Lesson14.cs#L246-L262 |
What do AtonalModalFamilies.yaml and ModesSkill call symmetric, and do the file’s Forte labels agree with ForteCatalog? |
Written in advance: 6 of 200 families; Forte 2-1, 3-1, 4-1 and 6-1 in the answer; no agreement for 2, 3, 4, 8, 9 and 10 notes, agreement for 1-1, 11-1 and 12-1 | As written; one hexachord family agrees too, 4 of 200 in all | Confirmed | 2026-10-01, Lesson14.cs#L266-L302 |
How many sets does IsSymmetricalSet flag? |
Written in advance: 156, 16 of them limited, 60 limited sets missed; C D E flagged, B♭ C D not | As written | Confirmed | 2026-10-01, Lesson14.cs#L246-L263 |
Does IsInversionallySymmetric agree with the course’s mirror axes, and do the limited classes have as many axes as fixing transpositions? |
Written in advance: 352 classes, 96 symmetric; 13 of the 15 limited classes mirror-symmetric, 6, 4 and 3 axes for the whole-tone, octatonic and augmented scales | As written, and no set anywhere with axes in another number | Confirmed | 2026-10-01, Lesson14.cs#L306-L330 |
| What do GA’s two parsers make of 41 chord symbols? | Written in advance: FromSymbol 14 right, 26 chords rejected, CM7 a minor seventh; ChordSymbolParser 17 right, nothing rejected, each misreading named, “Can” C major and “Give” G major |
As written | Confirmed | 2026-10-02, Lesson15.cs#L313-L336 |
| Do GA’s three ways of naming read the extended chords back? | Written in advance: TryFindExact nothing for C13, Cmaj13, Cm13 and Cmaj11; GetSymbolSuffix without the “maj” of maj9, maj11 and maj13; GenerateChordName all eleven; C13, Fmaj13 and Gm13 one set |
As written | Confirmed | 2026-10-02, Lesson15.cs#L273-L301 |
What does ChordAlterationService call GA’s nine altered chords? |
Written in advance: C9(b9,b5,#5), C9(b9), C7, four C7alt, C9(b9,b5), Cmaj7(b5); Cdim(b5), Caug(#5), Cdim7(b5), C6(b5) |
As written | Confirmed | 2026-10-02, Lesson15.cs#L340-L363 |
Which alterations do ChordTemplateFactory’s templates carry? |
Written in advance: every template twice; ♭13 never; ♯9 only in Sus2 templates, ♯11 only in Sus4 templates | As written: 80 and 176 templates | Confirmed | 2026-10-02, Lesson15.cs#L367-L382 |
What does ga_polychord print, and which modes contain each polychord? |
Written in advance: {C, Eb, E, F#, G, B} for B over C; Bm/C in Lydian only, B/C in Lydian ♯2 only; C over F♯ six notes, 6-30, in none of the 28 modes and in the half-whole octatonic; D over E♭ in Lydian ♯2 only; C over D A C D E F♯ G |
As written | Confirmed | 2026-10-02, Lesson15.cs#L406-L426 |
What does YamlKnowledgeLoader return from ExtendedChords.yaml and AdvancedHarmony.yaml? |
Written in advance: 3 and 9 entries; the 13th chord 1 3 5 ♭7 9 13; “Polychords” with twelve chromatic pitches | As written | Confirmed | 2026-10-02, Lesson15.cs#L430-L449 |
| Which triads over C7 avoid F and B, and does GA’s catalog name them? | Written in advance: 6 major and 6 minor, Wikipedia’s nine upper structures plus C, Gm and Am; no pattern in the catalog | As written; none of the 62 patterns is named upper structure or polychord | Confirmed | 2026-10-02, Lesson15.cs#L386-L402 |
What does DetectDropVoicing call the 128 drop voicings of the four seventh chords on C, and Wikipedia’s examples? |
Written in advance: “Drop-2” for the 64 close, drop-2, drop-3 and drop-4 voicings, nothing for the 64 others; nothing for Wikipedia’s seven examples | As written | Confirmed | 2026-10-02, Lesson16.cs#L173-L215 |
What do IsRootless and IsOpenVoicing say, and which guitar shapes are “Drop-2”? |
Written in advance: 112 rootless, none open; lesson 3’s seven open chords rootless, three of them “Drop-2”; x3200x “Drop-2” and not rootless, x3545x “Drop-2” and rootless | As written | Confirmed | 2026-10-02, Lesson16.cs#L219-L232 |
| Which voicings does each of GA’s three shell rules recognize? | Written in advance: the string rule the six shells, xx0232 and both Cmaj7 shapes; the engine the three sixth-string shells and the seven open triads; the filter the three sixth-string shells only | As written | Confirmed | 2026-10-02, Lesson16.cs#L236-L252 |
How many voicings does VoicingGenerator return, and what do GA’s label and filters make of the seventh chords among them? |
Written in advance: 667,125; “Drop-2” exactly on the close, drop-2, drop-3 and drop-4 voicings; MUS-005’s 48 drop-2 and 32 drop-3 shapes all present; Drop2 the close and single-drop voicings, ClosedPosition all, Rootless those over an octave, the others none |
As written: 687 voicings, 264 kept by Drop2, 672 by Rootless |
Confirmed | 2026-10-02, Lesson16.cs#L256-L333 |
Do the ii–V–I rows of TransposeTables show the guide-tone moves, and does GA’s analysis record guide tones? |
Written in advance: the four moves in all twelve rows, F F E and C B B in C; HasGuideTones false and Tones, OmittedTones empty for every voicing analyzed |
As written, over 711 analyses | Confirmed | 2026-10-02, Lesson16.cs#L337-L369 |
| Do the comping recipes reach retrieval, and do their fingerings play their names? | Written in advance: the six recipes returned with their fingerings; no fingering with the notes of its name or degree order; the blues recipe’s E7 right | As written; 36 entries from the file | Confirmed | 2026-10-02, Lesson16.cs#L373-L408 |
Where do GA’s two geometry classes put the frets, and are the spans quoted in PHYSICAL_PLAYABILITY_IMPROVEMENTS.md right? |
Written in advance: both agree with the course at every fret, fret 12 at 323.85 and 324.00 mm; MUS-009’s five figures; three DIFF rows, 162.55, 108.49 and 81.27 mm, the low span 100.0% larger, not 71.4% |
As written | Confirmed | 2026-10-02, Lesson17.cs#L185-L210 |
| How far does GA’s comfortable reach go, and does any measure read the player’s hand? | Written in advance: frets 1 to 5 from fret 1, 7 to 13 from fret 7, 12 to 21 from fret 12; the first position at 0.1502; the default profile’s Medium hand and 129 mm, which none of the three analyzers reads | As written | Confirmed | 2026-10-02, Lesson17.cs#L214-L226, Lesson17.cs#L334-L337 |
Where do the five CAGED shapes of C sit, and does DetectCagedShape name them? |
Written in advance: frets 0, 3, 5, 8 and 10, in every key the order C A G E D read round from one of its letters; in GA’s string order no shape named, 001220 named “E-Shape”; reversed, the E shape at every fret and nothing else | As written: the E shape at all 13 frets | Confirmed | 2026-10-02, Lesson17.cs#L230-L302 |
| What do GA’s three cost and difficulty measures make of the shapes? | Written in advance: no barre term; from −0.63 (Em) to −0.06 (D), F 0.29, the D shape of C 0.59, the E shape at fret 12 0.66; open C “Intermediate”; F “Very Easy” (0.92) above open C (0.82) for BiomechanicalAnalyzer; hand sizes and profile fields without effect; the D shape of C 1.04 under Beginner(), 0.18 under Jazz() |
As written | Confirmed | 2026-10-02, Lesson17.cs#L306-L347 |
Do the guitar tunings of Tunings.toml match Instruments.yaml, and does any GA code read the file? |
Written in advance: the same 15 entries, string 2 of OpenCMajor and OpenAMajor lowered by 11 and 10 semitones as in Instruments.yaml; OpenEMajorV2 an E minor chord; Wikipedia’s four string orders; no reader in GA’s C# or F# |
As written; the readers checked by searching the code, not by running it | Confirmed | 2026-10-02, Lesson17.cs#L351-L372 |
Are the 41 voicings behind ga_easier_voicings right, and what does it offer for a barre chord? |
Written in advance: Notes right for all 41; a B♭ in Gsus4, a B in C5, C7 without G; five HasBarre; Fmaj7 for F and F5, B7 and B5 for B and Bm, nothing for B♭; Fsus2 and C/F not in the table |
As written | Confirmed | 2026-10-02, Lesson17.cs#L376-L406 |
Do GA’s arpeggio tables, ArpeggioFor and GA’s modes give the seventh chord and the mode on each degree? |
Written in advance: all fourteen suffixes and symbols; the modes and intervals of both tables and MajorScaleMode right; ten of the twelve other scales, the two diminished modes DIFF |
As written | Confirmed | 2026-10-07, Lesson18.cs#L270-L315 |
What does ga_arpeggio_suggestions return when the request names its key? |
Written in advance: “Amm7”, “Dm7m7”, “G77”, “Cmaj7maj7”; the mode from the root’s degree, so Ionian for A7 in A major and Aeolian for an A major chord in C major; a key “Am” read as A major; B♭ in C major chromatic | As written; GA #626 had already fixed the suffix and the degree upstream | Confirmed | 2026-10-07, Lesson18.cs#L317-L341 |
Does the first scale ImprovisationSkill offers hold the chord, over 31 symbols on C? |
Written in advance: all but seven, CM7 read as a minor seventh, Cmaj7♯5, C7♯11, C7♭13, C7+5, C7♭9 and C7♯9; 16 of 17 example prompts accepted; F, C and G Ionian over Am F C G; G/A read as G and A | As written | Confirmed | 2026-10-07, Lesson18.cs#L343-L368 |
Which notes does OutsideNotesSkill.Classify call avoid notes and tensions over Cmaj7, C7, Cm7 and Cm7♭5? |
Written in advance: the notes a semitone above a chord tone avoid notes, D♭, F and A♭ over Cmaj7; five tensions in none of ImprovisationSkill’s scales; seven of ten example prompts answered |
As written | Confirmed | 2026-10-07, Lesson18.cs#L370-L395 |
Does Classify agree with GAA-003 on A minor pentatonic over Am7 and A7? |
Written in advance: agreement over Am7; over A7, D an avoid note but C a tension; the three notes that pull a mode away avoid notes; the targets C♯, F♯ and G♯ | As written | Confirmed | 2026-10-07, Lesson18.cs#L404-L419 |
| What do GA’s improvisation entries hold, and are GAA-003’s box 1 and modes right? | Written in advance: four entries with an empty category, none pairing a chord with a scale; box 1 A C D E G, GA’s fifth mode of the major pentatonic; the three modes spelled right | As written | Confirmed | 2026-10-07, Lesson18.cs#L421-L448 |
2026-09-21 — Appendix C reconciled upstream
Section titled “2026-09-21 — Appendix C reconciled upstream”- GA #711 reconciled the executable Appendix C findings and was merged as
b363c3f. - Defects 1–5, 7–11 and 13–18 are fixed with regression coverage. Entries 6, 12 and 19 remain documented design or representation boundaries.
- The course stays pinned to
a826864so the original 40DIFFrows remain reproducible; the appendix now links the newer upstream outcome instead of rewriting that historical evidence.
2026-09-18 — Upstream GA fixes: resolving the findings
Section titled “2026-09-18 — Upstream GA fixes: resolving the findings”- 16 of the 19 defects resolved upstream in GA:
- Notes & pitch parsing:
Pitch.Flatfactories (DFlat,FFlat,GFlat,EFlat,BFlat) corrected;PitchParseranchored regexes with compiled static patterns;Note.Flat.TryParsefixed so natural B parses as B (not B♭) and Unicode♭is handled without case mutation;PitchClass.TryParseSetNotationseparated fromTryParse;SimpleIntervalSize.TryParseandCompoundIntervalSize.TryParsereturnfalseon invalid inputs instead of throwing. - Chords & voicings:
ChordFormulaquality and suffix classification updated (dim7 distinguished from 6th/13th,m7b5anddim7preserved); spelling-aware interval transposition added toChordconstructor; originalRootandFormulapreserved across chord inversions;Voicing.HasBarre()open strings (fret 0) excluded. - Keys & tonality:
KeyTools.GetParallelKeypreserves tonic with opposite mode;KeyTools.GetNeighboringKeysuses signature count lookup;Key.GetIntervalroot-to-note argument order restored;Key.Major.TryParsereturnsfalseon invalid root;HarmonicFunction.Subtonicenum member added;Cadences.yamliiiRoman numeral fixed in E Minor. - Defect 12 (ICV packing base 12) remains pinned to preserve existing catalog numbering; defect 6 (ModalFamily) and defect 19 (ClosestDiatonicKey tonic ambiguity) documented as design/heuristic limitations.
- Notes & pitch parsing:
2026-09-15 — A verdict on every divergence, the ukulele and the bass, three appendices
Section titled “2026-09-15 — A verdict on every divergence, the ukulele and the bass, three appendices”- All 40
DIFFrows of lessons 1 to 7 now have a verdict, in Appendix C: 39 are GA’s bug, one (PitchClass.Parse("A")) is a defensible convention with a precedence flaw underneath, and none is an error in the course. They come from 19 distinct defects — one wrong line inNote.Chromatic.ToAccidentedaccounts for eight rows on its own — and they fall into three families: copy-paste inside a block of near-identical members, a reduced type asked for the information it was built to discard, andTryParsethat throws. - Nine sentences across lessons 1, 2, 3, 4, 6 and 7 presented a divergence as a matter of taste and now give the verdict. The worst of them was lesson 2’s “Neither answer is wrong” about
ModalFamily: a mode is a rotation, a scale has as many modes as it has notes, and Ian Ring’s pages answer 7 and 6 where GA answers 14 and 24. - Lesson 8, the ukulele and the bass. Two facts that guitar-shaped code gets wrong: a ukulele is re-entrant (its fourth string is higher than its third), and a bass is tuned entirely in fourths (it has none of the guitar’s one irregular pair). A ukulele’s gaps are 5 4 5, the same as the guitar’s top four strings; a baritone ukulele is those four strings; a bass is the bottom four, an octave down.
Tuning.BuildPitchArraydecides which end of a tuning is string 1 by comparing the first pitch with the last one only. That works on any tuning that rises or falls all the way. On GA’s own two 5-string banjo tunings, whose short drone string is written first and sounds higher than the last string, it keeps the file’s order and numbers the strings backwards.Str’s comment, “String 1 is the string with the highest pitch”, cannot hold for that instrument: string 1 is D4 and string 5 is G4.Fretboard.GetNotedocuments its first parameter as “Zero-based string index (0 = lowest string)” and then indexesTuning[stringIndex + 1], where string 1 is the highest. The comment is wrong, not the code.- Appendix A:
InstrumentsConfigreturns one instrument. The course program now referencesGA.Business.Configand callsgetAllInstruments()on the same run that reads the file itself: the file holds 122 instruments and 280 tunings, the loader returns 1 and 2.InstrumentsYamlexpects a document with anInstruments:list of{ Name, Tunings }; the file is a mapping of instruments, each a mapping of tunings, with noInstrumentskey anywhere. Both the null check and thewith _ ->handler fall back todefaultData (), two hard-coded guitar tunings. Nothing fails and nothing logs. - Seven of the 280 tunings are not pitches: two pedal steel entries begin with their tuning’s name (
C6,E9), one begins with the literal wordTuning, one is the instrument’s own name, one is missing an octave, and the two harp guitars use|to separate the sub-bass strings. The same name-as-a-pitch slip produced the ukulele’s five-pitch tunings, which parse silently. - Appendix B: the OPTIC hierarchy. One fingering climbed to a set class, one equivalence at a time, with GA’s type at each rung —
PitchClassSetafter O, P and C,TranspositionClassafter T,SetClassafter I — and the counts 4096, 352 and 224 agreeing with the course. GA’s OPTIC-K embedding schema splits the same ladder in two: STRUCTURE (dimensions 6-29, weight 0.45) is “pitch-class set invariants (O+P+T+I)”, MORPHOLOGY (30-53, weight 0.25) is “physical fretboard realization”, which is everything the ladder discards. The weights and ranges are read from the skill document, not run: to verify. - The appendix also explains Ian Ring’s scale finder as the ladder made clickable — Rotate is T, Reflect is I — and Harmonious as the same material seen from the other end, by key and by chord rather than by set number.
- The course program grows to ten entry points (
l1tol10), all incheck.sh.Diagrams.Fretboardnow takes a tuning, so the ukulele and the bass get their own fretboard diagrams; the fourteen existing SVG files are byte-identical after the change. - You can hear the lessons now. A ```play code block becomes a player: the pitches on one line sound together, one line after another. The samples are one recorded note per semitone of FluidR3_GM’s nylon acoustic guitar, pinned on one commit of
gleitz/midi-js-soundfontsand fetched on the first click — nothing is synthesised, no audio file is stored here, and every note is a sample played at its own pitch. Standard tuning is in lesson 1, C ionian against C dorian in lesson 2, the four voicings in lesson 3, ii–V–I in lesson 7, and the guitar shape against the same fingers on a ukulele in lesson 8. The block is code, so it is identical in the three languages; only the button’s label follows the page.
2026-09-14 — Pinning GA and building against it
Section titled “2026-09-14 — Pinning GA and building against it”- GA is pinned on
a826864(chore(quality): snapshot 2026-09-14), the head ofmainon the day. The author’s local clone of GA is never used or modified:fetch-ga.shmakes its own clone incode/music-theory-ga/.ga, ignored by Git. - The clone is blobless (
--filter=blob:none) with a non-cone sparse checkout of/Directory.Build.props,GA.Core,GA.Business.ConfigandGA.Domain.Core: Git downloads only the contents of those files at checkout.GA.Domain.Corereferences the two others;GA.Business.Configis an F# project, which the .NET SDK builds without extra setup. - In Git Bash on Windows, the sparse patterns starting with
/were rewritten into Windows paths (C:/Program Files/Git/Common/...) and matched nothing.MSYS_NO_PATHCONV=1fixes it. - A
git grepover the blobless clone hung: it fetched every blob of the repository one by one. Reading single files withgit show HEAD:<path>fetches only those. - The course project references GA with a plain
ProjectReference(GaTheory.csproj). Local build of GA’s three projects plus the course: 5 to 13 seconds after the first restore. - CI run 34903462624, for the push that contained commit
79d2198: green on the three OSes, 34 s on Linux, 47 s on macOS, 67 s on Windows, clone included.
2026-09-14 — Verifying the theory
Section titled “2026-09-14 — Verifying the theory”- The course’s
Theory.csis written from the textbook definitions only, then compared with GA. Sources: Open Music Theory (chapters listed in each lesson), Wikipedia (MIDI tuning standard, Guitar tunings, Guitar chord, Blues scale, Interval vector, List of set classes), Ian Ring’s scale 2741, OEIS A000029 and A000031. - The Open Music Theory site and OEIS answer 403 to plain HTTP clients; the chapters were read in a browser.
- Checked in bulk on all 4096 sets: the course’s Rahn prime form equals GA’s minimal-id prime form for every set; 224 set classes and 352 transposition classes, as OEIS says. Forte’s and Rahn’s packings differ on 6 set classes, and on 17 of the 352 transposition classes, the figure List of set classes gives (the 17 were computed with the same algorithm outside the program).
- Bugs found in the course program itself while writing: the empty set crashed the prime-form sort key; the barre rule first counted open strings, copying GA; the voicing
x02010was first named C6/A until the namer tried the bass as the root first.
2026-09-14 — Differences in GA’s code (commit a826864)
Section titled “2026-09-14 — Differences in GA’s code (commit a826864)”Kept as DIFF lines in the expected outputs, so that CI notices when GA changes. None was reported upstream.
Lesson 1, notes:
Pitch.Flat.DFlat(octave),FFlatandGFlatbuild D, G and A (Pitch.cs#L285-L295).PitchParser’s regex has no anchors and ignores case:Pitch.Sharp.TryParse("Eb2")succeeds with B2.Note.Flat.Parse("B")is B♭: the parser upper-cases, then reads a trailingBas a flat.PitchClass.Parse("A")is 10 (hexadecimal-style digit, on purpose), while the note A is 9.SimpleIntervalSize.TryParsethrows instead of returningfalse.Fretboard.GetPositionsForNote(Note.Sharp.C)finds nothing: positions holdNote.Chromatic, and records of different types are never equal.- Minor, no visible effect:
ValueObjectUtils.IsValueInRange(..., normalize: true)computescount = max - minand adds 1 after the modulo, unlikeEnsureValueRange; with normalization both always end in range (ValueObjectUtils.cs#L69-L92).
Lesson 2, scales:
ModalFamilygroups the sets containing 0 by interval-class vector, not by rotation: 14 “modes” for harmonic minor (its own 7 and harmonic major’s), 24 for blues (with its inversion and a Z-related class). Not a bug, but the name suggests rotations.- The minor scales are spelled from A, so
Scale.NaturalMinorhas the id of C major (2741). Expected for a pitch-class set, surprising next to the other scales, spelled from C.
Lesson 3, chords:
ChordFormula.DetermineQualitynever returnsMajor7,Minor7,HalfDiminishedorDiminished7, soGetSymbolSuffixgives7for maj7,dim7for m7♭5 anddim6for dim7.- The
Chordconstructor spells every non-root note with sharps:Eb→Eb G A#,Gb7→Gb A# C# E. Chord.AnalyzeChordFormulaskipsNotes[0]as if it were the root; afterToInversion(1)it is the bass, the third is lost and the quality isOther.Voicing.HasBarrecounts open strings: open C with a low E, open E and open G are “barre” chords.- GA’s voicing diagrams start at string 1 (high E), the reverse of chord charts.
CanonicalChordPatternCataloglists four interval sets twice (9-sus4/dominant-11,major-6-add-9/6-9,minor-6-add-9/minor-6-9,augmented-7/dominant-7-sharp-5);TryFindExactcan never return the second name of each pair.- The catalog matches intervals from the lowest note in the course’s usage, so an inversion such as
032010(C/E) has no name.
Lesson 4, set classes:
IntervalClassVectorIdpacks the counts in base 12; the chromatic scale’s counts of 12 overflow and decode to<1 1 1 1 0 6>.CanonicalForteCatalogdescribes its data as “the standard Forte-column values”, but stores Rahn’s spellings for the disputed classes (5-20 01568,6-Z29 023679), like Open Music Theory’s table. The labels are right; only the comment is imprecise.GrothendieckDelta.FromIcVsturns a zero difference intoIc1 = 1on purpose, so sets with the same vector are reported at distance 1, and a triad’s “neighbours at distance 1” are the other major and minor triads, itself included.
2026-09-14 — GA’s MCP server
Section titled “2026-09-14 — GA’s MCP server”Called from this session through the GA MCP server (the server does not report a version; it may not run commit a826864). The code references are to a826864.
ga_set_class_subs("Am")and("G7"): the right lists (all major and minor triads; all dominant and half-diminished sevenths), but every chord under[maj](c.EndsWith("")inChordAtonalTool.cs#L187-L190), and a description saying “Am and C are NOT equivalent”.ga_chord_intervals:Cm7b5→ P1 m3 P5 m7,G7b9→ P1 M3 P5 m7,C9→ P1 M3 P5 M9,Cmaj9→ P1 M3 P5 M9. The F# closure keeps one interval per extension and ignores alterations (DomainClosures.fs#L85-L98).ga_parse_chord("Cm7b5")did parsealt:b5.ga_chord_to_set, which takes its pitch classes from the same closure:Cm7b5→{C, Eb, G, Bb}, 4-26 (should be 4-27, with G♭);Cdim7→{C, Eb, F#, Bb}, 4-27, “Scale: Major Seventh” (should be 4-28, with A);C→ 3-11, prime0 3 7, a modal family of 6.ga_icv_neighbors("C", 1): twelve identical lines<0 0 1 1 1 0> Δ=1 Forte:3-11 [Major Triad], explained by the zero-delta rule above.ga_scale_by_id(2741): Major, withForte Number: Some(n/a)(7-35 expected).ga_scale_by_name("Dorian"): not found.get_tuning(Guitar, Standard): E2 A2 D3 G3 B3 E4, right.get_chord_voicings("C", maxFret 3): “An error occurred”.ga_search_voicings("C major open chord"): the “open” constraint was ignored (diagram8-8-x-x-7-x, labelled C/E).
2026-09-14 — Notes on the Streeling modules
Section titled “2026-09-14 — Notes on the Streeling modules”The modules are generated from GuitarAlchemist/Demerzel and were not modified; lessons link them where they help.
- MUS-006, “Modes as Rotations”: a circular left shift of the id transposes (C major shifted by 2 is D major, 2774); getting D Dorian on C needs the opposite shift (1709). The practice answer “rotate left by 2 semitones → 2nd mode” has the same direction problem.
- MUS-006 says Forte “identified 224 distinct set classes for cardinalities 3 through 9”; 224 counts all cardinalities from 0 to 12.
- MUS-002 derives the prime form of the open strings (E A D G B) as
[0,2,5,7,9], comparing pitch classes instead of intervals in the tie-break; the prime form is(02479). The same module answers “are major and minor triads different set classes? Yes”, then puts both in 3-11, and writes prime forms in square brackets where Open Music Theory uses parentheses. - GTR-002 labels the C shape
x 3 2 0 1 0with “Strings: 5-4-3-2-1”: six symbols for five strings, thexbeing string 6.
2026-09-15 — Diagrams
Section titled “2026-09-15 — Diagrams”- The diagrams are SVG files written by the course program (
Diagrams.cs) intosrc/assets/music-theory-ga/, then imported by the.mdxlessons as components, so they are inlined in the page. Their colours arecurrentColorand Starlight’s CSS variables (--sl-color-accent-high,--sl-color-orange-high,--sl-color-green-high,--sl-color-bg), with a light fallback, and they follow the site’s light or dark theme. They contain note names and numbers only, so the three languages share the same files; the description is in each page’saria-labeland in the paragraph before the figure. check.shregenerates them in memory and compares them with the committed files; CI fails when a diagram is out of date. Regenerate withdotnet run --project GaTheory -c Release -- svg ../../src/assets/music-theory-ga.- GA has React components for the same pictures, which the course reads but does not reuse:
BraceletNotation.tsx,FretDiagram.tsxandVexChordDiagram.tsx, underReactComponents/ga-react-components/src/components. ReadingBraceletNotationand itsNoteGroup(not run, to verify in a browser): the dots and labels are placed atangle − 90°, but the spokes ofNoteGroupusecos(angle)without the offset, so they would be rotated by a quarter turn; andfindSymmetryAxesonly tests axes through a note, missing axes between two notes, and adds each axis twice.
2026-09-15 — Lessons 5 to 7: differences in GA’s code (commit a826864)
Section titled “2026-09-15 — Lessons 5 to 7: differences in GA’s code (commit a826864)”Kept as DIFF lines in the expected outputs. None was reported upstream.
Lesson 5, keys:
Key.GetInterval(note)returnsnote.GetInterval(Root), the interval from the note up to the root:Key.Major.C.GetInterval(E)is m6, not M3 (Key.cs#L70-L76).Key.Major.TryParse("H")throwsInvalidOperationExceptioninstead of returningfalse, andKey.Minor.TryParsehas the same code (Key.cs#L153-L186).- The MCP tools
get_parallel_keyandget_relative_keyhave the same body: the other mode on the same signature, so the parallel key of C is A minor (KeyTools.cs#L135-L169). get_neighboring_keyspasseskey.KeySignature.ToString(), the list of accidentals, to a lookup by key name, and fails (KeyTools.cs#L197-L215).
Lesson 6, chords of a key:
HarmonicFunctionExtensions.FromDegree(7)is alwaysLeadingTone, also for the subtonic of natural minor;ScaleDegreeFunction.Subtonicexists but is not used there.ga_diatonic_chordsnames roots from a 12-name table: F♯ major getsFdim(E♯dim) and G♭ major getsB(C♭) (DomainClosures.fs#L23-L36). The core’sKey.Notesspells both keys right.- Code reading only (
GA.Domain.Servicesis not built by the course, to verify):HarmonicFunctionAnalyzer.ParsetestsContains("tonic")before"supertonic"and"mediant"before"submediant", so “Supertonic” would parse asTonicand “Submediant” asMediant(HarmonicFunctionAnalyzer.cs#L29-L72).ToPrimaryCategorygroups the mediant and submediant with the tonic, where Open Music Theory calls iii and vi weak predominants: a choice of textbook, not a bug.
Lesson 7, cadences and progressions:
Cadences.yamlnumbers “Chromatic Mediant (Metal)”, Em–Gm in E minor, asi biii, from E major; the Andalusian cadence in the same file is numbered from the notes of E Phrygian. Its “Phrygian Half Cadence” is ♭II–i, where the classical term means iv⁶–V in minor.PitchClassSet.ClosestDiatonicKeybreaks ties with “the normal form contains pitch class 3, so minor”. The normal form of a major scale’s notes is0 1 3 5 6 8 T, so C F G C, G D Em C, Dm7 G7 Cmaj7 and C Am F G7 come out in the relative minor (PitchClassSet.cs#L597-L660).ga_key_from_progressionandga_analyze_progressionscore keys by chord roots only, against the natural minor scale, and prefer the first chord’s root (GuitaristProblemTools.cs#L157-L223,DomainClosures.fs#L255-L336).
2026-09-15 — GA’s MCP server, keys and progressions
Section titled “2026-09-15 — GA’s MCP server, keys and progressions”Same caveat as on 2026-09-14: the server does not report its version.
get_parallel_key("Key of C")→Key of Am.get_relative_key("Key of Ab")→Key of Fm, right.get_key_signature_info("Key of Gm")→ root G,Bb Eb, notes G A Bb C D Eb F, right.get_neighboring_keys("Key of C")andget_diatonic_chords("A minor"): “An error occurred invoking …”.ga_diatonic_chords: F♯ major →F#, G#m, A#m, B, C#, D#m, Fdim; G♭ major →Gb, Abm, Bbm, B, Db, Ebm, Fdim.ga_key_from_progression(["Am","F","C","G"])→ best guess A minor (then C major and D minor, all 4/4), while the tool’s description promises C major;(["Dm7","G7","Cmaj7"])→ D minor (then C major and C minor).ga_analyze_progression("Am Dm E7 Am")→ “Key: A major, I IV V I”;("Dm7 G7 Cmaj7")→ “Key: D minor, i iv VII”.
2026-09-15 — Notes on the Streeling modules, continued
Section titled “2026-09-15 — Notes on the Streeling modules, continued”- MUS-003, “Guitar Example — D7 to G Voice Movements”: the tab puts C at fret 1 of the high E string and F♯ at fret 1 of the B string. Fret 1 is F on the high E string and C on the B string; open D7 (
xx0212) has F♯ at fret 2 of string 1 and C at fret 1 of string 2. The lessons link MUS-003 for its functions, cadences and closely related keys, not for this example. - MUS-003 puts iii and vi in the tonic family; lesson 6 gives both readings.
2026-10-02 — The Streeling notes, corrected upstream
Section titled “2026-10-02 — The Streeling notes, corrected upstream”- Demerzel #1091, merged as
e203e5a, corrected the MUS-006, MUS-002 and GTR-002 points of the 2026-09-14 notes; Demerzel #1098, merged as98625c3, corrected the MUS-003 tab of the 2026-09-15 notes. Learn #114 syncs both here. Ate203e5a:- MUS-006 describes a mode as a circular right shift and warns that a left shift transposes (lines 146-148); its practice answers rotate right (lines 194-195); it counts 208 Forte classes of 3 to 9 notes and 224 in all (line 223).
- MUS-002 gives the prime form of the open strings as (02479) (line 136), writes prime forms in parentheses (line 105), and answers the triad question under each equivalence (line 107).
- GTR-002 reads its diagrams from string 6 to string 1 (lines 29-33).
- MUS-003’s D7 puts F♯ at fret 2 of string 1 and C at fret 1 of string 2 (lines 196-197).
- Lesson 2 quoted MUS-006’s old rule in the present tense; it now quotes it in the past, pinned at Demerzel
fbfb2ee, the last commit before #1091.
2026-09-24 — Upstream fixes checked again
Section titled “2026-09-24 — Upstream fixes checked again”- GA has merged fixes for the rows of the QA table: #681 for the MCP tools and #682 for the parsers on 2026-09-23, #625 for key detection on 2026-09-24. The course stays pinned to
a826864, so the lessons and appendices still show the behaviour they were written against. recheck/probe.cscalls the same tool methods directly, without the MCP transport, on GA52f7fd5; its output isrecheck/results.txt. It prints only the facts each finding is about, andga-recheck.ymlruns it every Monday against GA’smainand fails on any difference fromresults.txt: a finding that comes back, or a fix that changes an answer, shows up there. It is not part ofcheck.sh, because it needs a full GA clone.- Fixed, and re-run:
ga_chord_to_set('Cm7b5')→{C, Eb, F#, Bb}, 4-27, and('Cdim7')→ 0 3 6 9, 4-28 (spelled{C, Eb, F#, A}).ga_set_class_subs('Am')→ the major triads under[maj], the minor ones under[m].ga_icv_neighbors('C', 1)→ “No other set class within distance 1 of C” instead of twelve identical lines.ga_scale_by_id(2741)→Forte Number: 7-35, andga_scale_by_name('Dorian')→ id 1709.get_neighboring_keys('Key of C')→ F, C, G. - Key detection now goes through
KeyIdentificationService, which adds a cadence weight to the count of diatonic chords (lines 171-237).ga_analyze_progression("Dm7 G7 Cmaj7")→ “Key: C major”, ii V I, andga_key_from_progressionagrees;ga_analyze_progression("Am Dm E7 Am")→ “Key: A minor”, i iv v i. - #729, merged 2026-09-24, fixes what that re-run still got wrong. In a minor key the major dominant now belongs to the key:
"Am Dm E7 Am"→ i iv V i, confidence 4/4 instead of 3/4. The numeral follows the chord’s quality (Bm7b5→ viiø,Bdim→ vii°). A tie between relative keys, which share their chords, goes to the key whose tonic triad opens the progression instead of the first in alphabetical order:[Am, F, C, G]→ A minor,[C, G, Am, F]→ C major, andga_analyze_progressionandga_key_from_progressionnow give the same key. Re-run on52f7fd5: lines 12-19 ofresults.txt. - Still not right, not reported: E7 is labelled
v, because the numeral comes from the natural-minor degree and not from the chord (romanFor); it also counts outside A minor (3/4), by design in #625, which credits a harmonic-minor V7 through the cadence instead.ga_key_from_progression(["Am","F","C","G"])still puts A minor first, tied 4/4 with C major, and the tool’s description still promises C major (line 168). - Not re-run:
get_chord_voicings,get_diatonic_chords("A minor")andga_search_voicings, which need GaApi running. - The
BraceletNotationrow was a code reading; #733, merged 2026-09-24, reproduced it and fixed it. Its test compares the SVG coordinates. On the old code, 3 of its 4 cases fail: C’s spoke ends at x=160 while its dot is at x=100; a diminished seventh gives the axis directions [0, 0, 90] instead of [0, 45, 90, 135]; the major scale draws its one axis twice. The spokes now use the dots’angleToCoordinates, and the axes are searched in half steps, so the ones between two notes are found. The rendering in a browser is still to verify. - #734, merged 2026-09-24, fixes the two rows outside the nineteen defects, each with a test that fails on the old code.
getAllInstruments()returns 122 instruments and 280 tunings where it returned 1 and 2. Nine malformed tunings were restored fromTunings.txt, the file the YAML came from: the two pedal steel entries, the Saz, the Huapanguera, the Dulcimer, and the four ukulele tunings that began withC6orD6. The 5-string banjo tunings now number string 1 from the treble side; tunings that rise or fall all the way are numbered as before. Instrument and tuning names are now the YAML keys,DropDrather thanDrop D. - One reading in appendix B was wrong.
Dulcimer.LydianModeisBb C4 C4 F3 Bb2, and I took the firstBbfor a pitch missing its octave.Tunings.txtreadsDucimer - Lydian Mode Bb C4 C4 F3 Bb2: theBbis the end of the tuning’s name, Lydian Mode Bb, which the conversion to YAML left in the pitch list. The appendix and the QA row now say so.
2026-09-30 — Lesson 9: predictions before the first run
Section titled “2026-09-30 — Lesson 9: predictions before the first run”Written from GA’s code at a826864, before the lesson’s program existed; the results entry quotes each one against what the program printed. The MCP tool ga_common_tones was called before this entry was written, so its answers are reported there as observations, not as tests.
- Common tones. GA’s core,
Chord.FromSymbolthenPitchClassSet.Intersect, agrees with the course on the lesson’s 13 pairs of chords,Cmaj9,Cdim7andC6included. - The chatbot’s smallest voice leading.
VoiceLeadingSkillmakes both chords the same size by repeating the root of the smaller one (VoiceLeadingSkill.cs, lines 185-194). For G → Cmaj7 it should answer 5 semitones where 3 exist, with B doubled: G–G, B–B, B–C, D–E. Over every ordered pair between the 48 triads (major, minor, diminished, augmented) and the 60 seventh chords (maj7, 7, m7, m7♭5, dim7), repeating the root should miss the minimum in more than 10 % of the triad → seventh pairs, and less often from seventh to triad. - The chatbot’s chord pattern. Of the skill’s ten example prompts, exactly one should fail its own regular expression: “voice leading C major to G major”, because the pattern wants a chord symbol right before “to”.
ga_voice_leading_pairwith voicings of different sizes. The MCP tool pairs the lowest notes of the two voicings and charges 3 semitones for each note left over (CompositionTools.cs, lines 320-336). From open G (320003) to open C (x32010) it should give 28, where leaving out the low G gives 10.- Parallel fifths and octaves.
ProgressionVoiceLeadingAnalyzerapplies the textbook rule string by string, and the course should agree on every example: F barre → G barre, 3 fifths and 4 octaves; E5 → G5, 1 and 1; open C → open G and open G7 → open C, one octave each, on strings 5 and 2; Am → Dm, none. VoiceLeadingSpace. With octave and permutation equivalence, its shortcut (the cyclic shifts of the two sorted chords, lines 63-91) should equal the brute-force minimum over every assignment of voices, for every ordered pair of 3-note and of 4-note pitch-class sets, with and without transposition: no disagreement. With transposition but without octave equivalence, it only tries upward shifts of 0 to 11 semitones (lines 46-61): from C4 E4 G4 to B3 D♯4 F♯4 it should give 0, since B3 shifted up by one is C4, and from B3 D♯4 F♯4 to C4 E4 G4 it should give 3.SetClassOpticIndex. For two set classes of the same size, it adds up, for each note of the first, the distance to the nearest note of the second (lines 167-224), so several voices may land on one note. That can never exceed the one-to-one minimum, and should fall below it, and differ from itself with the arguments swapped, on some of the 144 ordered pairs of the 12 trichord classes: (012) against (048) should give 2 one way and 6 the other, where one-to-one gives 6.
2026-09-30 — Lesson 9: results against the predictions
Section titled “2026-09-30 — Lesson 9: results against the predictions”The program is Lesson11.cs (entry l11, after the two appendices), its output expected/l11.txt; check.sh passes for lessons 1 to 11 and the 18 diagrams. It compiles four files of GA.Domain.Services as they are (VoiceLeadingSpace, SetClassOpticIndex, ProgressionVoiceLeadingAnalyzer and its report), which fetch-ga.sh now adds to its sparse checkout, and copies the chatbot skill’s pattern and the MCP tool’s distance as they are. The skill’s doubling rule is rewritten, so for that one the course tests its reading of GA’s code, not the running chatbot.
- Confirmed: 13 of 13.
- Confirmed for G → Cmaj7, 5 semitones where the course finds 3 with B doubled, and for the share: 1,260 of the 2,880 triad → seventh pairs (43.8 %) are above the minimum, by up to 4 semitones, Cdim → Gmaj7 being the first with that gap. Refuted for the direction: seventh → triad misses exactly as often, 1,260 times. I expected the direction to matter because the repeated root belongs to the first chord one way and to the second the other way. But the skill always pads the triad, and a voice leading read backwards costs the same, so the two directions are the same 2,880 problems.
- Confirmed: “voice leading C major to G major” is the only example without a match.
- Confirmed: 28 and 10. Two more rows have the same cause: open G7 → open C, 28 where 8 exists, and
xx2010→x32010, the same chord with a bass added, 19 where 3 exists. - Confirmed: 5 of 5 changes, pair of strings for pair of strings.
- Confirmed: no disagreement over 48,400 ordered pairs of 3-note sets and 245,025 of 4-note sets, with and without transposition. Without octave equivalence, 0 and 3 as written; C4 major → C5 major also gives 36 and the reverse 3, where a distance up to transposition gives 0.
- Confirmed: 2 one way and 6 the other, one-to-one 6. Over the 144 ordered pairs: 35 below the one-to-one minimum, none above, 70 that change when swapped.
Observations, not tests, from the MCP server running on this machine on 2026-09-30 (its version is not reported):
ga_common_tonesloses one note in five of seven pairs: F from Bm7b5/G7, B from Cmaj9/Em7, A from Cdim7/F7 and from C6/Am7, B♭ from C9/Gm7. The cause is the six-entry extension table that also brokega_chord_to_set(DomainClosures.fs, lines 85-98 ata826864). On GA’smain(5c3a52a),domain.commonTonestakes its notes fromchordTones, which #681 introduced in its commit82bc7ee6; read, not run.ga_parse_chord("Bm7b5")keeps the alteration ("components":["ext:7","alt:b5"]): the notes are lost after parsing.ga_voice_leading_pair("G7", "C", limit 3, guitar)evaluated 225 pairs and ranked first two G7/B shells at distance 5, then one at 6. Their extra notes are on top, where pairing from the bottom is right, and the copied function gives the same 5 for the first pair.
2026-10-01 — Lesson 10: predictions before the first run
Section titled “2026-10-01 — Lesson 10: predictions before the first run”Written from GA’s code at a826864, before the lesson’s program existed; the results entry quotes each one against what the program printed. No MCP tool and no chatbot was called for this lesson.
- The MCP server’s
ga_chord_substitutions. It calls the F# closuredomain.chordSubstitutions(DomainClosures.fs, lines 535-621), which keeps the diatonic triads of the key that share a note with the chord and sorts them by the number of shared notes, ties in scale order. For Am in C major it should rank C and F first with 2 shared notes, then Dm and Em with 1, so the example in the tool’s own description, “C (★★★, relative major), Em (★★, shared E/B), F (★, shared A)” (GaDslTool.cs, line 212), is wrong on all three chords. Without a key, the key is the chord’s letter, in major: Am is compared with the chords of A major, and B♭7 with those of B major. Ata826864, Bm7♭5 in C major is built as B D F♯ A, so Dm and Bdim share 2 notes with it instead of 3. - Its tritone line. It is added when the chord has a major third and a minor seventh above its root (lines 603-609): G7 gets D♭7; G9 and G13 get none, because at
a826864“9” and “13” add only their own degree. - The chatbot’s
ChordSubstitutionSkill: which path each example takes. The chatbot picks the skill by meaning; the skill then reads chord symbols with its own pattern (ChordSubstitutionSkill.cs, lines 69-71) and compares the chords when it finds two (lines 147-155). Of its twelve example prompts, ten should take the one-chord path; “Alternative chord for F major in C” should compare F with C instead of listing alternatives; “Borrow a chord from parallel minor” should find no chord symbol at all. - The skill’s one-chord list. It keeps the sets of the same size within ICV distance 3 and sorts them by cost (lines 168-174).
GrothendieckDelta.FromIcVsturns a zero difference into 1 (GrothendieckDelta.cs, lines 125-131), and two sets of the same size can only be an even distance apart, so every chord with the same interval-class vector, here the chords of the same set class, should come out at cost 0.60 and distance 1, ahead of everything else, in the order of their 12-bit numbers. For G7: Dm7♭5, A♭7, F7, D7, E♭m7♭5, without D♭7; for Am: Cm, C, A♭, D♭m, Fm, without E7; for C: Cm, A♭, D♭m, Fm, D♭, without B♭7; for Cmaj7: D♭maj7, A♭maj7, Fmaj7, Dmaj7, Amaj7. - The skill’s two-chord labels. G7 → D♭7 should get “Tritone Substitution”, “Set-Class Equivalent” and “ICV Neighbor (L1 = 1)”; Dm → G “Secondary Dominant”, because the test looks only at the roots (line 262); C → C “Set-Class Equivalent” and “ICV Neighbor (L1 = 1)”; B♭7 → C “Backdoor Dominant” alone.
get_borrowed_chords. The MCP tool forwards to GaApi’sContextualChordService.GetBorrowedChordsAsync(lines 75-119), which the program compiles as it is. For C major it should list 18 chords, each credited to the first parallel mode that has it, in the order Dorian, Phrygian, Lydian, Mixolydian, Aeolian, Locrian: Dorian Cm, D♯, Gm, A°, A♯; Phrygian C♯, Fm, G°, G♯, A♯m; Lydian D, F♯°, Bm; Mixolydian E°; Aeolian D°; Locrian C°, D♯m, F♯. The black-key roots are spelled with sharps (line 137) and the numerals carry no accidental (lines 157-170): G♯, the A♭ chord, is “VI”, A♯ “VII”, D♯ “III”, F♯, the G♭ chord, “V”, and C♯ and D are both “II”.ModalInterchange.yaml. Of the 13 borrowed chords it spells out in C major or A minor, 9 should be right and 4 wrong: VI F major, VII G major and III C major are A minor’s own chords, not chords borrowed from A major, and “bii°, Bb diminished” is not in A Phrygian, whose second degree is B♭ major. Of the six numerals of its harmonic and melodic minor examples, three should be wrong: ♭VI+ (the augmented chord of harmonic minor is ♭III+), iv+ (the fourth degree of melodic minor is a major chord, and its augmented chord is also ♭III+) and the vii°7 of melodic minor, which is half-diminished. No GA code should read the file: it is copied to the output directory and watched for changes, and a change only logs “Unknown configuration file”.
2026-10-01 — Lesson 10: results against the predictions
Section titled “2026-10-01 — Lesson 10: results against the predictions”The program is Lesson12.cs (entry l12), its output expected/l12.txt; check.sh passes for lessons 1 to 12 and the 18 diagrams. It compiles seven more of GA’s files as they are, which fetch-ga.sh now adds to its sparse checkout: GrothendieckDelta, GrothendieckService and its interface, ChordTemplateFactory and the global usings of GA.Domain.Services, and GaApi’s ContextualChordService with its models. It copies ChordSubstitutionSkill’s pattern, tables, selection and labels as they are. The MCP closure domain.chordSubstitutions is F# in a project the program does not build, so it is rewritten: for predictions 1 and 2 the course tests its reading of GA’s code, not the running server. The test of YamlKnowledgeLoader, which the program already compiled with GA.Business.Config, was not in the first run: I added it afterwards, in its own commit, aab1f4f, once I had found the loader.
- Confirmed, on the rewrite: C 2, F 2, Dm 1, Em 1 for Am in C major, so the description’s example is wrong on all three chords; Em shares only E with Am. Without a key, A major for Am and B major for B♭7, and two more of the same kind: F♯m against F major, E♭ against E major. With B D F♯ A, Bm7♭5 gets Dm 2, G 2, Bdim 2, where the course, with B D F A, puts Dm first with 3.
- Confirmed, on the rewrite: G7, D7, E7 and C7 get D♭7, A♭7, B♭7 and G♭7; G9 and G13 get none, and neither do Gm7 and Cmaj7, rightly.
- Confirmed: ten prompts list substitutes, “Alternative chord for F major in C” compares F with C, and “Borrow a chord from parallel minor” gets “Could not identify a chord symbol in your message.”
- Confirmed: the four lists as written, every chord at cost 0.60 and “Δ L1=1”. 23 chords tie for G7, Am and C, 11 for Cmaj7: exactly the other chords of each set class. D♭7 is number 19 of the 155 chords listed for G7; for Am, the textbook’s C is number 2 and F number 8 of 95. Dm7, which I had not predicted, gives Fm7, F♯m7, Am7, E♭m7, Cm7; its textbook substitute Fmaj7 is 4 away, beyond the cut-off of 3, and so are Em7 and Am7 from Cmaj7. Over the twelve roots of each chord type, the lists hold at most 6 different chords, and Dm7♭5 comes first for all 12 dominant sevenths.
- Confirmed for the four pairs. Dm → G also gets “Set-Class Equivalent” and “ICV Neighbor (L1 = 1)”, which I did not write down. Two pairs I had not predicted show the same two tests: F♯ → Bdim is a “Secondary Dominant”, and C → Am an “ICV Neighbor (L1 = 1)” where the distance is 0. G7 → C, D7 → G and B♭7 → C agree with the course.
- Confirmed: the 18 chords in the predicted order, with the predicted modes and numerals. One detail I had not written down: the notes are spelled with sharps even when the chord’s name has none: C minor is C D♯ G, A diminished A C D♯.
- Confirmed for the chords and the numerals: 9 of 13 right, the 4 predicted ones wrong; ♭VI+, iv+ and melodic minor’s vii°7 wrong, the other three right. Refuted for the readers.
YamlKnowledgeLoaderlists every*.yamlfile of the configuration directory, except five that have their own loaders, and flattens each entry into text;YamlKnowledgeSyncServicewould store those texts in theyaml_knowledgecollection with embeddings, “for semantic retrieval by the chatbot agents”, but no host registers it:AddSyncServices, which would, is never called, GaCLI has the call commented out with a TODO, and nothing else reads the collection. The program’s test returns the file’s 8 entries, and the four wrong strings are in their text. I had searched GA for the file’s name, which finds the watcher and the build’s copy, but cannot find a reader that lists a directory.
Observations, not tests:
- On the way, the loader skips
SpecializedTunings.yamlwith “While parsing a flow sequence, did not find expected ‘,’ or ‘]’.” on standard error, and nothing else. The file itself was not examined. - MUS-003, which the lesson links, has a mistake in its table of secondary dominants in G major: V7/IV is G7, G B D F, whose F is outside the key, not D7, which is V7 itself. Its note “V7/IV looks identical to V7” should say that V/IV, the G triad, looks like I. To fix in Demerzel, where the module is written.
- The mission page said GA’s partial clone and the build output need under 20 MB. Measured on 2026-10-01: 35.2 MB, the clone 17.5 MB and the build output 17.7 MB. The build output is mostly the libraries GA’s projects depend on (PCRE.NET’s native builds for three systems, FSharp.Core, MathNet.Numerics) and 2.2 MB of GA’s configuration files. The page now says about 35 MB.
- The lesson 9 entry said that
check.shchecks 19 diagrams. It checks 18: its nineteenthokline is the summary line for thesvgcommand. Corrected there.
2026-10-01 — Lesson 11: predictions before the first run
Section titled “2026-10-01 — Lesson 11: predictions before the first run”Written from GA’s code at a826864, before the lesson’s program existed; the results entry quotes each one against what the program printed. No MCP tool and no chatbot was called for this lesson.
- The modes of melodic minor.
MelodicMinorModerotates the notes ofScale.MelodicMinor, which GA spells from A (A B C D E F♯ G♯,Scale.cs, line 120), so its seven modes start on A, B, C, D, E, F♯ and G♯. EachModeFormulashould equal the formula the course computes from the steps 2 1 2 2 2 2 1, against lesson 2’s reference (Aeolian when the third is minor, Ionian otherwise): melodic minor1 2 b3 4 5 >♮6 >♮7, Dorian ♭21 >b2 b3 4 5 >♮6 b7, Lydian augmented1 2 3 >♯4 >♯5 6 7, Lydian dominant1 2 3 >♯4 5 6 >b7, Mixolydian ♭61 2 3 4 5 >b6 >b7, Locrian ♮21 2 b3 4 >b5 b6 b7, altered1 >b2 b3 >b4 >b5 b6 b7: 7 of 7. - The modes of harmonic minor. The same for
HarmonicMinorMode, from A B C D E F G♯ (line 119) and the steps 2 1 2 2 1 3 1: harmonic minor1 2 b3 4 5 b6 >♮7, Locrian ♮61 >b2 b3 4 >b5 >♮6 b7, Ionian ♯51 2 3 4 >♯5 6 7, Dorian ♯41 2 b3 >♯4 5 >♮6 b7, Phrygian dominant1 >b2 3 4 5 >b6 >b7, Lydian ♯21 >♯2 3 >♯4 5 6 7, altered 𝄫71 >b2 b3 >b4 >b5 b6 >bb7: 7 of 7. Lydian ♯2 is measured against Ionian, because an augmented second is not a minor third, and the altered 𝄫7’s seventh, G♯ to F, is a diminished seventh. - The short names. The five degree types implement the same
IScaleDegreeNaming.ToShortNamein three ways: Roman numerals without quality for major and harmonic major, the triad on each degree for the three minor scales, exceptiv#4for harmonic minor andIV7for melodic minor. Against the triad on each degree, 11 of the 35 should differ: 4 for major, 5 for harmonic major, 1 each for harmonic and melodic minor, none for natural minor. No GA code callsToShortName. PitchClassSet.StepBrightness. It averages the steps between consecutive notes and divides by 6 (PitchClassSet.cs, lines 265-283). The steps of a set of two notes or more add up to 12, so the value is 2/n for n notes: 0.2857 for each of the 21 modes of major, melodic minor and harmonic minor. Over the 4096 sets it should take 11 values, since sets of 0, 1 and 4 notes all give 0.5.IcvBrightness. The brightness of the chatbot’s embeddings (TheoryVectorService.cs, lines 163-172) reads only the interval-class vector, which all the modes of a scale share: 0.642857 for the seven modes of major, 0.595238 for melodic minor, 0.571429 for harmonic minor. By this measure Lydian and Locrian are equally bright.UnifiedModeService.RankByBrightness. It adds up the pitch classes of each member of the set’sModalFamily(UnifiedModeService.cs, lines 228-242). Every member contains C, so the sum is the course’s brightness of the mode on C: the semitones of its seven degrees above the tonic, added up. For major it should give the course’s order, Lydian 39 down to Locrian 33. For melodic minor too: Lydian augmented 40, Lydian dominant 38, melodic minor 37, Mixolydian ♭6 36, Dorian ♭2 35, Locrian ♮2 34, altered 32. For harmonic minor it should rank 14 sets, because the family also holds the seven modes of harmonic major (lesson 2). First comes harmonic major’s Lydian augmented ♯2 with 41, ahead of Lydian ♯2 with 40. Three ties, at 37, 36 and 35, each pair a mode of harmonic minor with one of harmonic major, in the order of their 12-bit numbers: Dorian ♯4 before harmonic major, Mixolydian ♭2 before harmonic minor, Phrygian dominant before Dorian ♭5.Modes.yaml. The file that the MCP server’s mode tools and the chatbot’sModesSkillread holds 31 families and 165 modes. 18 families declare an interval-class vector. For 9 of them it is not the vector GA’sPitchClassSetcomputes from the notes of the family’s first mode: harmonic minor, melodic minor, major pentatonic, whole tone, diminished, blues, chromatic, augmented triad and major seventh chord. Of the other 134 modes, 60 do not have the vector of their family’s first mode. Among them is the harmonic minor family’s Ultralocrian, spelled C D♭ E♭ F♭ G♭ A♭ B♭ like the altered scale, where its seventh is B𝄫.ModesConfig’s lookups.TryGetModeByIntervalClassVectorgives the “Scale:” line ofga_chord_to_set(ChordAtonalTool.cs, line 112). With the vectors GA computes, C major should find Ionian; harmonic minor, melodic minor and Cmaj7 nothing; G7 and Bm7♭5, both 4-27, “Major Seventh”; C and Cm “Major Triad”.TryGetModeByNameis behindget_mode_info. Of the 14 names of GA’s two mode classes, 8 should be found and 6 not: Locrian Natural 2, Locrian Natural 6, Ionian Augmented, Dorian Sharp 4, Lydian Sharp 2 and Altered bb7. No alternate name should be found, “Super Locrian” and “Acoustic Scale” included, becauseGetAllModessets every mode’s alternate names toNone(ModesConfig.fs, line 284).GetModalFamilies, whichModesSkillreads, keeps them.
2026-10-01 — Lesson 11: results against the predictions
Section titled “2026-10-01 — Lesson 11: results against the predictions”The program is Lesson13.cs (entry l13), its output expected/l13.txt; check.sh passes for lessons 1 to 13 and the 18 diagrams. It compiles one more of GA’s files as it is, UnifiedModeService, which fetch-ga.sh now adds to its sparse checkout, and copies TheoryVectorService.IcvBrightness, which is internal to GA.Business.ML, as it is. ModesConfig comes with GA.Business.Config, which the program already compiled. The test of the names Modes.yaml loses was not in the first run: I added it afterwards, in its own commit, 13e7607, once the first run had shown one of them.
- Confirmed: 7 of 7 formulas, and the 7 spellings. GA’s names are the textbook’s in ASCII, “Dorian b2” to “Locrian Natural 2”.
- Confirmed: 7 of 7, notes included. GA calls the seventh mode “Altered bb7” and the third “Ionian Augmented”.
- Confirmed: 11 of 35, degree for degree.
- Confirmed: 0.2857 for all 21 modes, and 11 values over the 4096 sets, one per size, with sets of 0, 1 and 4 notes sharing 0.5.
- Confirmed: 0.642857, 0.595238 and 0.571429, the same for every mode of each scale.
- Confirmed: major and melodic minor in the course’s order. For harmonic minor, 14 sets, harmonic major’s Lydian augmented ♯2 first with 41, and the three ties in the predicted order.
- Confirmed: 31 families, 165 modes, 18 declared vectors, the 9 predicted ones wrong; 60 of the 134 other modes without their family’s vector; the Ultralocrian with melodic minor’s vector,
<2 5 4 4 4 2>. - Confirmed for the vectors, as written. Refuted in part for the names: 9 of the 14 are found, not 8. “Ionian Augmented” is found, but in the Double Harmonic Family: the mode the file writes “Ionian Augmented #2” (
Modes.yaml, line 655) comes back without “ #2”, which YAML reads as a comment. I had read the harmonic minor family, where “Ionian Augmented” is an alternate name, and not the rest of the file. The other five names are not found, and neither are “Super Locrian”, “Acoustic Scale” and “Spanish Phrygian”, all alternate names;GetModalFamilieskeeps 104 alternate names,GetAllModesnone.
The test added after the first run, in 13e7607: 8 of the 165 names lose their alterations to a YAML comment, at lines 631, 639, 655, 663, 667, 671, 679 and 681, and 7 names come back for more than one mode. Two of the seven are not cut names: the Minor Second and Major Second families call their inversions “Major Seventh” and “Minor Seventh”, like two chords of the Major Seventh Chord family.
Observations, not tests:
- The chromatic scale is the one mode whose vector GA’s
PitchClassSetand the course compute differently: GA<1 1 1 1 0 6>, the course<12 12 12 12 12 6>.IntervalClassVectorIddocuments it as a “KNOWN LIMITATION” of its base-12 packing (IntervalClassVectorId.cs, lines 3-15). The file declares<11 11 11 11 11 6>for its family, wrong either way. HarmonicMajorScaleMode’s comment links to Ian Ring’s scale 2773 (HarmonicMajorScaleMode.cs, line 14), which is Lydian, C D E F♯ G A B; harmonic major is 2485. The links ofMelodicMinorMode(2733) andHarmonicMinorMode(2477) are right.get_mode_infoprints the family’s declared vector on a line called “Intervals” and ends every answer with “Alternate Names: None” (ModeTool.cs, lines 27-33). Read, not run.
2026-10-01 — Lesson 12: predictions before the first run
Section titled “2026-10-01 — Lesson 12: predictions before the first run”Written from GA’s code at a826864, before the lesson’s program existed; the results entry quotes each one against what the program printed. No MCP tool and no chatbot was called for this lesson.
- Limited transposition. A set has limited transpositions when a transposition other than T0 maps it onto itself. If d of the twelve transpositions fix it, it has 12/d distinct transpositions and, with n notes, n/d distinct modes. Over the 4096 sets, 76 should qualify, the empty set and the chromatic scale included, in 17 transposition classes. Without those two, they are the 15 “generalized Messiaen modes” Wikipedia counts. They repeat every 2 semitones (1 class, the whole-tone scale), 3 (2 classes: the diminished seventh and the octatonic scale), 4 (3 classes: the augmented triad, the augmented scale and Messiaen’s third mode) or 6 (9 classes). Messiaen’s seven modes should have 2, 3, 4, 6, 6, 6 and 6 transpositions and 1, 2, 3, 4, 3, 4 and 5 modes, as his list gives. GA’s
UnifiedModeService.IsSymmetricSettests the same thing,Transpose(k)for k from 1 to 11 (UnifiedModeService.cs, lines 349-362): it should agree with the course on all 4096 sets. - GA’s three symmetric mode classes.
WholeToneScaleMode,DiminishedScaleModeandAugmentedScaleModehard-code 2, 3 and 4 transpositions: the course’s counts. But their degree types run from 1 to 6, 8 and 6, soItemsgives 20 modes, which make 1, 2 and 2 different sets once each is moved to C. The class comments promise two, two and four distinct modes (line 12 of each file): the whole-tone and augmented counts are wrong. “Augmented dominant” and “Augmented mode 5” should be the same set as “Augmented”, C E♭ E G A♭ B, and “Augmented Lydian” and “Augmented mode 6” the same as “Augmented inversed”. - The two diminished scales.
DiminishedScaleModerotatesScale.Diminished, C D E♭ F G♭ A♭ A B (Scale.cs, line 62), which starts with a whole step. So degree 1, which GA names “Half-whole diminished”, should be the whole-half scale, and degree 2, “Whole-half diminished”, the half-whole one: the names are swapped.Modes.yamlnames the same two spellings the right way round (lines 331-342). - The tritone scale.
Scale.Tritoneis C D♭ E F♯ G A (line 67). The tritone scale, the notes of the Petrushka chord, is C D♭ E G♭ G B♭, 0 1 4 6 7 10: GA has A for B♭. GA’s notes should form 6-Z50 (014679), the vector<2 2 4 2 3 2>of lesson 4’s exercise, with 12 transpositions and 6 modes; the tritone scale is 6-30 (013679), with 6 transpositions and 3 modes.TritoneScaleMode’s comment calls it “a symmetrical scale built from alternating half steps and minor thirds” with “only two distinct modes” (lines 11-14). GA’s steps are 1 3 2 1 2 3, the tritone scale’s 1 3 2 1 3 2, and half steps alternating with minor thirds make the augmented scale. IdentifyMessiaenMode. It compares the id of the set’s prime form, the smallest of its 24 forms (lesson 4), with fixed ids (UnifiedModeService.cs, lines 290-347). Of Messiaen’s seven modes, it should name the first three. For modes 4 to 7 the prime forms are 975, 455, 1495 and 2015, but GA tests 2535, 2275, 3315 and 3055, ids of other transpositions, soMessiaenModeIndexshould stay empty. Both sets its comment gives for mode 6 are forms of mode 4, and the comment gives mode 3 three transpositions instead of four.IsMonomodal. It is true when a set’s modal family, the sets containing 0 with its interval-class vector, has one member (PitchClassSet.cs, line 189). It fills the dimension of the embeddings called “Is Symmetric/Monomodal” (ModalVectorService.cs, line 132;EmbeddingSchema.cs, lines 881-882). It should be true for 29 sets: the 12 single notes and the empty set, which share the vector<0 0 0 0 0 0>, 6 tritones, 4 augmented triads, 3 diminished sevenths, 2 whole-tone scales and the chromatic scale. That is 17 of the 76 sets with limited transpositions. The octatonic scale, which the property’s comment gives as an example (line 187), is not among them, nor are the augmented scale and Messiaen’s modes 3 to 7.AtonalModalFamilies.yaml. ItsIsSymmetricis true for 6 of its 200 families, the ones with a single distinct mode: single notes, tritone, augmented triad, diminished seventh, whole-tone and chromatic scales.ModesSkillanswers “modes of limited transposition” with these six (ModesSkill.cs, lines 596-601 and 687-705), then names the “octatonic (3), and hexatonic (4)”, which its list leaves out; the single note it lists has 12 transpositions. The file’s Forte labels come fromProgrammaticForteCatalog, which numbers each cardinality in increasing order of the vector’s id (ProgrammaticForteCatalog.cs, lines 123-133), the reverse of Forte’s order for small sets. The listing should print 2-1, 3-1, 4-1 and 6-1 for 2-6, 3-12, 4-28 and 6-35. Against GA’s ownForteCatalog(lesson 4), none of the 2-, 3-, 4-, 8-, 9- and 10-note families should agree, while 1-1, 11-1 and 12-1 should.AtonalChordAnalysisService.IsSymmetricalSet. It sorts the pitch classes and asks whether every step between neighbours is the same, leaving out the step from the last back to the first (AtonalChordAnalysisService.cs, lines 220-233). It should flag 156 of the 4096 sets: all 66 two-note sets and every evenly spaced run that fits between 0 and 11. 16 of them have limited transpositions: 6 tritones, 4 augmented triads, 3 diminished sevenths, 2 whole-tone scales and the chromatic scale. The other 60 sets with limited transpositions, the octatonic scales among them, should not be flagged. C D E should be flagged, and its transposition B♭ C D not.- Mirror symmetry.
TranspositionClass.IsInversionallySymmetriccompares a class’s prime form with the transposition prime form of its inversion (TranspositionClass.cs, lines 52-53). It should agree with the course on all 352 transposition classes, 96 of them symmetric: 352 − 224 = 128 set classes split into two transposition classes, and the other 96 do not. Of the 15 classes with limited transpositions, all but the two forms of 6-30 should be mirror-symmetric, each with as many mirror axes as transpositions that fix it: 6 for the whole-tone scale, 4 for the octatonic scale, 3 for the augmented scale.
2026-10-01 — Lesson 12: results against the predictions
Section titled “2026-10-01 — Lesson 12: results against the predictions”The program is Lesson14.cs (entry l14), its output expected/l14.txt; check.sh passes for lessons 1 to 14 and the 20 diagrams. It compiles one more of GA’s files as it is, AtonalChordAnalysisService, which fetch-ga.sh now adds to its sparse checkout, and calls its private IsSymmetricalSet by reflection. UnifiedModeService, compiled since lesson 11, gives IsSymmetricSet and MessiaenModeIndex; AtonalModalFamiliesConfig and ModesConfig come with GA.Business.Config. ModesSkill belongs to GA.Business.ML, which the course does not compile, so the program rebuilds its answer from its format and the same data. The test of what GA’s two mode catalogs call the fifteen classes was not in the first run: I added it afterwards, in its own commit, 6b4039a, once the first run had shown “Major Bebop Family”.
- Confirmed: 76 sets in 17 transposition classes, 15 without the empty set and the chromatic scale, in 14 set classes; 1, 2, 3 and 9 classes repeating every 2, 3, 4 and 6 semitones; Messiaen’s seven modes as his list gives them;
IsSymmetricSetagrees on all 4096 sets. - Confirmed: 2, 3 and 4 transpositions; 6, 8 and 6 modes, which make the sets 1365; 2925 and 1755; 2457 and 819 on C. “Augmented dominant” and “Augmented mode 5” are 2457 like “Augmented”, “Augmented Lydian” and “Augmented mode 6” 819 like “Augmented inversed”.
- Confirmed: degree 1, “Half-whole diminished”, has the steps 2 1 2 1 2 1 2 1, and degree 2 the steps 1 2 1 2 1 2 1 2.
- Confirmed: GA’s scale is 6-Z50,
<2 2 4 2 3 2>, with 12 transpositions and 6 modes; the tritone scale 6-30,<2 2 4 2 2 3>, with 6 and 3. GA’s ownIsSymmetricSetsays False and True.TritoneScaleMode.Itemsgives 6 modes, 6 different sets on C. - Confirmed: modes 1 to 3 named, 4 to 7 not. The program lists the eight ids the method tests: 2925, 2535, 2275, 3315 and 3055 are not prime forms, and 3315 is a form of mode 4.
- Confirmed: 29 sets, 1, 12, 6, 4, 3, 2 and 1 of 0, 1, 2, 3, 4, 6 and 12 notes, 17 of them limited; the octatonic scale not flagged.
- Confirmed: 200 families, 6 with
IsSymmetric, 15 with limited transpositions; the answer’s six families with Forte 1-1, 2-1, 3-1, 4-1, 6-1 and 12-1. No label agrees for 2, 3, 4, 8, 9 and 10 notes, and 1-1, 11-1 and 12-1 agree. The prediction said nothing of 5, 6 and 7 notes: one hexachord family agrees, which makes 4 of 200. The labels are stale output, not an unknown error: GA #436 had moved the generator toForteCatalogbeforea826864(Demos/AtonalModalFamiliesGenerator/Program.cs, line 183) and left regenerating the file for later; the file has not changed since7a4308a, which generated it. - Confirmed: 156 sets, 16 limited, 60 limited sets not flagged; C D E True, B♭ C D False.
- Confirmed: 352 transposition classes, 96 mirror-symmetric, all agreeing; 13 of the 15 limited classes mirror-symmetric, with 6, 4 and 3 axes for the whole-tone, octatonic and augmented scales; the two forms of 6-30 with none. No set has mirror axes in a number other than its fixing transpositions.
The test added after the first run, in 6b4039a: AtonalModalFamilies.yaml names six of the fifteen classes after Modes.yaml, two of them wrongly. Messiaen’s fourth mode is “Major Bebop Family”, because Modes.yaml’s “Major Bebop Mode 8”, C D♭ D F G♭ G A♭ B (lines 725-726), is Messiaen’s fourth mode, not a rotation of the bebop scale; the diminished seventh is “Major Seventh Chord Family”, from the “Diminished Seventh” of that family (line 531). TryGetModeByIntervalClassVector names one class only, Messiaen’s sixth mode, “Diminished (Half-Whole)”: the Diminished Family declares <4 6 4 6 4 4> (lines 328-329), the sixth mode’s vector. The octatonic scale is found nowhere. Twenty modes of Modes.yaml belong to the fifteen classes, ten of them to the octatonic scale.
Observations, not tests:
ModalCharacteristicIntervalServicestores each symmetric mode at a base plus its degree minus one, with bases 206, 208 and 212 (ModalCharacteristicIntervalService.cs, lines 114-118 and 135): the 8 diminished modes overlap the 6 whole-tone modes at 208 to 211 and the 6 augmented modes at 212 to 215, so indices 208 to 215 are written twice. Read, not run.GenericSymmetricScaleMode’s constructor defaults tohasLimitedTranspositions = trueandtranspositionCount = 12(GenericSymmetricScaleMode.cs, lines 23-27), two values that contradict each other.- GA’s tests for Messiaen’s modes 5 to 7 assert
Is.Null.Or.EqualTo(...), and the one for mode 6 builds 3315, a form of mode 4 (UnifiedModeAdvancedTests.cs, lines 87-119). ProgrammaticForteCatalog’s comment calls its differences from Forte’s numbering “minor” (lines 16-18);ForteCatalog’s says they diverge “for most set classes” and must not be surfaced (lines 9-12).- MUS-006 says that symmetric scales are not chiral. The tritone scale has limited transpositions and no mirror axis.
2026-10-01 — Lesson 13: predictions before the first run
Section titled “2026-10-01 — Lesson 13: predictions before the first run”Written from GA’s code at a826864, before the lesson’s program existed; the results entry quotes each one against what the program printed. No MCP tool and no chatbot was called for this lesson. The course reads 41 chord symbols on C: 14 extended chords, 11 altered chords, 12 spellings of familiar chords taken from Open Music Theory and Wikipedia, two slash chords and two English words.
- Two chord-symbol parsers. GA’s C# has two:
Chord.FromSymbolinGA.Domain.Core(Chord.cs, lines 75-140) andChordSymbolParserinGA.Domain.Services(ChordSymbolParser.cs, lines 56-189), which GaApi’sVoicingFilterServiceand the chatbot’sSpectralRagOrchestratorcall. Both lower-case the suffix and look it up in a table.FromSymbolshould read 14 of the 41 right: the 11 extended chords of its table (9, maj9, m9, 11, maj11, m11, 13, maj13, m13, 6/9, add9), Cø7, and the two words, which it rejects. It should throw on the other 26 chords: every altered chord,C7sus,C9sus4,Cadd2, both slash chords, and the textbooks’ own spellingsCmi,Cmi7,Cma7,Co7,C∆7(Open Music Theory’s ∆, U+2206; GA accepts △, U+25B3),CΔ7(Wikipedia’s Greek Δ),Cm(b5),Cm7♭5(with the sign ♭),C+7andCm(maj7).CM7, a major seventh, should come back as C minor seventh: it ism7once lower-cased.ChordSymbolParsershould throw on none of them and read 17 right. Past its table, it testsContains("alt"), thenb5,#5,b9,#9,#11andb13, and returns a major triad when nothing matches (lines 98-140). SoC7b9,C7#9,C7b13,Cmaj7#11and the pitch classes ofC/Ecome out right.C7b5andC7#5lose their seventh (C E G♭, C E G♯);C7#11andC9#11get a major seventh (C E G B F♯);C7altgets a perfect fifth and no altered fifth (C E G B♭ D♭ D♯);C7b9#11andC7#9b13lose their second alteration;Cm(b5)comes out C E G♭;CM7is a minor seventh again.Cmi,Cmi7,Cma7,Co7,C∆7,CΔ7,Cm7♭5,C+7,Cm(maj7),C7sus,C9sus4,Cadd2andC/F#all come out as a C major triad, and so do the words: “Can” is C major, “Give” G major. GA’s tests listC7b5,C7#5,GaltandC/Eamong the valid symbols and check only that a chord comes back (ChordSymbolParserTests.cs, lines 11-18 and 33-40).
- Extended chords, read back.
FromSymbolbuilds every 11 and 13 as the full stack of thirds, with the compound intervals 14, 17 and 21 (Chord.cs, lines 131-136). So C13 has seven notes, the F major collection, the same set asFmaj13andGm13. GA’sCanonicalChordPatternCatalogstores the voicings players use, the 13 without its 11 and the major 11 without its third (CanonicalChordPatternCatalog.cs, lines 82-91):TryFindExactshould find nothing for C13, Cmaj13, Cm13 and Cmaj11, and name the other seven.ChordFormula.GetSymbolSuffixshould drop the “maj” of maj9, maj11 and maj13, as it drops the “maj” of maj7 (lesson 3), whileBasicChordExtensionsService.GenerateChordName(lines 164-178), from the same quality and extension, should name all eleven right. - Alterations, named by
ChordAlterationService. A chord interval carries aFunction, but every builder the course found fills it from the semitones modulo 12 (ChordFunctionExtensions.FromSemitones, lines 13-22): 3 is a third, 6 and 8 are fifths, and 1 falls toRoot.DetectAlterationFromSemitones(lines 87-102) then reads 1 as ♭9, 6 as ♭5 and 8 as ♯5, and 3 never as ♯9, andGenerateNameWithAlterations(lines 37-61) calls a dominant seventh with any alteration “7alt”. GA’s own nine “common altered chords” (lines 186-202), built from their descriptions and passed the way GA builds an analytical template (ChordTemplate.Analytical.FromPitchClassSet), should all come back under another name: C7alt asC9(b9,b5,#5), C7(♭9) asC9(b9), C7(♯9) asC7with no alteration, C7(♭5), C7(♯5), C7(♯11) and C7(♭13) all four asC7alt, C7(♭9,♯11) asC9(b9,b5), and Cmaj7(♯11) asCmaj7(b5). The fifths that define a chord should count as alterations too:Cdim(b5),Caug(#5),Cdim7(b5)for Cm7♭5 andC6(b5)for Cdim7. - Every template of
ChordTemplateFactory.GenerateAllPossibleChordsyieldsGenerateFromAllModalFamilies, which already runs the traditional, symmetrical and pentatonic scales, then runs the three again (ChordTemplateFactory.cs, lines 37-62 and 93-115): every template should come twice, the second half repeating the first. Over the templates,ChordAlterationServiceshould never find ♭13, and should find ♯9 only in Sus2 templates and ♯11 only in Sus4 templates, the one place where the factory sets the function by hand (line 495). - Polychords.
ga_polychordmerges the pitch classes of two chords (ChordAtonalTool.cs, lines 194-218). Its description promises “B triad over C triad → Lydian mode set {C,D,E,F#,G,B}” (line 198), but a B major triad is B D♯ F♯: the tool’s own code, read withdomain.chordIntervals(DomainClosures.fs, lines 85-92 and 199-227), should print {C, Eb, E, F#, G, B}. {C, D, E, F♯, G, B} is B minor over C. Of the 28 modes of the major, melodic minor, harmonic minor and harmonic major scales built on the lower chord’s root, only Lydian should contain Bm/C, and only Lydian ♯2, the sixth mode of harmonic minor, B/C.AdvancedHarmony.yamlsays that C major over F♯ major “Creates all 12 chromatic pitches” (line 104): it makes six, C D♭ E F♯ G B♭, the Petrushka chord and lesson 12’s tritone scale, 6-30, which none of the 28 modes contains and the half-whole octatonic scale does. The pendingpolychordskill gives D over E♭ a “Lydian-augmented colour” (DRAFT.md, line 47): on E♭, only Lydian ♯2 should contain it, not Lydian augmented. Its reading of C over D, A C D E F♯ G, should be right. - The YAML the chatbot retrieves. No typed loader reads
ExtendedChords.yaml, butYamlKnowledgeLoaderflattens every YAML file without one into knowledge entries for retrieval (YamlKnowledgeLoader.fs, lines 25-31 and 131-140). It should return 3 entries fromExtendedChords.yaml, whose 13th chord, 1 3 5 ♭7 9 13, is the catalog’s and not the parsers’, and 9 fromAdvancedHarmony.yaml, among them “Polychords” with its 12 chromatic pitches. - Upper structures. A major or minor triad over C7 adds tensions. The course keeps the triads with no natural eleventh (F, a minor ninth above the third) and no major seventh (B, against the minor seventh). That should leave 6 major and 6 minor triads: Wikipedia’s nine upper structures (US II, ♭III, ♭V, ♭VI, VI, i, ♭ii, ♭iii and ♯iv) and three more, C major, the chord itself, G minor (5, ♭7, 9) and A minor (13, 1, 3). GA’s catalog has no upper-structure or polychord pattern, though its comment reserves priorities 90 to 99 for “polychord fragments” (
CanonicalChordPatternCatalog.cs, line 26).
2026-10-02 — Lesson 13: results against the predictions
Section titled “2026-10-02 — Lesson 13: results against the predictions”The program is Lesson15.cs (entry l15), its output expected/l15.txt; check.sh passes for lessons 1 to 15 and the 21 diagrams. It compiles three more of GA’s files as they are, ChordSymbolParser, BasicChordExtensionsService and ChordAlterationService, which fetch-ga.sh now adds to its sparse checkout. ga_polychord belongs to the MCP server and reads an F# closure of GA.Business.DSL, neither of which the course compiles: the program copies the tool’s code and replaces the closure with the triad intervals it returns. The test of MUS-005’s D♭/C was not in the first run: I added it afterwards, in its own commit, ac620ce, while writing the lesson.
- Confirmed:
FromSymbolreads 14 of 41 right and rejects 28 symbols, the 26 chords and the two words;CM7comes back as0 3 7 T.ChordSymbolParserreads 17 right and rejects none; each misreading is as written, “Can”0 4 7and “Give”2 7 E. - Confirmed:
TryFindExactnames 7 of 11, nothing for C13, Cmaj13, Cm13 and Cmaj11;GetSymbolSuffixgives back 8, with C9, C11 and C13 for the three major chords;GenerateChordName11. C13, Fmaj13, Gm13 and the F major scale are one set. - Confirmed: the nine names and the four chords defined by their fifth, as written. The prediction did not say that
SuggestedNotationcalls the F♯ of Cmaj7(♯11) “Flat fifth (tritone substitution)”, nor that the catalog names seven of the nine. - Confirmed: 25,900 templates, the second half repeating the first; ♭13 in none, ♯9 in 80 Sus2 templates, ♯11 in 176 Sus4 templates.
- Confirmed, with one citation corrected: the five merged sets and the modes that contain them are as written, but the draft’s “Lydian-augmented colour” is on line 46 of
DRAFT.md, not 47. Not predicted: the card prints “24 modes” for 6-Z19, lesson 2’s wide family, and “mode 0” for D over E♭, whose set has no C, so thatModeIndexis −1. - Confirmed: 3 and 9 entries, the 13th chord without its eleventh, and the Polychords entry with “Creates all 12 chromatic pitches”. Not predicted: the same loader returns
IconicChords.yaml’s Petrushka chord with its six pitch classes. - Confirmed: 12 triads, Wikipedia’s nine with C, Gm and Am; no catalog pattern named for an upper structure or a polychord, 0 of 62.
The test added after the first run, in ac620ce: D♭/C is 0 1 5 8, 1 ♭9 11 ♭13 over C, contained in Phrygian, Locrian, Phrygian dominant and Locrian ♭♭7; D/C is 0 2 6 9, in six modes with Lydian first; Cmaj7♯11 in Lydian and Lydian ♯2. MUS-005’s “Cmaj7#11 sound” is D/C, not D♭/C.
Observations, not tests:
- The three guitar voicings of the figure, which leave out the fifth, match no pattern of
TryFindExact. - While loading,
YamlKnowledgeLoaderprints on standard error “Skipping SpecializedTunings.yaml: While parsing a flow sequence, did not find expected ‘,’ or ‘]’.”: one of GA’s content files does not parse, and its entries never reach retrieval. SpectralRagOrchestrator’s progression handler keeps every tokenChordSymbolParseraccepts, minus a short list of words that leaves out “Can” (SpectralRagOrchestrator.cs, lines 217-226). Read, not run.- MUS-005’s table of upper structures gives B♭ major over C7, whose F is the eleventh, as “the sus/11 sound”; it is a sus chord only once the third is gone.
2026-10-02 — Lesson 14: predictions before the first run
Section titled “2026-10-02 — Lesson 14: predictions before the first run”Written from GA’s code at a826864, before the lesson’s program existed; the results entry quotes each one against what the program printed. No MCP tool and no chatbot was called for this lesson. The course takes Wikipedia’s definition of drop voicings: the voices of a close-position chord, all within an octave, are numbered from the top, and a drop-n voicing lowers voice n by an octave.
- Drop voicings, by definition. For the four seventh chords on C (maj7, 7, m7, m7♭5), each of their four close positions (one per top note) and each choice of dropped voices among voices 2, 3 and 4 (none, one, two or all three), the course builds 128 voicings and names each one back. GA’s
VoicingHarmonicAnalyzerraises the lowest note an octave and answers “Drop-2” when the notes then fit within an octave, nothing otherwise (VoicingHarmonicAnalyzer.cs, lines 46-58). With four notes of four different pitch classes, that is “Drop-2” exactly when at most one voice is dropped: GA should call the 64 close, drop-2, drop-3 and drop-4 voicings “Drop-2” and leave the 64 others unnamed. It answers nothing else, soVoicingFilters’Drop3andDrop2And4, which look for “Drop-3” and “Drop-2+4” (VoicingFilters.cs, lines 114-116), should match none of them. The test needs four notes: Wikipedia’s three drop-2 voicings of the C major triad and its four drop-2-and-4 voicings of G7, which the course should rebuild as written (C E G, G C E, E G C; G D F B, B F G D, D G B F, F B D G, reading down from the top), should get nothing. - Rootless and open.
VoicingCharacteristicshasIsRootless,DropVoicingandIsOpenVoicingin that order (VoicingCharacteristics.cs, lines 10-12), andAnalyzepassesintervalSpread > 12, the drop label andfalse(VoicingHarmonicAnalyzer.cs, lines 38-40). So in GA a voicing is “rootless” when it spans more than an octave, and no voicing is open. Of the 128 voicings, which all contain their root, the 112 with a dropped voice should be rootless and none open.ChordClassificationEnginethen tags every voicingclosed-voicingand every “Drop-2”drop-2-voicings, close ones included (ChordClassificationEngine.cs, lines 158-167). On guitar shapes, all seven open chords of lesson 3 should be rootless, and three of them “Drop-2”: x32010 (C), x02210 (Am) and xx0232 (D), where the notes fit within an octave once the bass is raised one; 032010, 022100, 320003 and 133211 get nothing. MUS-005’s “Drop-2 Cmaj7 (string set 5-4-3-2)”, x3200x, is C E G B within an octave, a close position: GA should call it “Drop-2”, like the page, and not rootless. The drop-2 voicing with C in the bass on those strings, x3545x (C G B E), should be “Drop-2” and rootless. - Shells. The course plays root, third and seventh on MUS-005’s Freddie Green string sets: G7, Gmaj7 and Gm7 with the root on the sixth string (3x34xx, 3x44xx, 3x33xx, strings 6-4-3, the seventh below the third), C7, Cmaj7 and Cm7 with the root on the fifth (x323xx, x324xx, x313xx, strings 5-4-3, the third below the seventh). The first three span 15 or 16 semitones, the others 10 or 11: GA should call the first three rootless, though their root is the bass, and not the others. Three GA rules decide what a shell is, and none of them looks at the chord tones:
VoicingPhysicalAnalyzergives theShellFamily“3-4 note shell”, and the tagshell-voicing, to any voicing on three or four strings (VoicingPhysicalAnalyzer.cs, lines 126-131 and 204): all six shells, xx0232, x3200x and every drop voicing on four strings.ChordClassificationEnginetagsshell-voicinga rootless voicing of three pitch classes (lines 169-173): the three sixth-string shells, not the fifth-string ones, and all seven of lesson 3’s open triads.VoicingFilters’ShellVoicingskeeps a rootless voicing of three distinct MIDI notes (lines 118-119): the three sixth-string shells and nothing else here; the open triads have four to six notes.
- Every voicing GA generates.
VoicingGeneratorslides a five-fret window along the 24-fret neck and keeps every combination of muted strings and frets in the window that plays at least two notes (VoicingGenerator.cs, lines 18-144 and 156-292). With six choices per string, a window gives 6⁶ − 31 = 46,625 voicings, and two neighbouring windows share 5⁶ − 25 = 15,600: run in sequence, it should return 21 × 46,625 − 20 × 15,600 = 667,125 voicings. The course keeps those that play the four notes of a seventh chord on C on four strings. GA’s label should be “Drop-2” on exactly those the course finds close, drop-2, drop-3 or drop-4. All 48 drop-2 shapes MUS-005 counts (4 qualities × 4 inversions × 3 sets of adjacent strings) should be among them, since none spans more than four frets, GA’s limit, and so should the 32 drop-3 shapes on its string sets 6-4-3-2 and 5-3-2-1. Over these voicings,VoicingFiltersshould keep withDrop2the close voicings along with the drop-2, drop-3 and drop-4 ones; withClosedPosition, all of them; withOpenPosition,Drop3,Drop2And4andShellVoicings, none; withRootless, those spread over more than an octave. - Guide tones. In a ii–V–I, the third of ii is the seventh of V and the third of V the seventh of I, while the sevenths of ii and V fall a half step to the next third. GA’s
TransposeTablesgive the major ii–V–I in twelve keys (ChordProgressions.yaml, lines 581-618): the course should find these four moves in every row, and in C the two lines F F E and C B B behind MUS-005’s “C-B, F-E”.VoicingAnalyzer.AnalyzeEnhancedbuilds everyToneInventoryasnew ToneInventory([], false, [], [])(VoicingAnalyzer.cs, line 155):HasGuideTonesshould be false, andTonesandOmittedTonesempty, for every voicing the course analyzes, the shells included. - GA’s comping recipes.
ChordProgressions.yamllists sixGuitarCompingRecipeswith fifteen fingerings on named string sets (lines 461-577). Its typed loader reads only theChordProgressionslist (ChordProgressionsConfigLoader.cs, lines 41-44), butYamlKnowledgeLoader, which skips five files and not this one (YamlKnowledgeLoader.fs, lines 25-31), should return the six recipes for retrieval, fingerings included. Read low to high on their string sets in standard tuning, as the file’s conventions say (line 464), no fingering should give the notes of its name or of its degree order:- The major ii–V–I, a “Rootless Drop-2 set” on strings 6-4-3-2, a drop-3 string set: “Dm9: x-5-5-5” is G C E; “G7(13,#9): x-5-4-6” is G B F, the shell of G7 with its root; “Cmaj9: 8-x-9-9-10” has five frets for four strings and, read from the sixth string up, is C B E A.
- The minor iiø–V–i, on 5-4-3-2: “Dm7b5(11): 5-6-5-6” is D A♭ C F, a drop-2 Dm7♭5 with its root and no eleventh; “G7(b9,#9): 5-4-5-5” is D F♯ C E, D9 without its fifth, with none of the four notes its degree order lists (B F A♭ A♯); “Cm(maj9): 3-5-4-5” is C G B E, a drop-2 Cmaj7.
- The pop loop, on 5-4-3-2: “G(add9): 10-12-12-10” is G D G A, without B; “D(add9)/A: 12-11-11-12” is A C♯ F♯ B, without D; “Em(add9): 7-9-9-7” is E B E F♯, without G; “C(add9)/G: 10-10-9-10” is G C E A, without D.
- The rock recipe, on 6-5-4-3: “A5(add2): 5-7-7-7” is A E A D, a fourth instead of a second; “Gsus2: 3-5-5-5” is G D G C, a Gsus4; “Dsus2/F#: 2-5-7-7” is F♯ D A D, D major over its third.
- The “So What” vamp’s “Stacked 4ths (no 3rd)”: “Dm11: 5-7-9-10” is D A E A and “Ebm11: 6-8-10-11” is E♭ B♭ F B♭, two fifths and a fourth.
- The blues recipe gives no frets; its E7, “7th on D string, 3rd on G string”, is right: D is the open fourth string and G♯ the first fret of the third.
2026-10-02 — Lesson 14: results against the predictions
Section titled “2026-10-02 — Lesson 14: results against the predictions”The program is Lesson16.cs (entry l16), its output expected/l16.txt; check.sh passes for lessons 1 to 16 and the 22 diagrams. It compiles, as they are, twelve more files of GA.Domain.Services, the voicing generator, analyzers and filters with the chord recognizer and fret distances they call, and thirteen files of GA.Business.Core, the twelve analysis records they return and a class of constants; fetch-ga.sh now adds them to its sparse checkout. The build reports one warning, CS8604, in GA’s own VoicingAnalyzer.cs (line 198), where a ModeInfo that can be null goes to a parameter that does not accept null. No MCP tool and no chatbot was called, and no test was added after the first run.
- Confirmed: 64 “Drop-2”, 64 nothing, no other label; “Drop-2” exactly when at most one voice is dropped. Wikipedia’s seven examples are rebuilt as written, and GA names none.
- Confirmed: 112 “rootless”, none open, all 128 with their root; every voicing tagged
closed-voicing, every “Drop-2”drop-2-voicings, the close ones included. On the shapes, lesson 3’s seven open chords are “rootless”, and x32010, x02210 and xx0232 “Drop-2”; x3200x is “Drop-2” and not rootless, x3545x “Drop-2” and rootless. - Confirmed: the string rule on the six shells, xx0232, x3200x and x3545x; the engine on the three sixth-string shells and the seven open triads; the filter on the three sixth-string shells and nothing else.
- Confirmed: 667,125 voicings; “Drop-2” exactly on the course’s close, drop-2, drop-3 and drop-4 voicings; 48 of 48 drop-2 shapes and 32 of 32 drop-3 shapes, none wider than four frets;
Drop2264,ClosedPosition687,Rootless672, exactly those spread over more than an octave,OpenPosition,Drop3,Drop2And4andShellVoicingsnone. Not predicted: 687 voicings in all, 141 of them beyond drop-n; drop 2s on seven string sets, the four missing from MUS-005’s table each skipping a string; the widest shapes reach the four-fret limit exactly. - Confirmed: 12 rows of 12 with the four moves, F F E and C B B in C; over 711 analyses,
HasGuideTonesnever true,TonesandOmittedTonesalways empty. - Confirmed: an entry for each of the six recipes, holding all its fingerings; the fifteen fingerings give the notes written in advance, none those of its name or degree order; the blues recipe’s E7 is right. Not predicted: the loader returns 36 entries from
ChordProgressions.yaml.
Observations, not tests:
InterpretationService, whose only caller, GaCLI’sIndexVoicingsCommand, is excluded from the build (GaCLI.csproj, line 18), looks for “drop 2” and “drop 3” with a space (InterpretationService.cs, lines 41-46), whileDropVoicingholds “Drop-2”: its drop tags never fire. Read, not run.- MUS-005, as it read at Demerzel
6aef19buntil Demerzel #1098 corrected it, called x3200x, a close position, a “Drop-2 Cmaj7”; it said “Drop-2 voicings exist on four string sets” above a table of three rows; its shell diagrams showed one note per chord. - The section on drop voicings of Wikipedia’s “Voicing (music)” is flagged “This section does not cite any sources”.
2026-10-02 — Lesson 15: predictions before the first run
Section titled “2026-10-02 — Lesson 15: predictions before the first run”Written from GA’s code at a826864 after the lesson’s program was built and before it first ran; the figures were worked out by hand from GA’s formulas, and the results entry quotes each one against what the program printed. No MCP tool and no chatbot was called for this lesson. The course places fret n at d(n) = L(1 − 2^(−n/12)) from the nut, reads every shape from string 6 in standard tuning, and takes the CAGED system from Wikipedia’s “Bar chord”.
- Where the frets go.
FretboardGeometry.CalculateSpanMm(0, n)multiplies 2^0 − 2^(−n/12) by 647.7 mm (FretboardGeometry.cs, lines 17-32), andPhysicalFretboardCalculator.CalculateFretPositionMm(n)computes 648 · (1 − 2^(−n/12)) (PhysicalFretboardCalculator.cs, lines 35-43). Both should agree with the course at every fret, on two scale lengths 0.3 mm apart: fret 12 at 323.85 and 324.00 mm. The calculator should give MUS-009’s 36.4, 162.5, 215.5, 324 and 486 mm.PHYSICAL_PLAYABILITY_IMPROVEMENTS.mdquotes 120.11, 85.42 and 70.09 mm for frets 0-5, 7-12 and 12-17, the low span “71.4% larger” than the high one. The formula gives 162.55, 108.49 and 81.27 mm, and since every distance halves an octave higher, the low span is exactly twice the high one: threeDIFFrows, and 100.0% larger. - How far a hand reaches.
ComfortableReachScaleUnitsis 0.21, commented “(1 - 2^(-4/12)) approx 0.206”, the distance from the nut to fret 4 (BiomechanicsConstants.cs, lines 25-28).PhysicalCostServicecompares it with the span of the fretted notes only (PhysicalCostService.cs, lines 25-38, andFretboardGeometry.cs, lines 38-57): open strings never count, so the lowest fret it measures from is 1. From fret 1 the reach should cover frets 1 to 5; from fret 7, frets 7 to 13; from fret 12, frets 12 to 21, ten frets. The first position, index finger on fret 1 and little finger on fret 4, measures 0.1502, well within it. The defaultPlayerProfilehas aHandSizeof Medium and aMaxComfortableStretchMmof 129 mm (PlayerProfile.cs, lines 14-17), and none of the three analyzers reads either. - CAGED. The five open shapes should give GTR-002’s degrees exactly. Raised until their root is C, they should sit at frets 0, 3, 5, 8 and 10, as Wikipedia says, each holding three or four frets and playing only C, E and G. In every key, the order up the neck should be C A G E D read round from one of its letters; in G, G E D C A at frets 0, 3, 5, 7 and 10, Wikipedia’s sequence. GTR-002’s third exercise asks for C on string 2 “in each of the five CAGED positions”: only the C shape (fret 1) and the D shape (fret 13) have it there; the A, G and E shapes play E, E and G on that string. GA’s
DetectCagedShapereturns null at once when index 0 is muted (VoicingPhysicalAnalyzer.cs, lines 264-265), and its A and C tests both need index 0 muted (lines 297 and 323), so it can only ever answer “E-Shape”. Its comments read index 0 as string 6 (line 263), whileExtractPhysicalLayoutnumbers index 0 as string 1 (line 27), the order of GA’s voicings. In that order no E shape should be recognised; the pattern that is, 001220 from string 6, plays E A D♯ A C♯ E. Reversed, the E shape should be recognised at every fret, and nothing else. The tag it writes ise-shape(line 203), which contains neither “CAGED-E” nor “E shape”, the stringsVoicingFilterEnginelooks for (VoicingFilterEngine.cs, lines 61-66; read, not run). - The effort of a shape.
PhysicalCostService.CalculateStaticCosthas no term for a barre (PhysicalCostService.cs, lines 17-142). On these shapes it should come down to the tension of the fretted strings, a register term when the average fret is below 3 or above 9, and a bonus for each open string: the open chords below zero, from −0.63 (Em) to −0.06 (D); F 0.29; the A, G and E shapes of C 0.21, 0.24 and 0.24; the D shape of C 0.59, and the E shape at fret 12 the highest, 0.66.VoicingPhysicalAnalyzershould call open C “Intermediate”, because its fretted span, 66.7 mm on 648 mm, is over 0.8 × 80 mm, and Am, Em, E, G and D “Beginner”; it finds a barre only on three adjacent strings at the same fret, so in x35553 and 875558, and not in F or the E shapes.BiomechanicalAnalyzerfinds a barre whenever three notes share a fret, open strings included (BiomechanicalAnalyzer.cs, line 153): Em, E and G should get one, along with F and the barre shapes, while Am, C, D and the D shape of C do not. It should rate F “Very Easy” (0.92), with Em and E, above open C (0.82, “Easy”). ItsHandSizeis never read, so the four hand sizes should give the same analyses; nor doesPhysicalCostServiceread the profile’sHandSizeorMaxComfortableStretchMm. UnderPlayerProfile.Beginner()the shapes above fret 5 should cost more, the D shape of C 1.04, and underJazz()that shape should cost 0.18. - Open tunings.
Tunings.tomlshould hold the same 15 guitar entries asInstruments.yaml, where MUS-009 found string 2 of Open C and Open A an octave low. As changes from standard, OpenCMajor should lower string 2 by 11 semitones and OpenAMajor by 10, while the nine other six-string tunings move no string by more than 2. Their open strings should sound the chord their names give, except OpenEMajorV2, “Open E - 2 Minor”, an E minor chord. Wikipedia’s string orders for open C, D, E and G should match. No C# or F# code of GA reads the file; a React component lists it as an optional data URL and ignores the property. - The table behind
ga_easier_voicings. The tool’s 41 voicings (GuitaristProblemTools.cs, lines 506-562) should all list inNotesthe notes of their symbol. Read in standard tuning, Gsus4 310013 should play a B♭ and C5 x3500x a B, outside their chords, and C7 x32310 should leave out its fifth, G. Five are markedHasBarre, F, B♭, B, Bm and F5; four have more than four fretted notes, while F5 has three. Under the default constraint “no-barre” the tool offers only voicings of the table on the same root (lines 611-652): Fmaj7 for F and F5, B7 and B5 for B and Bm, neither with the D of B minor, and nothing for B♭. The description’s Fsus2 (133011) and C/F are not in the table.
2026-10-02 — Lesson 15: results against the predictions
Section titled “2026-10-02 — Lesson 15: results against the predictions”The program is Lesson17.cs (entry l17), its output expected/l17.txt; check.sh passes for lessons 1 to 17 and the 23 diagrams. It compiles, as they are, seven more files of GA.Domain.Services, the fretboard geometry, the cost service with the position record and the ranker interface it takes, and the biomechanical analyzer with the records it returns, and PlayerProfile from GA.Business.Core; it reads Tunings.toml and GuitaristProblemTools.cs, a file of GA’s MCP server, as text. fetch-ga.sh now adds them to its sparse checkout. The build reports no new warning. No MCP tool and no chatbot was called, and no test was added after the first run. After an independent review, ce3a9ed relabels the two Wikipedia tables, which printed the course’s header over Wikipedia’s figure, and the tunings table, which said GA reads Instruments.yaml, and marks the reach from fret 15 as stopping at the 24th fret; no number changed.
- Confirmed: every fret right on 647.7 and 648 mm, fret 12 at 323.85 and 324.00 mm; the ratio 1.059463 at all 24 frets; MUS-009’s five figures; three
DIFFrows, 162.55, 108.49 and 81.27 mm, the low span 100.0% larger. - Confirmed: 0.21 against 0.2063; frets 1 to 5 from fret 1, 7 to 13 from fret 7, 12 to 21 from fret 12; the first position at 0.1502; the default profile Medium and 129.0 mm, which no measure reads. Not predicted: the other starting frets, 2, 3, 5 and 9, which reach frets 6, 7, 10 and 16; from fret 15 the reach runs past the 24th fret, the last of the neck; and the reach in millimetres, from 112.4 to 131.3 mm where the neck does not stop it.
- Confirmed: GTR-002’s degrees for all five shapes; C at frets 0, 3, 5, 8 and 10, three or four frets each, C, E and G only; every order a rotation of C A G E D, and G’s Wikipedia’s; C on string 2 only in the C shape (fret 1) and the D shape (fret 13), E, E and G in the A, G and E shapes. In GA’s order no shape recognized, and 001220, E2 A2 D♯3 A3 C♯4 E4, recognized as “E-Shape”; reversed, the E shape at all 13 frets and nothing else; the tag
e-shape, which failsVoicingFilterEngine’s test. - Confirmed: no barre term; the open chords from −0.63 (Em) to −0.06 (D), F 0.29, the A, G and E shapes of C 0.21, 0.24 and 0.24, the D shape 0.59, the E shape at fret 12 0.66; open C “Intermediate”, Am, Em, E, G and D “Beginner”;
VoicingPhysicalAnalyzer’s barre in x35553 and 875558 only;BiomechanicalAnalyzer’s in Em, E, G, F and the barre shapes, not in Am, C, D or the D shape of C; F, Em and E “Very Easy” at 0.92, open C “Easy” at 0.82; the same results for the four hand sizes, and for a profile’sHandSizeandMaxComfortableStretchMm; the D shape of C at 1.04 underBeginner()and 0.18 underJazz(). Not predicted: the scores not quoted above, such as 6.90 for 875558 and 0.72 for the D shape of C. - Confirmed: the 15 entries as in
Instruments.yaml; string 2 lowered by 11 semitones in OpenCMajor and by 10 in OpenAMajor, no string moved by more than 2 in the nine others; OpenEMajorV2 an E minor chord; Wikipedia’s four string orders. That GA’s C# and F# never read the file was checked by searching the code ata826864, not by running it. - Confirmed:
Notesright for 41 of 41; Gsus4’s B♭, C5’s B, C7 without G;HasBarreon F, B♭, B, Bm and F5, more than four fretted notes on all but F5; Fmaj7 for F and F5, B7 and B5 for B and Bm, nothing for B♭; Fsus2 and C/F not in the table. Not predicted: B7 holds all of B’s notes and B5 does not; 133011 has five fretted notes.
Observations, not tests:
PHYSICAL_PLAYABILITY_IMPROVEMENTS.mdpresents its spans as the output ofFretDistance_SameFretSpan_DifferentPositions_ShouldHaveDifferentPhysicalDistances, a test inPhysicalFretboardCalculatorTests.cs, which GA’s test project removes from compilation (GA.Business.Core.Tests.csproj, line 47). The same project removesBiomechanicalAnalyzerTests.cs(line 49), whose hand-size tests callBiomechanicalAnalyzer.CreateForHandSize, a method the class does not have. Read, not run.MusicalEmbeddingGeneratorappends “-shape” to the lower-casedCagedShape(MusicalEmbeddingGenerator.cs, lines 110-113), which would givee-shape-shape. Read, not run.- GTR-002’s figure “for key of E major” draws the shapes on a scale of frets 0, 3, 5, 7, 8, 10 and 12; the program finds them at 0, 2, 4, 7 and 9.
- The Guitar Alchemist Lab’s P7 found open C “Intermediate” and no barre in 133211 at GA’s commit
66bdd04, as this lesson did ata826864.
2026-10-02 — Lesson 16: predictions before the first run
Section titled “2026-10-02 — Lesson 16: predictions before the first run”Written from GA’s code at a826864 after the lesson’s program was built and before it first ran; the results entry quotes each one against what the program printed. No MCP tool and no chatbot was called for this lesson: the program compiles GA’s two chatbot skills and calls them directly, with stand-ins for the logger and the query extractor they take, and it reads the MCP tool as text and applies it. The course builds the seventh chord on each degree by stacking thirds within the scale, and takes the chord-scale pairs from Wikipedia’s “Chord-scale system” and “Jazz improvisation” and the avoid note from its “Avoid note”.
- Arpeggios and modes. The seventh chords of C major are Cmaj7, Dm7, Em7, Fmaj7, G7, Am7 and Bm7♭5, and those of A minor are the same seven from Am7. The arpeggio suffixes of the tool’s two tables (
GuitaristProblemTools.cs, lines 386-406) should match all fourteen, andImprovisationSkill.ArpeggioForshould give each chord’s own symbol back (ImprovisationSkill.cs, lines 266-284). The tables’ Mode and Notes columns should match the mode on each degree, and so should GA’sMajorScaleMode. Of the twelve other scales the tool and the skills name, GA’s mode in the same place of its class should match ten. The two exceptions are GA’s diminished modes, as in lesson 12: the first, which GA names “Half-whole diminished”, begins with a whole step, and the second is the reverse, so both rows should readDIFF. ga_arpeggio_suggestions. The tool finds the degree from the chord’s root alone (line 463) and returnschord + arpeggioSuffix(line 482): the whole symbol, followed by the table’s suffix. For its own example, Am F C G in C major, it should return “Amm7”, “Fmaj7”, “Cmaj7” and “G7”, not the “Am7” of its description (line 412). For a ii–V–I written with sevenths it should return “Dm7m7”, “G77” and “Cmaj7maj7”. The mode comes from the degree, not from the chord. In A major, A7, E7 and D7 should get Ionian, Mixolydian and Lydian, which puts A7’s G and D7’s C outside the mode, where Wikipedia’s chord-scale system pairs all three with Mixolydian. An A major chord in C major should get Aeolian, whose C clashes with the chord’s C♯;ImprovisationSkill’s remarks describe this case (lines 23-32). E7 in A minor should get Phrygian, which lacks the chord’s G♯. The key’s second word names the mode, and any word but “minor” means major (lines 428-430 and 450). A key written “Am” should therefore read “Am major”, that is A major: Am gets “Ammaj7” and Ionian, with C outside, and Dm gets “Dmmaj7” and Lydian, with F outside. B♭ in C major is chromatic: it should get “Bb (chromatic — outside key)”, “depends on context” and the notes “R, M2, M3, P5” (lines 464-475).ImprovisationSkill.InferQualitylowercases the symbol before matching it (line 323), so CM7 should read “minor 7”: arpeggio Cm7, Dorian first, and E and B outside all three of its scales. Over the 31 symbols on C, the first scale offered should hold every note of the chord except for seven symbols. They are CM7; Cmaj7♯5, read “major 7” because line 340 comes before line 343, with G♯ outside both Ionian and Lydian; C7♯11, whose Mixolydian lacks the F♯ that Lydian Dominant has; C7♭13 and C7+5, read “dominant 7”, whose Mixolydian lacks the A♭ or G♯ that Mixolydian ♭6 has; and C7♭9 and C7♯9, read “altered dominant” with the arpeggio “C7alt”, where the Altered scale lacks the chord’s G and Half-Whole Diminished holds all five notes. Cadd9, Csus2, Csus4 and C5 should read “unknown” and get the major scale of the root. C6 and C69 should read “major triad”, arpeggio C; Cm6 “minor major 7”, arpeggio CmMaj7; C7♯5 “augmented”, arpeggio Caug.CanHandleshould accept 16 of its 17 example prompts. It should turn down “what scales fit over the progression Cmaj7 A7 Dm7 G7” (line 74), which holds none of its keywords as a whole word: there “what scale” is followed by an s (ChordIntentMatching.cs, lines 22-35). On a run of chords the skill reads each symbol on its own (lines 196-261). Am F C G should give A Aeolian, then F, C and G Ionian; F Ionian has a B♭ and G Ionian an F♯, notes none of the four chords has. A7 E7 D7 should give Mixolydian three times, Wikipedia’s answer. GAA-003’s Dorian vamp, Am7 D7, should give A Dorian and D Mixolydian. Its Mixolydian vamp, A7 G/A, should read as three chords, A7, G and A, with A Ionian for the last.OutsideNotesSkill.Classifycalls a note outside the chord an avoid note when it lies a semitone above a chord tone, and a tension otherwise (lines 141-189). The avoid notes should be D♭, F and A♭ over Cmaj7, with D, E♭, F♯, A and B♭ as tensions; D♭, F, A♭ and B, the major seventh, over C7; D♭, E, A♭ and B over Cm7; D♭, E, G and B over Cm7♭5. The comment on dominant chords names “the b9/#9/#11/b13 half-step clashes” (line 164), but over C7 D♯ (♯9) and F♯ (♯11) should be tensions, and F and B avoid notes. Some tensions are in none of the scalesImprovisationSkilloffers for the same chord: E♭ and B♭ over Cmaj7, E♭ over C7, F♯ over Cm7 and A over Cm7♭5. The skill should answer seven of its ten example prompts (lines 48-63): F an avoid note over Cmaj7, three times; A and F♯ tensions over Cmaj7; F the minor seventh of G7, thoughCanHandleturns that prompt down for lack of a keyword; and B♭ over C major “an available tension — the b7 (minor seventh)”, measured against a C major triad. “why does that note clash over the chord” and “why does the b9 sound so tense over C7” should passCanHandleand get no answer, since no capital note comes before “over”; the first passes only because the chord pattern ignores case (line 292) and reads “the chord” as a C chord. “why does the note clash over this chord” should fail both.- GAA-003 through
Classify. The module’s answer to its first self-check question says that over Am7 no note of A minor pentatonic lies a half step from a chord tone, and that over A7 C lies a half step below the chord’s C♯ and D a half step above it. Over Am7,Classifyshould agree: A, C, E and G are chord tones, and D is a tension (the 11). Over A7 it should see only half of that rub: D is an avoid note (the 11), but C is a tension (♯9). The notes the module says pull each mode away should all be avoid notes: F in A Dorian over Am7, the ♭13; G♯ in Mixolydian over A7, the major seventh; D in Lydian over Amaj7, the 11. The thirds of A7, D7 and E7 fromChordVocabulary.GetFormula("dominant 7")(ChordVocabulary.cs, line 121) should be C♯, F♯ and G♯, the module’s targets. - GA’s improvisation entries and box 1.
ImprovisationConcepts.yamlholds four concepts (lines 6-14), each with a name and aConceptline and none with aCategory.YamlKnowledgeLoadershould return four entries, with an empty category and the file name as their only tag (YamlKnowledgeLoader.fs, lines 65-91). Their content should be the name followed by “Concept: …”, and none of them pairs a scale with a chord. GAA-003’s box 1 is frets 5 and 8 on strings 6, 2 and 1 and frets 5 and 7 on strings 5, 4 and 3. It should play A, C, D, E and G, the notes of GA’s fifth mode of the major pentatonic, and the module’s three modes on A should match the course’s spelling.
2026-10-04 — Fixes proposed to Guitar Alchemist
Section titled “2026-10-04 — Fixes proposed to Guitar Alchemist”Three rows of the QA table went back to GA in PR #810, and one in PR #808, opened from a separate clone at main 75959835. Neither is merged yet: GA leaves the review and the merge to someone other than the author.
-
Scale.Tritonebecomes C D♭ E G♭ G B♭, the notes of the Petrushka chord: 6 transpositions, where the old set, C D♭ E F♯ G A, had 12.Scales.yamlandExtendedScales.yamlfollow, so the catalogs give the name “Tritone” to binary ID 1235 instead of 723. -
DiminishedScaleDegreenames degree 1 “Whole-half diminished” and degree 2 “Half-whole diminished”, after the first step of each mode ofScale.Diminished. -
IsSymmetricalSetalso compares the step from the last pitch class back to the first: it is true for 16 of the 4096 sets instead of 156, which included all 66 dyads and C D E. -
In #808,
SpecializedTunings.yamlis valid YAML.YamlKnowledgeLoader.LoadAllKnowledgeEntries(), called from a file-based app that referencesCommon/GA.Business.Config/GA.Business.Config.fsproj, counted by source file:main 75959835[YamlKnowledgeLoader] Skipping SpecializedTunings.yaml: While parsing a flow sequence, did not find expected ',' or ']'.entries: 192#808 (e4ce3cc6)entries: 213SpecializedTunings: 21The 15 other files give the same counts on both.
ChordProgressions.yamlandGuitarTechniques.yaml, which GA’s typed C# loaders can’t read onmain, give 36 and 10 entries there: this loader reads any valid YAML into plain objects.
The row on ChordFormula.GetSymbolSuffix (lesson 13) was already fixed upstream when the course measured it. The course reads GA at a826864, a commit of 2026-09-14, and PR #680, merged on 2026-09-17, adds the “maj”. "C" + Chord.FromSymbol(symbol).Formula.GetSymbolSuffix() gives C9, C11 and C13 for Cmaj9, Cmaj11 and Cmaj13 at a826864, and the symbol itself at #680’s commit 86f81ab2 and at main 75959835.
Eleven more rows went back the same day in four pull requests, opened from the same clone and measured before and after on main 75959835. When this entry was written, GA’s CI had passed on #818, #819 and #820’s first commit, and was running on #820’s second commit and on #823. None is merged yet.
| PR | QA rows | Before → after |
|---|---|---|
| #818 | Modes.yaml’s vectors and rotations, the names YAML cut as comments, the alternate names; the “Scale:” line in part |
Names cut: 8 of 165 → 0; modes that keep their alternate names: 0 → 79; declared vectors that differ from their family’s notes: 2 of 18 → 1; members without their first mode’s vector: 26 of 134 → 22 |
| #819 | Drop voicings, the drop filters, shells | Over the 313,047 voicings of GA’s voicing audit, DropVoicing follows Wikipedia’s definition on 225,338 → all; on lesson 14’s 687 seventh chords on C: Drop2 264 → 111, Drop3 0 → 92, Drop2And4 0 → 143; shell-voicing on 57,981 voicings → on the 877 shells |
| #820 | ChordSymbolParser; CM7 in Chord.FromSymbol |
Lesson 13’s symbols right: 17 of 41 → 41; “Can” C major, “Give” G major → rejected |
| #823 | GenerateAllPossibleChords |
25,900 templates → 12,950, the first half, in the same order |
- The course reads GA at
a826864, and onmainsome rows had already moved: 2 of the 18 declared vectors differed, not 9, and 26 members lacked their first mode’s vector, not 60. - Codex reviewed #818: the augmented triad’s inversions were spelled C E G♯, like the root position. They are now C E A♭ and C F♭ A♭, spelled by their intervals above the bass, as the other inversions are.
- #820 rejects what the parser can’t read. The chatbot, which tries it on a whole message, now finds no chord in “Cmaj7 jazz voicings”, where it found C major.
- Codex’s review of #820 found that the parser read a slash chord’s bass, then dropped it:
C/Ehad C as itsBass. A second commit puts the bass note first, soC/Eis E G C. GaApi’s voicing search still ignores it, since it passes only the pitch classes. - #823’s first commit also removed
NaturalMinorMode, whose seven modes are the major scale’s, under the same names: its 1,666 templates have the same notes and pitch classes as the major modes’. Codex pointed out that their mode’s parent scale differs (A B C D E F G, notC D E F G A B) and thatCreateTraditionalChordLibrarypromises those modes, so a second commit puts them back. - The
ChordAlterationServicerow went to no PR: onlyChordTemplateNamingServiceandHybridChordNamingServicecall it, and no app, MCP tool or chatbot path calls those at 75959835.
2026-10-07 — Lesson 16: results against the predictions
Section titled “2026-10-07 — Lesson 16: results against the predictions”The program is Lesson18.cs (entry l18), its output expected/l18.txt; check.sh passes for lessons 1 to 18 and the 23 diagrams. Codex wrote the program and the predictions on 2026-10-02, before Program.cs had an entry for it; this session took the work over, added the entry and ran the program for the first time on 2026-10-07. It compiles, as they are, five files of GA.Business.ML, the two skills, the keyword matcher, the chord vocabulary and the skill interface, and the attribute of GuitarAlchemist.Registry they carry; StandIns.cs replaces the four types they take from code with packages the course does not build: the logger, the response record, the LLM query extractor and its query. It reads GuitaristProblemTools.cs as text, as lesson 15 did. fetch-ga.sh now adds the six files to its sparse checkout. The build reports no new warning. No MCP tool and no chatbot was called. After the first run, three tables were realigned, with no value changed, and one block was added under a title that says so: OutsideNotesSkill’s whole answer for B over C7, and for E and B over CM7.
- Confirmed: the fourteen suffixes and the fourteen symbols of
ArpeggioFor; the Mode and Notes columns of both tables andMajorScaleMode; ten of the twelve other scales, and the two diminished modesDIFF. - Confirmed: “Amm7”, “Fmaj7”, “Cmaj7” and “G7”; “Dm7m7”, “G77” and “Cmaj7maj7”; Ionian, Mixolydian and Lydian for A7, E7 and D7, with G and C outside; Aeolian for A in C major, against its C♯; Phrygian for E7 in A minor, without its G♯; “Am major”, with “Ammaj7” and C outside, “Dmmaj7” and F outside; B♭ chromatic, with the three fixed strings. Not predicted: the arpeggios “Am7” for the A major chord and “E7m7” for E7. Found after the run: GA #626, merged on 2026-09-24, fixed the suffix and the degree upstream; on
mainc1416eeethe key is read as before. Read, not run. - Confirmed: CM7 “minor 7”, arpeggio Cm7, Dorian first, E and B outside all three scales; seven symbols whose first scale lacks a note: CM7, Cmaj7♯5 (G♯, in neither of its scales), C7♯11 (Lydian Dominant holds it), C7♭13 and C7+5 (Mixolydian ♭6), C7♭9 and C7♯9 (Half-Whole Diminished); Cadd9, Csus2, Csus4 and C5 “unknown”; C6 and C69 “major triad”, arpeggio C; Cm6 “minor major 7”, arpeggio CmMaj7; C7♯5 “augmented”, arpeggio Caug; 16 of 17 example prompts, the progression prompt turned down; A Aeolian, then F, C and G Ionian; Mixolydian three times; A Dorian and D Mixolydian; A7, G and A, with A Ionian. Not predicted: the remark “careful on the IV chord” under C and G as under F. Found reading the code after the run:
ChordVocabulary’s remarks describe the CM7 regression. - Confirmed: the avoid notes and tensions of all four columns; the five tensions in none of the skill’s scales; seven answers, F over G7 answered though
CanHandleturns it down, B♭ measured against a C major triad; two prompts that passCanHandleand get the help text, one that fails both. Not predicted, added after the run: the advice for B over C7, “exactly the kind of altered tension players reach for (major 7th on the V)”, and CM7 read as a major seventh by this skill. - Confirmed: over Am7, four chord tones and D the 11; over A7, D an avoid note and C the ♯9; F, G♯ and D avoid notes, the ♭13, the major seventh and the 11; C♯, F♯ and G♯.
- Confirmed: four entries with an empty category, the file name as their only tag, the name then “Concept: …”; box 1 A C D E G, GA’s “Minor pentatonic”; the three modes. Not predicted: 192 entries from 15 files,
SpecializedTunings.yamlskipped as on 2026-10-04.
Observations, not tests:
- Since GA #626,
ga_arpeggio_suggestionsonmainnames arpeggios throughImprovisationSkill.InferQuality, so the tool would now read CM7 as a minor seventh too. Read, not run. - The lesson cites GAA-003 at Demerzel
0f7a5fd, the commit of the site’s last Streeling sync.
To verify
Section titled “To verify”- Whether GA’s full chord recognizer (not
TryFindExactalone) names inversions such as032010; the MCP voicing search suggests it does (C/E), but the course did not call it. - The MCP server’s commit: the answers above were not reproduced against a server built from
a826864. HarmonicFunctionAnalyzer.Parseon “Supertonic” and “Submediant”, by a test in GA.- The spokes and symmetry axes of GA’s
BraceletNotation, rendered in a browser. domain.commonToneson a server built after #681: the fix was read on5c3a52a, not run.- The chatbot’s own answers to “voice leading C major to G major” and “voice leading from G to Cmaj7”, rather than the course’s rewrite of its rule.
- Whether a later GA registers
YamlKnowledgeSyncServiceand lets an agent search theyaml_knowledgecollection, so that the wrong lines ofModalInterchange.yamlcan reach an answer. - Both live
ga_chord_substitutionstools, the MCP server’s closure and GaApi’s tool of the same name, against lesson 10’s results. get_borrowed_chordsthrough the MCP server and through GaApi, rather than the service compiled alone.get_mode_infoandget_available_modesthrough the running MCP server, rather thanModesConfigalone:get_mode_info("Ionian Augmented")should answer with C D♯ E F G♯ A B.- What the chatbot’s
ModesSkill, which readsGetModalFamiliesand so keeps the alternate names, answers for “Ionian Augmented”, “Altered bb7” and “Lydian”. - The “Scale:” line of the live
ga_chord_to_setfor Cmaj7, G7 and Cm. ModesSkill’s live answer to “modes of limited transposition”, rather than the course’s rebuild of its format.- The “Scale:” line of the live
ga_chord_to_setfor Messiaen’s sixth mode, C D E F G♭ A♭ B♭ B: the lookup says “Diminished (Half-Whole)”. - The chords
GenerateFromSymmetricalScalesbuilds from the 20 modes, and which modesModalCharacteristicIntervalServiceloses to its overlapping indices, by running them. VoicingFilterServiceon “Cmi7” and the chatbot on “Can you analyze this progression: Dm7 G7 Cmaj7”, run rather than read.- The live
ga_polychordon B over C and C over F♯, against the course’s copy of its code. - GA’s full chord recognizer, not
TryFindExactalone, on the voicings x3233x, x32335 and x3234x. - The live
ga_search_voicingson “drop2”, “shell” and “rootless”: which voicings the index returns for each tag. AutoTaggingService’s “Shell” tag on the indexed corpus, run rather than read, and whether a later GA buildsIndexVoicingsCommandagain, which would makeInterpretationService’s drop tags reachable.- What the chatbot answers when asked for drop-3 voicings, since GA labels none.
- The live
ga_easier_voicingson F, Bm and B♭, rather than the course’s reading of its filter, and the substitution hints it adds fromdomain.chordSubstitutions. - Whether a later GA reads
Tunings.toml, or letsHarmonicNavigator3Duse itstuningsanddataUrlsproperties. ga_arpeggio_suggestions,ImprovisationSkillandOutsideNotesSkilllive, on lesson 16’s requests, rather than the tool read as text and the skills compiled alone; and onmain, whether the tool, which now callsInferQuality, reads CM7 as a minor seventh.