Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
85 KiB
Ensemble Ledger — Live Task Board
The shared queue all agents read and write. Lifecycle and rules: PROTOCOL.md. Roster + cadence weights: ROSTER.md.
Status: backlog → ready → claimed → in-review → done / returned
Lock: a task's files column is its lock — no two claimed/in-review tasks may overlap files.
Active sprint: sprint-integrated-glance (branch: sprint-jamguide-piano — continued; commits extend PR #3)
Goal (user directive 2026-07-10, after testing the glance-mode sprint — "its already a lot better, but"):
- Move it up & integrate — "i would like to move it up and integrate it somewhat in the space of the main module up top. or maybe right below it as it is super important." The Jam Guide content is currently the LAST mount in App.jsx (line ~712); the main module (ProgressionBanner + instrument view) is at ~609-622.
- One loop display — "i would like to be able to see the loop clearly, no need to have this repeated again. as its already in the main module." ProgressionBanner (top) and the Roadmap track (inside JamGuide) both show the detected loop — exactly one clear loop display must survive.
- One instrument selector — "only one selection for GUITAR/PIANO/BASS and everything should show in that instrument." App.jsx line 58 ALREADY holds global
instrumentstate ('piano'|'guitar'|'bass') driving the main views; JamGuide ignores it and has its own internal tabs. Everything (voicings, licks, guide) must follow the one selector. Bass has a main-view BassFretboard but zero KB content — needs an honest state (and a stretch chain to make it real). - All chords' voicings visible at once — "it's difficult to see as it changes when the chord is not playing so i'd like to see all the chords and their voicings in a specific way in case a loop is detected (or at least just like 4 chords or something at least, so you can follow and potentially learn new ways to play it while you are playing the loop." The playhead accordion (only the active station expanded) is hard to follow live — show EVERY loop station's voicings simultaneously (≥4 chords), playhead highlights rather than reveals.
- Scroll-first — "scrolling is easier then clicking." Layout principle for everything above.
Loop: /jam-loop every 30 min for 12 h (24 iterations), started 2026-07-10 evening (cron 13,43). "let each agent do a part and revise the work" — standard ensemble + gates. Weights: Luthier 3, Muse 3, Professor 2, Critic gate.
| id | title | domain | status | depends-on | files (lock) | definition of done |
|---|---|---|---|---|---|---|
| M-05 | Seed sprint-integrated-glance; schedule the 24×30m loop |
maestro | done | — | docs/agents/LEDGER.md |
seeded, cron created |
| D-40 | Integration concept doc: (a) where the Jam Guide content lands relative to the main module (in it vs right below — pick, record rationale); (b) which loop display survives (ProgressionBanner vs Roadmap track — the loser's unique value, e.g. guide-tone rails, must be honestly dispositioned); (c) JamGuide obeys App's existing global instrument — internal tabs retired; honest bass state until the bass chain lands; (d) the all-stations-expanded voicings layout (≥4 chords visible, playhead HIGHLIGHTS not reveals, scroll-first — the user explicitly licensed scrolling, so D-31's "everything expanded" rejection is overturned by directive); (e) what remains of the four-section dock below; (f) honest space math + migration order. No user gate: pick strongest, record rejected alternatives |
design | ready | — | docs/design/integrated-glance.md |
doc names every component, the single-loop-display call, the instrument-threading contract, ≥2 rejected alternatives, bounded L-40/D-41 scopes |
| L-40 | App restructure per D-40: promote the Jam Guide content to the D-40 position; retire the duplicated loop display per the doc's call; JamGuide takes instrument as a prop from App's existing selector (internal tabs removed; VoicingsSection/LicksSection/ExplorePanel mounts follow too); honest bass empty-state. 🚨 App.jsx changes = layout/mount/UI-state ONLY — audio callbacks/refs/AudioCapture untouched (grep-gated) |
engineering | backlog | D-40 | src/App.jsx (layout + UI-state only), src/components/JamGuide.jsx (+ files D-40 names — re-lock at promotion) |
one selector drives everything; guide content up top; loop shown exactly once; build + smoke green; audio contract grep-clean |
| D-41 | All-expanded voicings rail per D-40: every station's gallery visible simultaneously (≥4 chords), active station highlighted by the playhead (accent ring/header, NO reveal/hide), scroll-first reflow, licks strip follows the global instrument per the doc | design | backlog | D-40, L-40 | src/components/GlanceRail.jsx (+ per doc — re-lock at promotion) |
all voicings of all loop chords on screen/scroll with zero clicks; playhead never hides content; AA + tokens; build + smoke green |
| C-40 | Drift guards in smoke (two hand-synced duplications, backlog debt): (a) JamGuide's resolveDegree copy vs validator's — 16-degree × 14-quality truth table; (b) technique vocab validate-kb.mjs LICK_TECHNIQUES ↔ LickCard.jsx TECHNIQUE_VOCAB. Ride-along: fix scripts/loop-fixtures.mjs header's stale "App.jsx:322-324" line-ref (C-31 sweep finding) |
quality | ready | — | scripts/smoke.mjs, scripts/loop-fixtures.mjs (comment only) |
drift in either duplication turns smoke red (sabotage-proven); header ref current; smoke green |
| P-40 | Refresh docs/kb-backlog.md: mark all shipped cells done (gospel/pop guitar; jazz/gospel/rnb/blues piano), set the bass column as next (blues → jazz → funk per plan) |
content | ready | — | docs/kb-backlog.md |
backlog reflects reality; next-cell pointer correct |
| C-41 | Bass play schema (additive): SCHEMA.md + validator + smoke bite-test for bass patterns (per-station patterns: root/fifth/approach-note walks — design the minimal honest shape with 4-string, fret 0-15 representation) | quality | backlog | C-40 | src/data/kb/SCHEMA.md, scripts/validate-kb.mjs, scripts/smoke.mjs |
schema documented; validator enforces; existing KB untouched-green; smoke proves the check bites |
| P-41 | First bass cell: blues bass (kb-backlog order blues → jazz → funk) | content | backlog | C-41 | src/data/kb/blues/bass.js, src/data/kb/index.js |
validator green; every pattern playable as written; prose arithmetic-verified |
| L-42 | Minimal bass pattern renderer for the guide (per-station bass display per D-40's naming; BassFretboard covers the main view already) — makes the BASS selector real end-to-end | engineering | backlog | C-41, P-41, L-40 | per D-40 doc — re-lock at promotion | bass stations render the authored patterns; guitar/piano paths untouched; build + smoke green |
| C-42 | Sprint-end sweep + PR #3 update per PROTOCOL §6 | quality | backlog | L-40, D-41 | (none — verification) | all green; PR updated |
Sequencing: D-40 ‖ C-40 ‖ P-40 file-disjoint, ready now. Then D-40 → L-40 → D-41 (App/JamGuide/GlanceRail serialized — same surfaces), and C-40 → C-41 → P-41 → L-42 (bass chain, stretch). C-42 closes. Critic gates every task.
Shipped sprint: sprint-glance-and-loop (branch: sprint-jamguide-piano — complete 2026-07-10, 4 iterations, PR #3 updated)
Goal (user directive 2026-07-10): three asks, in the user's words:
- All voicing variations in one view — "in the music theory … see all the variations G shape, C shape, etc in one view without having to push a button. so they all line up next to each other." VoicingBrowser currently chip-switches one shape at a time; replace with a gallery that renders every shape/style side by side, each independently playable.
- Fix the loop logic — "it doesn't recognize when 3 chords return, or when its 5 and then 2 others."
detectRepeatingProgression(theory.js) does exact contiguous block matching, lengths 2–6: one spurious misdetected chord breaks a rep; a 5-chord loop followed by 2 foreign chords (tag/turnaround) is missed; 7–8-chord loops can't be found at all. Redesign to be noise-tolerant; tune the App.jsx commit layer so a committed loop survives fills. - Glanceable learn session — "expand the learn session so we see as much as possible in voicing variations and styles without having to click buttons, the idea is to have it open as the jam is playing." Knowledge Center should auto-follow the live jam with zero clicks.
Loop: /jam-loop every 30 min for 12 h (24 iterations), started 2026-07-10 (cron 13,43). User is away — no user-gated tasks; Muse picks the strongest option and records rationale. Weights: Luthier 3, Muse 3, Professor 1, Critic gate, Herald 0.
| id | title | domain | status | depends-on | files (lock) | definition of done |
|---|---|---|---|---|---|---|
| M-04 | Seed sprint-glance-and-loop from user directive 2026-07-10; schedule the 24×30m loop |
maestro | done | — | docs/agents/LEDGER.md |
sprint seeded, cron created |
| C-30 | Loop-detection truth fixtures: new scripts/loop-fixtures.mjs (+ smoke wiring) — realistic chord-history cases with expected loops: (a) clean 3-chord loop ×2–3 reps; (b) 3-chord loop with one spurious misdetection inside a rep; (c) consecutive duplicate commits of the same chord; (d) 5-chord loop followed by 2 foreign chords — loop must survive; (e) 7- and 8-chord loops; (f) section change loop-A→loop-B — detection must switch; (g) chromatic non-loop → null. Run each against the CURRENT detectRepeatingProgression and mark which fail today (expectedFail: true) so the suite is green now and L-30 flips the markers off |
quality | done | — | scripts/loop-fixtures.mjs, scripts/smoke.mjs |
fixtures runnable via smoke; failure map of the current algorithm documented in the fixture file header; smoke green (expected-fails annotated, not silently skipped) |
| L-30 | Redesign detectRepeatingProgression in theory.js: collapse consecutive duplicate chords before matching; tolerate ≤1 substitution/insertion per cycle (noise from misdetection); support loop lengths 2–8; recency-weighted scoring so an old section can't outvote the current loop; keep the pure signature, the rotation-canonicalize output, and every other export byte-untouched. Flip all C-30 expectedFail markers to passing. C-30 findings folded in (2026-07-10): (a) the reps × len² scoring artifact is the primary everyday bug — a clean 2-chord vamp ×4 reports a bogus 3-chord [Am,Am,G] via self-overlapping occurrences; candidate generation must reject candidates that are rotations/overlaps of a shorter period (not just exact periodic patterns at len ≥ 4); (b) 7/8-loops contain realistic non-adjacent internal chord repeats (Am … Am) — period detection must not collapse those into shorter false loops |
engineering | done | C-30 | src/lib/theory.js (detectRepeatingProgression + private helpers only) |
all C-30 fixtures green with zero expectedFail markers (incl. vamp-2x4/vamp-2-sustained); no other theory.js export changed; build + smoke green |
| L-31 | Commit-layer tuning in App.jsx's progression effect (lines ~154-173): a committed loop must survive transient misses (the miss-4-then-clear rule drops the loop during fills/turnarounds); a new loop replaces the old only with consistent evidence; first commit shouldn't need extra rounds when detection is already stable. Primary trace case (C-30 finding, 2026-07-10): pre-L-30 detection flaps between the true loop and ghost 4-patterns, so progressionVoteRef never sees 2 consecutive identical keys and nothing ever commits — verify post-L-30 stability makes the 2-vote commit reachable in the noisy fixtures, then tune (post-L-30 status: done). L-30 gate findings folded in (2026-07-10): (a) a 2-rep loop with one corrupted rep FLAPS through data-faithful sub-cycles commit-to-commit until the next clean rep — faster first-commit must NOT let a single transient sub-cycle detection replace an already-committed loop (replacement needs consistent evidence); note non-null detection resets the miss counter, so today's committed loop already survives the flap; (b) ride-along one-line fix: theory.js ~line 601-603 docstring overclaims "ghost occurs exactly once by construction" — false for same-chord-same-phase corruption (behavior fine, comment too strong); (c) deletions untolerated by design — fine at ≥3 reps, degrades to (a)'s flapping at exactly 2. 🚨 Audio contract: touch ONLY the progression useEffect + its refs — no callback, ref-sync, or AudioCapture change |
engineering | done | L-30 | src/App.jsx (progression effect only) |
loop survives fixture-style fills end-to-end (hand-trace documented in commit); App.jsx diff confined to the progression effect block; build + smoke green |
| D-30 | VoicingBrowser gallery: render ALL matching guitar shapes side by side (each = label + ChordDiagram + its own ▶) and all four piano styles side by side (label + MiniPiano thumb + ▶) — no chips, no selection state; grid wraps on narrow viewports; one-at-a-time playback preserved (new play stops the previous). All existing mounts (Voicings section, ChordDetailModal tabs, JamGuide station-enlarge) get the gallery automatically; show prop semantics unchanged |
design | done | — | src/components/VoicingBrowser.jsx |
every placeable shape/style visible simultaneously with zero clicks; AA contrast + tokens; keyboard-reachable play buttons; build + smoke green |
| D-31 | Glance-mode concept doc: the Knowledge Center panel open WHILE the jam plays — what auto-follows live detection with zero clicks (current station's voicing gallery inline? licks strip for the style? what stays on screen vs behind interaction), density/space budget vs the Roadmap track, narrow-viewport plan, and the migration order for L-33. No user gate: pick the strongest layout, record rationale + rejected alternatives. Returned once (2026-07-10): piano gallery width understated ~45% (2-octave crops for rootless 7th-chord voicings → ~940px not 640; scroll is the piano rail's normal state on most loops) + licks strip ~190px not 150 + 4 clarifying notes; layout itself held — fixed + re-gate PASS | design | done | — | docs/design/glance-mode.md |
doc names every component to touch, the auto-follow rules, and honest space math (what fits at 1280×900 and at narrow) |
| L-33 | Implement glance mode per D-31 (docs/design/glance-mode.md — the "playhead accordion"): the station column at canonicalPos expands to the full D-30 gallery and advances with the playhead; licks strip below (level-filtered, token-boundary context match, strip-owned "fits — now" chrome, guitar licks under piano tab with honest heading); pin gesture inherits onFocusChord semantics; auto-follow never emits focus-chord and never auto-plays audio; piano rail EXPECTED to scroll (never assert one-row fits); follow the doc's 5-commit migration order |
engineering | done | D-30, D-31 | src/components/GlanceRail.jsx (new), src/components/JamGuide.jsx, src/components/VoicingBrowser.jsx (optional additive dense prop only) |
glance behaviours live per the doc; audio contract intact (App.jsx untouched or additive-only); build + smoke green |
| P-30 | KB expansion: neo-soul/rnb piano cell (next per docs/kb-backlog.md after jazz/gospel) |
content | done | — | src/data/kb/rnb/piano.js, src/data/kb/index.js |
validator green + registered; renders in the piano tab; prose claims arithmetic-verified |
| P-31 | KB expansion: blues piano cell. Returned once (2026-07-10): turnaround jump-kicks bars 3-4 dyad orientations flipped (breaks the play's own only-leap law — gate pre-verified the exact swap) + 2 prose rewordings (♭7 "unmoved all night" contradicted by bar 9; "octave-and-change" actually a major 7th) — fixed + re-gate PASS | content | done | P-30 | src/data/kb/blues/piano.js, src/data/kb/index.js |
validator green + registered |
| C-31 | Sprint-end sweep: full build + validator + smoke + fixtures, then update PR #3 (push + PR body/comment summarising this sprint) per PROTOCOL §6 | quality | done | L-31, L-33, D-30 | (none — verification) | all green; PR #3 updated |
Sequencing: C-30 ‖ D-30 ‖ D-31 ‖ P-30 are file-disjoint and ready now. Then C-30 → L-30 → L-31 (serial chain on theory.js/App.jsx), and D-30+D-31 → L-33. P-31 fills spare iterations. Critic gates every task.
GATE 2026-07-10 (Critic) · D-30 PASS (
0945a08) — scope confined to VoicingBrowser.jsx; build green, smoke 809/809, validator green. SSR of the real component (Cmaj7/G7/Asus2/F#m7 × show variants): guitar cell count === independently re-derived matchingShapes count (4/4/3/3), all four piano labels honest, ZERO chips/aria-pressed (button count === cell count), every ▶ aria-labeled chord+voicing, rootPc badge guard proven (rootless voicings show 0 R badges, root/shell exactly 1; buggy variant rendered + diffed = absent), show prop scoping correct, E-add9 empty state graceful. Playback single-handle verified by read. Non-blocking: thumb-size diagrams drop finger numbers → backlogged.
GATE 2026-07-10 (Critic) · C-30 PASS — smoke 809/809 exit 0 with 8 annotated expected-fails (printed with today/contract values, never skipped); validator + build green. Failure map independently recomputed against the real function: vamp-2x4 self-overlap 2×3²=18 > pair 4×2²=16 → bogus
[Am,Am,G]✓; spurious-substitution ghost 4-pattern 2×16=32 > true 3×9=27 ✓; section-change stale-A 48 > 27 ✓; five-plus-tag genuinely passes pure-function (L-31 attribution honest) ✓. Sabotage ×3: broken guard → exit 1 named; stripped expectedFail → exit 1; stale marker → exit 1 with explicit STALE message — none can rot silently.canonicalLoopreplica byte-equivalent to theory.js's privatecanonicalize+ load-time self-check. clean-2x3 vs vamp-2x4 pins the exact boundary where the len² artifact kicks in. Nit (non-blocking): fixture header line 25 says[Am,G,Am]vs comment[Am,Am,G]— same loop pre/post canonicalization. NOTE: the transient smoke red the D-31 gate reported (clean-3x3) was this gate's own sabotage edit (a) running concurrently — tree restored, verified clean.
GATE 2026-07-10 (Critic) · D-31 RETURNED → PASS on scoped re-gate — first gate verified the playhead-accordion layout, the App.jsx-zero-changes claim (all 7 props already flow; pin inherits selectedStation semantics incl. reset effects), chordContext data support, and the vertical budget (256px at 1280×900 recomputed from real component geometry) but returned one arithmetic finding: expanded piano gallery ~640px understated ~45% (rootless A/B of true-7th chords → 2-octave D-24 crops = 266px thumbs) + licks strip 150→190px. Muse fixed: 940 / 1350–1550 (scrolls at ~1200, not "borderline") / 2300 / 3,500+ / 190 / 1070, "scroll is the piano rail's normal state on most loops", commit-5 must never assert one-row-fits, + 4 notes (token-boundary chordContext match; strip-owned "fits — now" chrome; guitar licks under piano tab stated; licksFor "lifted not reused"). Re-gate recomputed Dm7 rootlessA [17,21,24,28] → 266px from piano.js/MiniPiano.jsx, grep-verified no stale figures, no regression to passed sections. Nuance (non-blocking, for L-33): "any true-7th chord" slightly overgeneral — some rootless voicings fit 1 octave (e.g. Dm7 rootlessB); 940 is the correct conservative worst case.
GATE 2026-07-10 (Critic) · P-30 PASS first try (
b51daa1) — validator 154 plays green, build green, shared-tree smoke 817/817. Independent arithmetic (own script from SCHEMA/CHORD_TYPES, not Professor's): max per-hand span 11 (≤15), ≤4 notes/hand, combined span ≤23 → every recipe renders for all 12 roots in the 36-key window (zero silent fallbacks); 11 hand-picked prose claims all recompute exactly (♭VI→V sink 1,1,1,1,2; 9sus RH = major triad on ♭7; So What [0,5,10,15,19]; I-RH ≡ vi7-RH pcs; 13sus = Type A bottom+1; ...). Rule-4 idiomatic difference genuine per pair; outside-key 9-on-iii honestly flagged; sources hedged. One chased-and-accepted oddity: ♭VI13 stab's C–F–G♭ pinch is deliberate voice-leading, not a stacking bug.
GATE 2026-07-10 (Critic) · L-30 PASS (
4cc0009) — smoke 817/817 (all 17 fixtures plain guards, 9 original greens no regression), validator + build green. Diff confined: theory.js 2 hunks in the repeating-progression section only,canonicalizeunchanged context; loop-fixtures.mjs = marker removals + historical rewordings, every history/expect array untouched (frozen contract intact). 15 novel generalization probes: 11 correct, 3 data-faithful (only phase-locked exactly-alternating corruption yields a doubled pattern — genuinely 6-periodic data no algorithm could distinguish), 1 better-than-expected (all-reps-edited loop found via clean rotation). Every reportable "ghost" now corresponds to a pattern that exactly recurred — the old structurally-fake ghosts are gone. Perf 0.21–0.73 ms/call ×1000. Consumer contract at App.jsx:154-173 type-matches. 3 non-blocking findings folded into L-31's row.
GATE 2026-07-10 (Critic) · L-33 PASS (
see commit) — build green, smoke 817/817, validator green; diff exactly the 3-file lock (App.jsx/theory.js diffs attributed to L-31). SSR of the real JamGuide 37/37: expanded-column cell counts == independently derived shape counts (dom7@G=4, min7@D=4), aria-current one-per-list, mic microcopy exactly once (dense suppresses per-mount copies), pin semantics diffed line-by-line identical to old selectedStation (deps + emit/clear), GlanceRail imports no chordAudio + auto-follow has zero focus/audio side effects (scrollIntoView reduced-motion-guarded), heard-live + nothing-heard paths correct. Token matcher proven through the real render on a hostile country I-vs-I7 case (3 fits not 4) + full 23-lick chordContext audit — no false positive possible; exotic glyphs (♯/°/ø) outside the char class fail conservative (miss, never false-fit).dense-less VoicingBrowser SSR byte-identical to committed0945a08. Zero-click audit: all variations + all licks in initial markup. Deviations accepted (staging cosmetic; heard-live licks strip musically right). Non-blocking: first-mount scroll on unknown playhead benign; LicksStrip perf fine unmemoized. Committedc78baf4.
GATE 2026-07-10 (Critic) · L-31 PASS (
ce24d54) — 🚨 audio contract CLEAN: 1 hunk in the progression useEffect, contract-grep zero hits, no ref-sync/mount props; theory.js ride-along comment-only (verified zero executable lines). Independent re-trace with own mirror + real detector: spurious-substitution commits #7 zero drops; section change replaces with zero intermediate nulls; breakdown first-null at foreign-commit 28 (comment's "~28" numerically exact) and clears at exactly 6 nulls; 2-rep flap survives with rival counter provably reset. HOSTILE-1 proved REPLACE_VOTES=3 load-bearing (rival hit 2 before agreement reset — 2 would displace-and-flap); alternating rivals never accumulate; newSong null-shape defensively handled. Build/smoke 817/817/validator green. 2/3/6 judged musically sensible; v-a commit-then-upgrade UX accepted over blank display. Non-blocking: "consecutive" comment nuance (nulls are neutral, not resetting — amend to "consecutive non-null" if ever touched); threshold consts re-created per render (trivially cheap, hoisting would exceed the lock); Luthier's +53/−12 was arithmetic sloppiness for +47/−6.
GATE 2026-07-10 (Critic) · P-31 RETURNED → PASS on scoped re-gate (
81cd230) — first gate verified 90%+ of the pack exactly (♭VI7→V7 five-voice plane numerically perfect; all spans 11/4/22 legal; all 96 recipes render for 12 roots; rule-4 contrasts genuine) but returned 3 findings: jump-kicks bars 3-4 dyad orientations flipped (broke the play's own only-leap law; gate pre-verified the exact swap), "unmoved all night" contradicted by bar 9's own note, "octave-and-change" = actually a major 7th (11 semitones). Professor applied all 3; re-gate recomputed the lap chain from scratch: E4,B♭4 → G4,D♭5 → F4,C5 → F4,B4 → E4,B♭4 — "only leap" now provably unavoidable (all pairwise pc distances = 3), validator 164 plays / smoke 817/817 / build green, no fourth edit area.
Shipped sprint: sprint-knowledge-center (branch: sprint-jamguide-piano — complete 2026-07-09, PR #3)
Goal (user directive 2026-07-08): revise the visual structure of the Knowledge Center — today's knowledge lives in three disconnected surfaces (JamGuide/Roadmap, ExplorePanel, EducationPanel). Four user asks, verbatim priorities:
- Playable voicings per chord — browse and hear alternative voicings for any chord (guitar shapes + generated piano voicings), with simple switching.
- Simple ways of seeing techniques for licks — lick cards with technique markers (hammer-on, slide, bend…), per style.
- Intermediate-level progressions — research them and find the easiest way to surface them in-app (level tags + filter, not a new panel).
- Keep expanding music knowledge — continue KB cells per
docs/kb-backlog.mdin spare iterations.
Loop: /jam-loop every 30 min for 12 h (24 iterations), started 2026-07-08. User is away — no user-gated tasks this sprint; where the old sprint would have asked (concept selection), Muse picks the strongest option and records the rationale in the concept doc. Weights: Muse 3, Luthier 3, Professor 2, Critic gate, Herald 0.
| id | title | domain | status | depends-on | files (lock) | definition of done |
|---|---|---|---|---|---|---|
| M-03 | Seed sprint-knowledge-center from user directive 2026-07-08; carry L-11 forward (hold lifted — user asked to continue on this branch) |
maestro | done | — | docs/agents/LEDGER.md |
sprint seeded, loop scheduled |
| L-11 | Wire piano into JamGuide.jsx: Piano tab active; per station render MiniPiano voicing={…} from pianoVoicing/pianoVoicingChain; keep the guitar path intact. Carried from piano sprint; user hold lifted 2026-07-08 |
engineering | done | — | src/components/JamGuide.jsx |
piano tab shows per-station keyboards synced to the loop; guitar unchanged; build + smoke green |
| D-20 | Knowledge Center concept doc: one unified IA for JamGuide (live) + ExplorePanel (browse) + EducationPanel (learn) — sections Jam Guide / Explore / Voicings / Licks & Techniques, where the voicing player and lick cards mount, level-filter placement, narrow-viewport plan. No user gate: pick the strongest layout, record rationale + rejected alternatives in the doc | design | done | — | docs/design/knowledge-center.md |
doc names every component to touch, the target structure, and the migration order for L-22; honest about what stays untouched |
| L-20 | src/lib/chordAudio.js — Web Audio voicing playback: playVoicing(notes, {strumMs, durMs}) (piano notes are absolute 0–36 above C3; also accept guitar {string,fret} arrays via a midi mapper), own AudioContext created lazily on first user gesture, simple triangle/partials envelope, stopAll(). Must not touch the detection pipeline's contexts; document mic-feedback caveat (playback may be heard by detection) |
engineering | done | — | src/lib/chordAudio.js |
pure module + tiny API; no import from AudioCapture/App; plays a Cmaj7 shell audibly in dev; build green |
| D-21 | VoicingBrowser.jsx — for {rootPc, quality}: guitar alternatives (all matching voicings.js shapes via ChordDiagram) + piano alternatives (pianoVoicing root/shell/rootlessA/rootlessB via MiniPiano voicing) as switchable chips, each with a ▶ button calling chordAudio. Note (D-20 gate): GUITAR_SHAPES is private — lock includes an export-only line in voicings.js; do not cite the D-20 doc for small-text AA on active chips (use surface-background rule) |
design | done | L-20 | src/components/VoicingBrowser.jsx, src/lib/voicings.js (export-only) |
renders + plays all styles for any KB quality in any key; design tokens; AA contrast; keyboard-reachable |
| L-21 | Integrate VoicingBrowser: ChordDetailModal (replace/extend its static voicing grids) + JamGuide station-enlarge view — tap any chord anywhere → browse + audition voicings |
engineering | done | D-21, L-11 | src/components/ChordDetailModal.jsx, src/components/JamGuide.jsx |
both entry points work; legacy modal content preserved where not superseded; build + smoke green; audio-callback contract intact (App.jsx untouched or additive-only) |
| C-20 | Schema + validator + smoke for the two new KB shapes (both optional/additive): (a) level: 'foundation'|'intermediate' on progressions; (b) per-style licks — {id, name, level, chordContext, techniques[]} from a fixed technique vocab (hammer-on, pull-off, slide, bend, double-stop, ghost-note, chromatic-approach, vibrato) + tab: [{string, fret, technique?}] ordered notes. Existing KB stays green untouched |
quality | done | — | src/data/kb/SCHEMA.md, scripts/validate-kb.mjs, scripts/smoke.mjs |
validator enforces the vocab + tab shape when present; 10-style KB still green; smoke still 776+ green |
| P-20 | Intermediate progressions: research per docs/progression-repertoire.md, then tag existing KB progressions with level and author 2 new intermediate progressions each for jazz, gospel, neo-soul/rnb (secondary dominants, chained ii-Vs, backdoor, borrowed iv…) with guitar plays |
content | done | C-20 | src/data/kb/** (progressions + guitar files of jazz/gospel/rnb), src/data/kb/index.js |
every progression carries level; 6 new intermediate progressions validator-green; tips written for the "confident enough to jam" player (GOAL Part 2 audience) |
| P-21 | Licks pack #1: author 3–4 licks each for blues, jazz, funk guitar using the C-20 lick schema — technique tags, chordContext (which station/quality it fits), honest attribution | content | done | C-20, P-20 (done) | src/data/kb/blues/guitar.js, src/data/kb/jazz/guitar.js, src/data/kb/funk/guitar.js |
validator green; every lick playable as written (Critic hand-checks fret/string sanity) |
| L-23 | Fix latent getGuitarVoicings bug (found by L-20): strIdx = shape.rootStr - 1 indexes OPEN (ordered s6…s1) wrongly — rootStr 5 reads the B string's pc, rootStr 4 reads G's; A-shape C major computes fret 1 instead of 3. Use the ChordDiagram convention 6 - rootStr. Affects fret labels in ChordDetailModal/ExplorePanel/CurrentJamPanel for rootStr 4/5 movable shapes; ChordDiagram itself is correct. Also fix the playChord docstring octave example in chordAudio.js (Critic nit) |
engineering | done | — | src/lib/voicings.js, src/lib/chordAudio.js (docstring only) |
A-shape/C-shape fret labels correct (hand-verify 3 shapes × 2 keys); build + smoke green |
| D-22 | LickCard.jsx — tab-style SVG lick renderer: ordered notes on a string×fret window, technique glyphs (h, p, ⌒ slide, ↑ bend), compact card + technique legend; graceful on empty/malformed |
design | done | C-20 | src/components/LickCard.jsx |
renders every P-21 lick; glyph legend readable at card size; tokens; AA contrast |
| L-22 | Knowledge Center shell per D-20: restructure how JamGuide/ExplorePanel/EducationPanel mount into the unified IA; add the level filter chip (foundation/intermediate) wherever progressions list; mount Licks section (LickCard grid per style) | engineering | done | D-20, D-22, P-20, P-21 (licks commit may land empty-state-first per the D-20 doc). Ride-along polish (D-22 gate nit): LickCard stack-collision guard should check all same-column notes, not just prev (LickCard.jsx:100) |
src/components/JamGuide.jsx, src/components/ExplorePanel.jsx, src/App.jsx (mount only) |
unified structure live; level filter works; licks browsable per style; audio contract intact; build + smoke green |
| P-22 | KB expansion: jazz piano cell (first piano cell per docs/kb-backlog.md) — authored comp voicings override computed where they add signature value |
content | done | L-11 | src/data/kb/jazz/piano.js, src/data/kb/index.js |
validator green + registered (SCHEMA "Piano play" recipes); rendering the authored pack is L-24, not this task — status: done |
| C-22 | checkPianoRecipe span check: enforce SCHEMA rule 3 (each hand ≤ a 10th = 15 semitones) in the validator so future piano cells don't rely on hand-verification (P-22 gate follow-up) |
quality | done | P-22 | scripts/validate-kb.mjs, scripts/smoke.mjs |
span violation fails validator; existing KB green; smoke proves the check bites |
| D-23 | VoicingBrowser show="guitar"|"piano"|"both" prop (default both — zero change for existing mounts) + LickCard stack-collision guard checks ALL same-column notes not just prev (D-22 gate nit, LickCard.jsx:100) |
design | done | D-21, D-22 | src/components/VoicingBrowser.jsx, src/components/LickCard.jsx |
prop-gated rows; all existing mounts render identically with no prop; guard fixed; build + smoke green |
| L-25 | ChordDetailModal Guitar/Piano tabs pass show="guitar"/show="piano" to VoicingBrowser (JamGuide station-enlarge + Voicings section keep both rows) |
engineering | done | D-23 | src/components/ChordDetailModal.jsx |
tabs show only their instrument's row; build + smoke green |
| D-24 | MiniPiano voicing-path compact window: crop the keyboard to the voicing's octave span (+1 key padding each side) so Jam Guide station thumbs aren't ~390 px (L-11 gate observation); size="full" and the legacy lh/rh path byte-unchanged |
design | done | D-10 | src/components/MiniPiano.jsx |
thumbs materially narrower for ≤1-octave voicings; root/bass marks intact; legacy consumers render identically; build + smoke green |
| P-24 | Licks pack #2: 3–4 licks each for rock, country, reggae guitar (C-20 schema; same bar as P-21 — playable as written, honest sources) | content | done | C-20, P-21 | src/data/kb/rock/guitar.js, src/data/kb/country/guitar.js, src/data/kb/reggae/guitar.js |
validator green with ~21+ licks; every note serves its chordContext (Critic verifies) |
| L-24 | JamGuide piano branch prefers an authored piano pack (SCHEMA piano recipes) over computed pianoVoicingChain when the style has one; fall back to computed otherwise. Recipe→notes convention: order inside each hand = voicing order low→high (documented at jazz/piano.js:14) |
engineering | done | P-22, L-22 | src/components/JamGuide.jsx |
jazz piano stations render the authored comp; other styles keep computed voicings; build + smoke green |
| P-23 | KB expansion: gospel piano cell | content | done | P-22 | src/data/kb/gospel/piano.js, src/data/kb/index.js |
validator green; renders in the piano tab |
| C-21 | Sprint-end sweep: full build + validator + smoke, cross-browser sanity notes, PR body draft summarising the sprint for main |
quality | done | L-21, L-22, P-21 | (none — verification) | all green; PR body ready |
Sequencing: L-11 ‖ D-20 ‖ L-20 ‖ C-20 are all file-disjoint and ready now. Then D-21 → L-21, and P-20/P-21/D-22 → L-22. P-22/P-23 fill spare iterations. Critic gates every task as usual.
Shipped sprint: sprint-jamguide-piano (branch: sprint-jamguide-piano — piano resolver phase complete; L-11 carried into the sprint above)
Goal: extend the shipped Roadmap Jam Guide to piano (guitar→piano→bass roadmap). When the Piano instrument tab is selected, each Roadmap station shows a generated piano voicing on a mini-keyboard — voicings computed from the progression's degrees+qualities (GOAL G4: generate piano voicings from interval recipes; no authored data needed for the MVP). Branch cut off sprint-jam-guide HEAD. Weights: Luthier 3, Muse 2, Critic gate.
| id | title | domain | status | depends-on | files (lock) | definition of done |
|---|---|---|---|---|---|---|
| M-02 | Cut sprint-jamguide-piano branch off sprint-jam-guide; seed sprint |
maestro | done | — | (branch) | branch cut, ledger seeded |
| L-10 | src/lib/piano.js — pure piano voicing resolver: pianoVoicing({rootPc, quality}, opts?) → shell (1-3-7), rootless A/B (3-5-7-9 / 7-9-3-5), root-position; picks the inversion minimizing movement from a previous voicing (voice-leading); returns absolute key positions + pcs + a label |
engineering | done | M-02 | src/lib/piano.js |
pure fns; correct tones for all 14 CHORD_TYPES; voice-leading-minimal vs a prev voicing; build + smoke green; output shape documented for D-10/L-11 |
| D-10 | Extend existing src/components/MiniPiano.jsx (already imported by ChordDetailModal/ExplorePanel via {rootPc, lh, rh}) with an ADDITIVE voicing prop that renders a pianoVoicing output ({notes,pcs,bass,style,label}) on a 2–3 octave keyboard — root in accent, bass marked, thumb/full sizes; legacy lh/rh path unchanged |
design | done | L-10 | src/components/MiniPiano.jsx |
renders any pianoVoicing in any key; ChordDetailModal + ExplorePanel render identically (legacy path untouched); build green; design tokens; AA contrast |
| L-11 | Wire piano into JamGuide.jsx |
engineering | carried → sprint-knowledge-center | L-10, D-10 | — | see the active sprint table above (hold lifted by user 2026-07-08) |
| C-10 | Extend scripts/smoke.mjs: assert pianoVoicing returns a valid voicing for every KB quality (no crash, notes in range, contains the chord's defining tones); also assert no duplicate absolute note across styles (the sus2 forced-rootless nit from L-10 gate) |
quality | done | L-10 | scripts/smoke.mjs |
smoke covers the piano resolver; exits non-zero on regression — currently red (1/776): surfaces the sus2 dup-note nit → L-13 fixes the resolver |
| L-13 | Resolver dedupe: pianoVoicing must never emit a duplicate absolute note (sus2 forced-rootlessB collides pc2 → notes=[26,26,31]). Drop/merge collided notes so every voicing's notes are distinct; keep pcs/bass valid; default + chain paths unchanged |
engineering | done | L-10 | src/lib/piano.js |
no duplicate absolute note for any quality×style; C-10 smoke goes green (776/776); build green; existing 56-voicing correctness preserved |
Piano authored packs (signature comps overriding computed voicings) are deferred to a later sprint — computed voicings suffice for the piano MVP.
Shipped sprint: sprint-jam-guide (branch: sprint-jam-guide, PR #2 — complete)
Emphasis this sprint: ship the Jam Guide MVP (put the 8 guitar style packs on screen, synced to live detection) + reframe the repo as a learning platform. Weights this sprint: Luthier 3, Muse 3 (design-heavy), Professor 2, Herald 2, Critic gate.
Design-first gate (user directive 2026-06-14): Muse explored three distinct concepts; user chose "Roadmap" (improv-first highway) on 2026-06-15. Implementation tasks below are re-planned to build Roadmap. Concept doc: docs/design/jam-guide-concept-c.md. Stage/Playbook (-a/-b) kept as reference for future modes.
Roadmap build shape: a horizontal timeline panel — stations (= loop chords) carry guide-tone lanes (3rd/7th), a solo-scale label, and voice-leading rails (7→3) between stations; a playhead + beat grid track loop position; the chosen voicing is a secondary thumbnail per station; tap a station → guide tones on the fretboard. Needs derived theory (guideTones, voiceLeadingPairs, default soloScale) — Luthier owns those.
| id | title | domain | status | depends-on | files (lock) | definition of done |
|---|---|---|---|---|---|---|
| M-01 | Cut sprint-jam-guide branch; seed sprint |
maestro | done | — | (branch) | branch cut, ledger header set |
| D-00a | Viz concept A — "Stage" | design | done | — | docs/design/jam-guide-concept-a.md |
delivered; reference for future collapsed/glance mode |
| D-00b | Viz concept B — "Playbook" | design | done | — | docs/design/jam-guide-concept-b.md |
delivered; reference for future study mode |
| D-00c | Viz concept C — "Roadmap" | design | done | — | docs/design/jam-guide-concept-c.md |
delivered; CHOSEN |
| D-SEL | User selects a concept | maestro | done | D-00a, D-00b, D-00c | docs/agents/LEDGER.md |
Roadmap chosen 2026-06-15; tasks re-planned below |
| L-01 | Shared matcher: extract/author findLoopPosition (which chord index the loop is on) + rotation-invariant degree-relative loop→progression-id matcher into src/lib/match.js; refactor ProgressionBanner.jsx to use it |
engineering | done | M-01 | src/lib/match.js, src/components/ProgressionBanner.jsx |
matcher maps detected loop → style progression id (rotation-invariant) AND returns current position index for the playhead; banner still works; build green — VERIFY: npm run build green; banner renders identically (findLoopPosition now imported from match.js); matchLoopToProgression rotation-invariant + quality tie-break (smoke: ii–V–I & its rotation → jazz-251-major rot 0/2; minor 251 → jazz-251-minor; chromatic → no match) |
| L-01b | Derived theory for Roadmap: add guideTones(chordRoot,quality) (3rd & 7th pcs), voiceLeadingPairs(chordA,chordB) (7→3 / nearest-tone rails), and default soloScale(quality,mode) (Mixo/dom7, Dorian/m7, Ionian/maj7…) to theory.js — additive exports only |
engineering | done | M-01 | src/lib/theory.js |
pure functions, unit-sane (ii–V–I in C → C→B, F→E rails); reuses existing getChordTones; build green; no existing export changed |
| L-02 | JamGuide.jsx panel shell: mounts last in App.jsx, reads kb/index.js, instrument+style tabs from registry, collapsed header → ~70vh; receives live loop + position props |
engineering | done | L-01 | src/components/JamGuide.jsx, src/App.jsx |
panel renders, tabs from KB, matched progression or fallback; build green |
| D-01 | RoadmapTrack.jsx — the heart: horizontal stations (loop chords) with guide-tone lanes (3rd/7th dots), solo-scale label, voice-leading rails between stations, playhead + beat grid, lookahead highlight on the next station |
design | done | L-01, L-01b | src/components/RoadmapTrack.jsx |
renders a real ii–V–I & a 12-bar blues from KB; lanes computed from guideTones/voiceLeadingPairs/soloScale; design tokens; AA contrast |
| D-01b | ChordDiagram.jsx — secondary per-station voicing thumbnail (movable rootStr+offsets, open frets+onlyRoot), key-aware fret placement, tap-to-enlarge |
design | done | L-01 | src/components/ChordDiagram.jsx |
renders any KB guitar shape in any key; chord-tone colour tier; compact thumbnail + enlarged states |
| D-02 | Roadmap assembly & live polish in JamGuide.jsx: place RoadmapTrack + thumbnails, animate playhead against BPM/onset, narrow-viewport reflow, tap-station → fretboard guide tones |
design | done | L-02, D-01, D-01b | src/components/JamGuide.jsx (assembly/styling), tailwind.config.js |
playhead tracks position; reflows on narrow; keyboard-reachable; AA contrast |
| D-03 | Finish the flagship: tap a Roadmap station → highlight that chord's guide tones (3rd/7th) on the main Fretboard. Lift a jamFocusChord state into App.jsx, JamGuide emits the selected station's {rootPc, quality} via a callback prop, Fretboard highlights those guide tones reusing its existing tier rendering. Returned by Critic → also fix root cause guideTones so 4-tone non-seventh chords (add9/maj6/min6) don't badge their 5th/6th as a "7" |
engineering | done | D-02 | src/App.jsx, src/components/JamGuide.jsx, src/components/Fretboard.jsx, src/lib/theory.js |
tapping a station lights its 3rd/7th (honest secondary anchor for non-7th chords); build green; smoke green; audio-callback contract intact; RoadmapTrack lane also corrected; keyboard-reachable; clears on deselect |
| P-01 | Gospel guitar KB cell | content | done | — | src/data/kb/gospel/**, src/data/kb/index.js |
5 progressions × 2 plays, validator green (run /kb-expand) |
| P-02 | Pop guitar KB cell | content | done | P-01 | src/data/kb/pop/**, src/data/kb/index.js |
5 progressions × 2 plays, validator green |
| H-01 | README reframe: lead with the learning-platform vision (detect → guide → learn), screenshot/gif placeholder, link GOAL.md + docs/agents/ |
community | done | — | README.md |
README states the dual vision; links resolve |
| H-02 | CONTRIBUTING.md + issue templates: the data-contract path so a musician can PR a style without coding (point at src/data/kb/SCHEMA.md) |
community | done | H-01 | CONTRIBUTING.md, .github/ISSUE_TEMPLATE/** |
a non-coder can follow "add a style"; /kb-expand documented as the assisted path |
| C-01 | Smoke-test harness: a scripts/smoke.mjs that imports kb/index.js + runs the matcher on sample loops, wired alongside validate-kb.mjs |
quality | done | L-01 | scripts/smoke.mjs |
catches a broken matcher/registry before merge; documented in PROTOCOL gate |
Critic (C-) reviews every L-/D-/P-/H- task as it reaches
in-review— those reviews are the gate, not separate ledger rows, except where new test infra is itself the deliverable (e.g. C-01).
GATE 2026-06-15 (Critic) · L-01 PASS — build green, validator green (8 styles/40 progs/80 plays).
findLoopPositionextracted byte-identical (verified by diff, no semantic change). matchLoopToProgression verified rotation-invariant with quality tie-break:[Dm7,G7,Cmaj7]→jazz-251-majorrot 0; rotation[G7,Cmaj7,Dm7]→ rot 2;[Dm7b5,G7,Cm7]→jazz-251-minor(tie-break works); chromatic→clean{matched:false}. rotation index correctly points at the loop slot aligning with KB degrees[0].match.jsholds only matching/position logic + a small local chord-root parser (theory.js exposes no pc helper — acceptable). Note (non-blocking): banner refactor also addsonChordClickclick affordances — beyond a pure extract but already wired tosetSelectedChord/ChordDetailModal in App.jsx and behaviour-preserving forfindLoopPosition. Minor:match.jsuses extensionlessimport … from './theory'(works under Vite; matches existingeducation.jsconvention). GATE 2026-06-15 (Critic) · L-01b PASS — build green. theory.js diff is purely additive (zero-lines; no existing export touched). Verified by running the real functions: ii–V–I in C → Dm7→G7 = C→B (−1) and G7→Cmaj7 = F→E (−1) rails (plus intentional 0-semitone common-tone rails).guideTonestriad fallback flagshasSeventh:falseand uses the 5th.soloScaledefaults sane: dom7→mixolydian, min7→dorian, maj7→major(ionian), half_dim→locrian, dom7/minor→phrygian-dominant. Functions are pure and reuse CHORD_TYPES/SCALES. GATE 2026-06-15 (Critic) · L-02 PASS — build green; validator green (8 styles/40 progs/80 plays). 🚨 Audio contract INTACT:git diff HEAD -- src/App.jsxis +10 lines, zero deletions — only theimport JamGuideline and the<JamGuide …/>mount (placed last, after the tuner block).handleNote/handleChroma/handleOnsetlines do not appear anywhere in the diff; nouseCallbackdep, ref-syncuseEffect, orAudioCaptureprop was touched. Black-screen/infinite-restart risk avoided. All 5 props passed (detectedProgression,effectiveKey,chordHistory,bpm,currentChord) exist in App scope. Tabs derive from the KB registry (instrument availability fromstyle.instrumentskeys, style labels frommeta.label); matched-progression vs. dashed-fallback both render. Disabled instrument tabs marked "soon" withdisabled+ title. GATE 2026-06-15 (Critic) · D-01 PASS — RoadmapTrack renders from props only (pure/presentational). Verified against the real KB: guide-tone honesty confirmed by runningguideTones— C-major triad returnshasSeventh:false, secondary anchor = the 5th (pc 7), and the Station labels it "5th" not "7th" (seventhKindgate at line 113). The headline rail picksvoiceLeadingPairs(...)[0]= the 7→3: Dm7→G7 ⇒ C→B (−1), G7→Cmaj7 ⇒ F→E (−1). BeatGrid station-start indexing is canonical-order-consistent with the stations array; playheadpctclamps at 0 whenposition=-1. Tokens used;aria-current,role=progressbar+aria-valuetext, focus rings present. Malformed/empty progression → graceful "no loop to map" card, no crash. GATE 2026-06-15 (Critic) · D-01b PASS — ChordDiagram movable base-fret formula verified independently: E-shape A7 → fret 5 ✓ (rootStr 6, rootPc 9:((9−4)%12)=5); A-shape C → fret 3 ✓; open-string root → octave barre (12), a sane degradation. Root-tone coloured in accent tier (isRoot→#a855f7), non-root dots light-gray (AA on dark board). Boththumb/fullsizes;fulladds finger numbers + label. Undefined/unplaceable shape (root > fret 15 or!shape) → graceful "—" placeholder, no crash — covers the empty-thumbnail path. Open vs movable forms both handled. GATE 2026-06-15 (Critic) · P-01 PASS — validator green:✓ KB valid — 9 style(s), 45 progressions, 90 plays(gospel now included);npm run buildgreen (gospel imported bykb/index.js, 87 modules, built in 5.65s). Schema: 5 progressions × 2 plays = 10 plays, all idsgospel--prefixed, rn/qualities/bars all length-consistent with degrees, qualities all in CHORD_TYPES (min7/dom7/maj7/maj/add9/sus4/dim7). No duplicate id across all 45. Registered inindex.jsmirroring the other 8 styles (no broken import). Voicings hand-verified (independent pc computation matching the validator's): SHELL_6.maj7 → {0,11,4}=R-7-3 ✓; SUS4_5 → {0,5,7}=R-4-5 ✓; DIM7_5 → {0,6,9,3}=R-♭5-𝄫7-♭3 symmetric ✓; ADD9_6 → {0,2,4,7} full add9 (9th present) ✓; MIN9_5 → {0,2,3,7,10} full min9 ✓ — confirms the validator genuinely exercises these shapes viacheckGuitarShape. Theory sound: backdoor ♭VII7=pc10 rises a whole step to I; #iv°7=pc6 passing chord; 6-2-5-1 + plagal IV-I Amen tag; cascading cycle-of-dominants all correctly spelled. Authenticity honest: attributions hedged appropriately ("traditional gospel turnaround", "reharmonized", "Every Praise … vamp feel", "e.g. Tenderly bars 5-7" as a back-door reference) — no claim that a specific recording uses an exact voicing; no music-theory error in any tip (Dorian-over-min7, Mixo-over-dom7, sus-non-resolution advice all correct). Non-blocking nit: a few shape comments list tones in interval order, not low-to-high string order (e.g. MAJ9_6 "R–3–7–9" sounds R-9-3-7) — labeling nicety, all tones present and correctly spelled; not a defect. GATE 2026-06-15 (Critic) · H-01 PASS — every relative link resolves on disk:GOAL.md,CLAUDE.md,src/data/kb/SCHEMA.md,src/data/kb/jazz/(dir),docs/agents/+ ROSTER/PROTOCOL/LEDGER all exist;CONTRIBUTING.mdis correctly referenced as "coming (tracked as task H-02)" and does NOT exist on disk — honest, not a dead live-link. Every command real:electron:dev,dev,electron:build:win|mac|linuxall inpackage.json;scripts/validate-kb.mjsexists. Nofrontend/path remains; build output dir stated asrelease/matches electron-builderdirectories.output: "release". git clone URLwhattheflat/whattheflat.gitmatches actualorigin. Honesty verified: gospel described as "landing next" (not shipped, still in-review at review time); Piano/bass packs, Progression Builder, detection-powered drills all under In progress, not today; Roadmap Jam Guide listed as working-today (true — D-02 passed, MVP live). Leads with detect → guide → level up; links GOAL.md + docs/agents/. No overstatement found. GATE 2026-06-15 (Critic) · P-02 PASS — gated against the FINAL combined tree (P-02/H-02/C-01 merged).node scripts/validate-kb.mjs→✓ KB valid — 10 style(s), 50 progressions, 100 plays(pop registered inindex.js; the transient "pop not registered" mid-batch failure is resolved —index.jsimports popMeta/popProgressions/popGuitar and exports thepopblock). Schema: 5 progressions × 2 plays = 10, all idspop--prefixed, no duplicate across all 50 (verified). Voicings hand-computed (independent pc calc): OPEN_CADD9 → {0,2,4,7} = R-9-3-5, the 9th (pc2) genuinely present (true add9, not plain C) ✓; OPEN_G/OPEN_F → {0,4,7} major ✓; BARRE_MAJ_6 (E-shape) {0,4,7}, BARRE_MIN_5 (Am-shape) {0,3,7}, BARRE_MAJ_5 (A-shape) {0,4,7} ✓ — confirms validator exercises the shapes. Non-duplication judged ACCEPTABLE: pop-axis (0-7-9-5 maj) shares shape with rock-axis/reggae-nwnc and pop-mixo-bVII (0-10-5 mixo) with rock-mixo-vamp, but ids differ, songs differ (No Woman No Cry/Adele/Beatles vs rock), and guitar plays are capo-and-open framed vs rock's barre framing — a real genre reuse with distinct content, not a duplication smell; differentiation rationale documented in the progressions.js header. Honesty CONFIRMED: every sus2/sus4 mention is prose (note/tips/styleIntro) framed as a hammer-on/pull-off fill over a held chord ("the chord stays major, your finger wiggles"); zero sus in the data — all pop-mixo chords are voiced plainmaj; tips never claim a voicing the data lacks. Song attributions hedged (Clocks "♭VII colour", Royals "verse", Memories "Pachelbel, set in B"). GATE 2026-06-15 (Critic) · H-02 PASS — every relative link resolves on disk: GOAL.md, README.md, src/data/kb/SCHEMA.md, gospel/{meta,progressions,guitar}.js, index.js, src/lib/theory.js, scripts/validate-kb.mjs, docs/agents/ROSTER.md, and all three issue templates (add-style/bug_report/feature_request) + config.yml — verified via on-disk existence check. Every command real (npm install / electron:dev / dev / build / node scripts/validate-kb.mjs all in package.json). Schema fidelity exact: the quality listmaj,min,dom7,maj7,min7,dim,dim7,half_dim,aug,sus4,sus2,maj6,min6,add9matchesCHORD_TYPESkeys byte-for-byte; modes list matches the validator's MODES; degrees-0-11, movable(rootStr/offsets) vs open(frets/onlyRoot), and extensions/rootless/omit3 explanations all match SCHEMA.md + validator logic — no invented field, no drift. LICENSE correctly NOT added (CONTRIBUTING honestly states "doesn't have a license file yet … reuse terms aren't settled"). Issue templates present and sane. Non-blocking nit: CONTRIBUTING's illustrative validator-output sample reads9 style(s)/45/90(true at authoring time, pre-pop) — it's a "what a passing run looks like" example, not a load-bearing claim; the instructions don't depend on the count. Worth a one-char refresh to 10/50/100 someday, not a return. GATE 2026-06-15 (Critic) · C-01 PASS —node scripts/smoke.mjs→✓ Smoke test passed — 71/71 checks green (10 styles, 50 progressions), exit 0; reports the FULL final KB (10 styles, derived from the loaded registry, not hardcoded). Imports the REALkb/index.js+match.js(no mocks); asserts registry integrity (every style meta/progressions[]/instruments.guitar, per-prog degrees/qualities/rn/bars consistency, cross-KB id uniqueness) and matcher correctness (ii–V–I matched:true + structural rebased-degree-shape check, rotation invariance to the SAME derived id with non-zero rotation, axis match guarded with skip-if-absent, chromatic → matched:false/id:null, findLoopPosition in-range/-1/-1-on-empty). Exits non-zero on failure (mirrors validate-kb). Adversarial proof: sabotagedmatchLoopToProgressionto always return no-match → smoke FAILED 4 checks, exit code 1 (assertions are NOT too weak — a broken matcher cannot pass). match.js restored, no diff. Resolve hook judged SOUND: the inlinemodule.registerESM hook retries ONLY oncatch, ONLY for relative+extensionless specifiers (/^\.{1,2}\//&&!/\.[mc]?js$/) — verified the regex skips./theory.js,react,node:url,./a.mjsand retries only./theory/../lib/match; it cannot mask a genuine missing module (the.jsretry itself surfaces the real ERR_MODULE_NOT_FOUND). Correctly chosen over editing match.js (locked to L-01). No npm script added (validate-kb has none) —package.jsonuntouched (git: onlysrc/data/kb/index.jsis modified; smoke.mjs/pop/CONTRIBUTING/templates are new untracked). No hardcoded fragile ids — expected ids derived from the loaded KB; survives KB growth. GATE 2026-06-15 (Critic) · D-03 FAIL (returned) — build green (vite, 90 modules, 10.66s); validator green (✓ KB valid — 10 style(s), 50 progressions, 100 plays, no KB change). 🚨 Audio contract INTACT:git diff -- src/App.jsxis purely additive — exactly (a) one newuseState(jamFocusChord/null)placed in the UI-state block (outside all audio-callback/ref logic, with a comment that it is not read by any callback), (b)jamFocusChord={jamFocusChord}on the existing<Fretboard>mount, (c)onFocusChord={setJamFocusChord}on the existing<JamGuide>mount. Grep of the changed lines forhandleNote|handleChroma|handleOnset|useCallback|AudioCapture|Ref|useEffect→ NO MATCHES. No callback, ref, ref-sync useEffect, or AudioCapture prop touched. Black-screen/infinite-restart risk avoided. Wiring correct: JamGuide emits{rootPc, quality:qualities[i]}(station's actual KB quality) on select,nullon deselect; the existingselectedStation→nullreset effect (loop/style/instrument change) flows through the new cross-link effect and clears the highlight; an unmount-cleanup effect also clears; all guardedonFocusChord?.so JamGuide stays standalone. Fretboard null path verified unchanged (hasFocus=false⇒tagalways null ⇒if(!color&&!tag)collapses to originalif(!color); no halo/badge/legend). Emphasis is visually distinct (purple ringDOT_R+3+ degree badge, accent token#a855f7). Triad labeling correct for maj/min/dim/aug/sus4/sus2 (allhasSeventh:false→ badge/legend read "5"). DEFECT (blocking):guideTones' secondary-anchor heuristic ishasSeventh = ints.length >= 4, so the 4-tone non-seventh KB qualitiesadd9[0,2,4,7],maj6/min6[0,4,7,9]returnhasSeventh:truewithseventh = ints[last]= the 5th (add9) or 6th (maj6/min6). D-03'sfocusLabeltrusts that boolean and badges those tones "7", legend reads "3 / 7" — a perfect fifth / sixth rendered to the user as a seventh on the flagship Fretboard. Reachable:add9is in gospel progression qualities (×4),min6in bossa + rnb qualities — tapping those stations mislabels a non-7th. Verified by runningguideTones(0,'add9')→{third:4,seventh:7,hasSeventh:true}(G badged "7"),guideTones(0,'min6')→{third:3,seventh:9,hasSeventh:true}(A badged "7"). The DoD's "the chord's guide tones (3rd/7th)" / "badge reads 5 not 7 for a triad" contract is violated for these KB-present qualities. Fix direction (return to Luthier): make the secondary anchor honest for extended non-7th chords — either tightenguideTonesso a chord with no minor/major 7th reportshasSeventh:falseand falls back to the 5th (root cause, L-01b owns theory.js), or havefocusLabel/the badge derive the actual interval ofseventhabove root (10/11 ⇒ "7", 9 ⇒ "6", 7 ⇒ "5", 2 ⇒ "9") rather than trusting the boolean. Re-gate after fix. GATE 2026-06-15 (Critic) · D-03 PASS (re-gate) — the returned defect is fixed at the root cause and hardened.npm run buildgreen (vite, 90 modules, built in 3.25s);node scripts/smoke.mjs→✓ Smoke test passed — 71/71 checks green (10 styles, 50 progressions), exit 0;node scripts/validate-kb.mjs→✓ KB valid — 10 style(s), 50 progressions, 100 plays(no KB change). Root-cause fix VERIFIED by running the realguideTones:hasSeventhnow keys on the actual presence of interval 10 or 11 (ints.find(i=>i===10||i===11)), notlength>=4. Independent truth table (root C): add9→{third:2,seventh:7,hasSeventh:false,anchor=5th G}; maj6→{4,7,false,5th}; min6→{3,7,false,5th}; dom7→{4,10,true,7=A♯}; maj7→{4,11,true,7=B}; min7→{3,10,true,7=A♯}; triads maj/min/sus4/sus2→false,anchor 5th(7); dim→anchor ♭5(6); aug→anchor #5(8); dim7→♭5(6); half_dim→true,10. Return shape{third, seventh, root, hasSeventh}unchanged (keys verified). Badge hardening (Fretboard) VERIFIED:focusSeventhLabelderives the label from the actual interval of the anchor pc above the chord root (10/11→"7", 9→"6", 8→"♭6", 7→"5", 6→"♭5"), so a wrong boolean can't mislabel — adversarial sweep of all 14 KB qualities × keys {3,7,11}: a "7" badge appears iff the interval is truly 10/11; NO MISLABEL. Unknown quality →majfallback, no crash. Null-focus path byte-equivalent:jamFocusChord=null⇒hasFocus=false⇒tagalways null ⇒if(!color&&!tag)collapses to the originalif(!color) return null; no halo/badge/legend;focusSeventhLabelis dead-but-harmless. No collateral:voiceLeadingPairs/soloScalesignatures untouched (theory.js diff hits onlyguideTonesbody+jsdoc); ii–V–I rails still correct (Dm7→G7 C→B [0→11,−1]; G7→Cmaj7 F→E [5→4,−1]) andvoiceLeadingPairsdoes NOT crash for the now-5th-anchored add9/maj6/min6 (Cadd9→G7, Cmaj6→F, Amin6→Dm7 all return smooth rails). match.js/RoadmapTrack/ChordDiagram/KB untouched (git diff --name-only= only the 4 declared D-03 files). 🚨 Audio contract INTACT:git diff -- src/App.jsxpurely additive (oneuseState(jamFocusChord/null)outside the callback/ref block + an additivejamFocusChord=prop on<Fretboard>+onFocusChord=setJamFocusChordon<JamGuide>); grep of changed lines forhandleNote|handleChroma|handleOnset|useCallback|AudioCapture|Ref|configRef|useEffect→ NO MATCHES; the sole "−" line is the Fretboard mount being re-emitted with the added prop. Non-blocking observation (pre-existing, out of D-03 scope):guideTonesusesints[1]for the 3rd, soadd9[0,2,4,7]reports its 9th (pc 2) asthird, not the major 3rd (pc 4) — true at L-01b time, unchanged by this fix, and D-03's bug was strictly the seventh/secondary anchor; worth a future tidy, not a return. GATE 2026-06-15 (Critic) · L-10 PASS — (re-gated cleanly after the prior dispatch died on an API error pre-verdict.)npm run buildgreen (vite 7.3.1, 90 modules, built in 2.24s);node scripts/smoke.mjs→✓ Smoke test passed — 71/71 checks green (10 styles, 50 progressions)exit 0;node scripts/validate-kb.mjs→✓ KB valid — 10 style(s), 50 progressions, 100 plays. Purity confirmed by reading the full module: exportspianoVoicing({rootPc,quality},opts?)→{notes,pcs,bass,style,label}pluspianoVoicingChain,hasTrueSeventh,voicingToneSet(and re-exportsguideTones); imports ONLY{CHORD_TYPES, guideTones}from./theory; noDate/Math.random/module-level mutable state — determinism verified (every quality voiced twice → byte-identical). Music verified myself via a throwaway ESM script (deleted): swept all 14 CHORD_TYPES × 4 styles = 56 voicings at rootPc 0 — everypcs ⊆ voicingToneSet(...)(NO out-of-chord note), real 3rd present (sus→2/5), every TRUE 7th (interval 10/11: dom7/maj7/min7/half_dim) present in shell+rootless, allnotes ∈ [0,36](≤3 octaves),bass=min(notes). Spot-checks exact: Cmaj7 shell→{0,4,11} ✓, Dm7 rootlessA→{5,9,0,4}=F-A-C-E ✓, G7 shell→{7,11,5} ✓. Awkward qualities honest: half_dim shell→{0,3,10} (true ♭7 kept), rootlessA→{3,6,10,2} "3-5-7-9" ✓; dim7 correctly NOT a true-7th chord — its 7-slot is interval 9 (𝄫7 = enharmonic maj6, not 10/11), sohasTrueSeventh('dim7')=false, shells as R-3-5 {0,3,6}, no fabricated 7th; min6/maj6 (no true 7th) → root {0,3,7,9}/{0,4,7,9}, rootless labels honestly read "3-5-6-9" using the 6th as upper colour — no wrong note. Voice-leading confirmed:pianoVoicingChain([Dm7,G7,Cmaj7])total semitone motion 16 vs 18 unthreaded (opts.prevslides whole shapes by octaves toward the previous voicing); pcs unchanged by threading (per-chord pc sets identical to unthreaded — re-registered only, never corrupted). Adversarial: bogus/empty/null chord → gracefulmajfallback, no crash. One non-blocking nit (NOT a defect): forcingrootlessB(orrootlessA) explicitly onto a sus2 chord produces a cosmetic duplicate absolute note (notes=[26,26,31]) because the suspended-2nd "3rd-slot" tone (pc2) and the synthesized 9th (pc2) collide — still no wrong pc, in range, and honestly labeled "no 7th, 9-3-5 colour". It is unreachable on the shipping path:defaultStyle(sus2)='root'and L-11/pianoVoicingChainuse defaults, so sus2 renders as clean root[0,2,7]; the dup only appears under an explicit forced-rootless override of a sus chord (documented graceful degradation). Default-style sweep of all 14 qualities confirmed zero duplicate notes. Recommend a future tidy (dedupe collided absolute notes in the rootless fallback) — not a return.src/lib/piano.jsNOT edited; throwaway script removed. GATE 2026-06-15 (Critic) · D-02 PASS — the load-bearing integration is correct. Independent rotation check:canonicalPos = ((position − rotation) % n + n) % ntranslates afindLoopPositionindex (which is into the detected loop) into the KB-canonical station RoadmapTrack/stationVoicings render. Worked a rotated [ii V I VI] of KB [I VI ii V] (rotation=2, n=4): playhead@detected-idx1(V)→canonical 3(V), @2(I)→0(I), @3(VI)→1(VI), @0(ii)→2(ii) — NOW lands on the chord actually playing. ✓ rootPc parity confirmed: thumbnailrootPcand RoadmapTrack station root are byte-identical(((keyRoot+deg)%12)+12)%12, andkeyInfo.root(a note name, e.g.detectKey→"F#") is converted once viachordRootPC→ pc, guarded>=0. stationVoicingschords[i]aligns 1:1 withdegrees[i](canonical). Auto-scroll is prop-driven offposition(no rAF on the audio thread). Reflows (flex-wrap/sm:flex-nowrap), keyboard-reachable, AA contrast. NO_MATCH path → dashed fallback, never empty/crash. Non-blocking deferral: the DoD's "tap-station → fretboard guide tones" cross-link andtailwind.config.jsedit were not delivered — the implementation cross-links via an inline enlarged ChordDiagram instead (flagged in-code as deferred). Panel is fully functional without it; recommend Maestro file the fretboard cross-link as a phase-2 follow-up. GATE 2026-06-16 (Critic) · D-10 PASS —npm run buildgreen (vite 7.3.1, 90 modules, built in 9.36s);node scripts/smoke.mjs→ 776/776 exit 0;node scripts/validate-kb.mjs→ 10 styles/50/100 (no KB change). ADDITIVE confirmed by reading the full diff: the publicMiniPianonow dispatchesif (voicing) <VoicingPiano/> else <LegacyPiano/>. The legacy{rootPc,lh,rh}path is the SAME code, only refactored to named constants holding the IDENTICAL hex values (LH_BLUE=#3b82f6,ACCENT=#a855f7,WHITE_FILL=#f5f5f5,WHITE_STROKE=#374151,BLACK_FILL=#1f2937,BLACK_STROKE=#111827) — geometry (OCTAVES=2, WW/WH/BW/BH, BLACK_OFFSETS), highlight map, R-label all unchanged. Consumers render identically:grepconfirmsChordDetailModal.jsx:86andExplorePanel.jsx:85both call<MiniPiano rootPc lh rh />with NOvoicingprop →voicingisundefined→ both hitLegacyPiano→ byte-equivalent output. Voicing path correct: maps absolutenotes(0=low C, [0,36]) to keys viaoct*12+pc, root pc lights accent#a855f7+ "R", bass key amber-ringed (#fbbf24AA), other tones soft accent#c084fc; OCTAVES auto-spans 2–3 to containmax(notes). Worked examplepianoVoicing({rootPc:0,quality:'maj7'})→ default shell, pcs{0,4,11}=C-E-B (R-3-7): C lit accent+R, B & E soft purple, C bass-ringed — musically right.role="img"+aria-label. Design tokens used. No legacy regression, no colour/render bug. GATE 2026-06-16 (Critic) · C-10 PASS —node scripts/smoke.mjs→ 776/776 exit 0 (was 71 pre-piano; +705 piano checks). Diff ADDED a piano block, kept ALL prior registry/matcher checks. Sweeps 14 qualities × {C,G} × {root,shell,rootlessA,rootlessB,default} asserting: valid shape (notes/pcs/bass/style/label),pcs ⊆ voicingToneSet(quality,actualStyle), real 3rd (or sus tone) present, true 7th present in shell/rootless whenhasTrueSeventh,notes ∈ [0,36],bass===min(notes), no-dup-note, determinism, and chain pcs-preservation. Adversarially proven NON-vacuous: inject pc1 into pcs → 125 fails, exit 1 (pcs⊆toneSet bites);bass=max(notes)→ 140 fails, exit 1; revert L-13 dedupe (notes=placed) → the no-dup check fails on exactlysus2@0 [rootlessB] notes=[26,26,31]+sus2@7 [21,21,26], exit 1. So the suite now passes LEGITIMATELY because L-13 fixed the resolver, not because any check was weakened. piano.js restored to its L-13 diff after each sabotage (git: 9 insertions, clean). GATE 2026-06-16 (Critic) · L-13 PASS — minimal fix at the single funnel point inpianoVoicing:const notes = [...new Set(placed)](dedupe ABSOLUTE notes),pcs/bassderived from the deduped array so both stay consistent. Verified via a throwaway resolve-hook ESM check (written + deleted): (a)pianoVoicing({rootPc:0,quality:'sus2'},{style:'rootlessB'})→[26,31]distinct (was[26,26,31]); (b) NO default-style voicing across all 14 qualities has a duplicate, so the dedupe is a pure no-op on the default/chain path — L-11's render is unaffected; ii-V-I chain[14,17,24]|[19,23,29]|[24,28,35]all distinct & voice-led. The full 56-voicing correctness is re-asserted by the now-776-green smoke (pcs⊆toneSet, 3rd, 7th, [0,36], bass for every quality×style). Safety reasoning — dedupe NEVER drops a needed note: a JSSetof absolute integers merges two entries only when they are the identical integer, i.e. identical pc AND identical octave — the same physical key, which can sound only one note anyway. Two musically-distinct intended tones (different pc, or same pc a different octave like 14 vs 26) yield different integers and are never merged. The sus2 collision is a genuine unison (pc2 stand-in 3rd at +24=26 vs synthesized 9th at +12=26, both pc2 same octave) — a redundant doubling, safe to drop. No information loss possible. build green; default + chain paths unchanged.
Backlog (future sprints)
-
Retire
EducationPanel.jsx— confirmed orphaned (no importer anywhere insrc/, D-20 gate verified); delete after the Knowledge Center ships. FoldCurrentJamPanel's overlapping content (voicings/scales/similar progressions) into the Knowledge Center and retire it too. -
Level-tag
FAMOUS_PROGRESSIONS(src/lib/education.js, Professor): famous-progression cards are exempt from the level filter this sprint (Maestro call 2026-07-08, per D-20 open question 1). -
Drift guards in smoke (Critic, tiny): two hand-synced duplications need permanent smoke checks — JamGuide.jsx's copy of the validator's
resolveDegree(fold in the L-24 gate's 16-degree × 14-quality drift test) and the 8-word technique vocab duplicated betweenvalidate-kb.mjsLICK_TECHNIQUESandLickCard.jsxTECHNIQUE_VOCAB(C-21 finding). -
pianoVoicingshould returnrootPc(Luthier, tiny): callers currently must attach it themselves (JamGuide and VoicingBrowser both do); returning it at the source removes the false-"R" foot-gun for future consumers (D-24 gate observation — NOT a live bug, both call sites verified correct 2026-07-08). -
docs/kb-backlog.mdis stale (Professor, tiny): still lists gospel/pop guitar + jazz/gospel piano as "todo" though shipped; P-30 (rnb piano) AND P-31 (blues piano, both 2026-07-10) need done entries — refresh next content iteration (flagged by P-30 + C-31 sweep, outside their locks). -
scripts/loop-fixtures.mjsheader comment drift (tiny): cites "App.jsx:322-324" for adjacent-dup suppression; L-31 shifted it to ~line 364 — comment-only, fix when the file is next touched (C-31 sweep finding). -
Fingering view lost at gallery thumb size (Muse, small): D-30's gallery renders ChordDiagram at
size="thumb", which never draws finger numbers — nothing in the browser shows fingering anymore (D-30 gate note 2026-07-10). If pedagogically wanted: tap-to-enlarge tosize="full"inside a gallery cell. -
Negative-fret shape handling inconsistency (Luthier, small):
voicings.jsskips shapes that compute negative frets whilechordAudio.guitarShapeToNotesslides them up an octave — pre-existing, flagged at the L-23 gate; unify someday. -
Jam Guide phase 3: bass pattern renderer (guitar → piano → bass roadmap; MiniPiano + piano recipe resolver shipped in sprint-knowledge-center).
-
Content: piano packs (jazz → gospel → neo-soul first), then bass packs (blues → jazz → funk first) — see
docs/kb-backlog.md. -
guideTonesthird bug (L-12, Luthier — small):guideTonestakesints[1]as the "third", soadd9[0,2,4,7]reports its 9th (pc 2) as the 3rd instead of the major 3rd (pc 4) — wrong "3rd" lane/badge for add9 (live in gospel + pop-axis Cadd9). Pre-existing since L-01b; flagged by Critic during the D-03 re-gate. Fix: pick the actual 3rd/4th interval (3 or 4, or sus 2/5) rather than positionalints[1]. Smoke + a guideTones truth-table check. -
Learning features (Professor + Luthier): drills tab seeded from
docs/learn-curriculum.md; target-note highlighting; ear-training quiz on own chord history; pocket report from the onset pipeline. -
Progression Builder (GOAL G3): key-relative palette, drag-reorder, Nashville-number toggle, voicing alternatives.
-
Platform (Herald): GitHub Pages docs site; "you're playing the Creep progression" engagement hook; contributor leaderboard for styles added.
Iteration log
(Maestro appends one line per completed iteration: <date> · <task ids done> · <next>.)
- 2026-06-14 · done: M-01 · in-review (awaiting user pick): D-00a/b/c viz concepts · next: D-SEL (user chooses) → then L-01/D-01/D-02 implement chosen concept
- 2026-06-15 · done: D-00a/b/c, D-SEL (Roadmap chosen), L-01 (match.js + banner refactor), L-01b (guideTones/voiceLeadingPairs/soloScale) — Critic PASS both · next: L-02 (JamGuide shell) → D-01 (RoadmapTrack) ‖ D-01b (ChordDiagram)
- 2026-06-15 · done: L-02 (JamGuide shell + App mount), D-01 (RoadmapTrack), D-01b (ChordDiagram), D-02 (assembly + playhead rotation + thumbnails) — Critic PASS all 4, audio contract intact (App.jsx +10/−0) · Roadmap Jam Guide MVP is live & builds green · next: D-03 (fretboard cross-link, backlog) ‖ P-01 (gospel content) ‖ H-01 (README reframe)
- 2026-06-15 · done: P-01 (gospel guitar pack — 5 progs × 2 plays, validator 9 styles/45/90), H-01 (README reframed as learning platform, stale frontend/ paths fixed) — Critic PASS both · next ready: P-02 (pop pack) ‖ H-02 (CONTRIBUTING) ‖ C-01 (smoke harness) ‖ D-03 (fretboard cross-link)
- 2026-06-15 · done: P-02 (pop guitar pack — KB now 10 styles/50/100), H-02 (CONTRIBUTING.md + issue templates), C-01 (scripts/smoke.mjs — 71/71, adversarially proven to catch a broken matcher) — Critic PASS all 3 · SPRINT
sprint-jam-guideCOMPLETE → opening PR to main · remaining (next sprint): D-03 fretboard cross-link, piano/bass packs, drills - 2026-06-15 · done: D-03 (tap station → guide tones on the main Fretboard; root-cause fix to
guideToneshasSeventh + badge hardening) — Critic returned once (add9/maj6/min6 mislabeled 5th/6th as "7"), fixed, PASS on re-gate · audio contract intact · folded into PR #2 (completes the flagship) · filed L-12 (guideTones third bug) to backlog · next: seed piano phase-2 sprint (resolver + MiniPiano + wire) - 2026-06-15 · new sprint
sprint-jamguide-pianocut off sprint-jam-guide (keeps PR #2 stable) · done: M-02 (seed), L-10 (src/lib/piano.jsvoicing resolver — shells/rootless A·B/root, voice-leading threading; Critic PASS, 56 voicings, 0 wrong notes) · next ready: D-10 (MiniPiano) ‖ C-10 (smoke piano) → then L-11 (wire piano tab) · L-10 chosen as a new unimported lib so the user's live frontend review stayed undisturbed - 2026-06-16 · done: D-10 (extended existing
MiniPiano.jsxwith additivevoicingprop — legacy lh/rh path for ChordDetailModal/ExplorePanel byte-unchanged), C-10 (smoke +705 piano checks → 776 total), L-13 (resolver dedupe —[...new Set], fixes sus2 dup-note C-10 caught) — Critic PASS all 3 (adversarially proved C-10 checks bite + dedupe never drops a needed note) · mid-iteration corrections: D-10's "new file" premise was wrong (MiniPiano already existed + imported) → re-scoped to additive extend; C-10 correctly turned the branch red surfacing a real wart → filed+fixed L-13; 3 subagents hit API errors (2 produced nothing, 1 landed its diff before dying) · L-11 (wire piano tab) intentionally HELD — it's the first UI-visible change; waiting until the user finishes reviewing localhost:5173 · next: L-11 on the user's go - 2026-07-08 · new sprint
sprint-knowledge-centerseeded on the SAME branch (user directive: continue onsprint-jamguide-piano) · user asks: playable voicings per chord, lick/technique cards, intermediate progressions (easiest in-app surface = level tags + filter), Knowledge Center visual restructure, keep expanding KB · L-11 hold LIFTED, carried forward · loop scheduled: /jam-loop every 30 min × 24 iterations (12 h) · ready now (file-disjoint): L-11 ‖ D-20 ‖ L-20 ‖ C-20 - 2026-07-08 · iteration 1/24 · done: M-03, L-20 (
4b0f0c8audio engine), L-11 (7b669f8piano tab LIVE), D-20 (96dda6aKnowledge Center concept), C-20 (793e60alick/level schema, smoke 787) — Critic PASS all four, zero returns · findings folded into the board: D-21 lock +=voicings.jsexport-only (GUITAR_SHAPES private); L-22 deps += P-21; P-21 serialized behind P-20 (jazz/**overlap); filed L-23 (pre-existinggetGuitarVoicingsrootStr fret-label bug, found by L-20); D-20 discovered ExplorePanel + EducationPanel are ORPHANED (never mounted) → retirement backlogged; famous-progressions level-filter exemption recorded · next ready (file-disjoint): D-21 ‖ P-20 ‖ D-22 (D-22 may build against the SCHEMA fixture until P-21 lands) - 2026-07-08 · iteration 2/24 · done: D-22 (
44d9c4fLickCard), D-21 (3c903adVoicingBrowser — returned once: rootless voicings badged lowest voice as "R", one-line rootPc fix, PASS on re-gate), P-20 (c08b334— returned once: 3 caption theory misstatements, string fixes, PASS on re-gate; KB 56 progs/112 plays, all jazz/gospel/rnb progressions level-tagged) · incident: both first-round gates stalled on API watchdog (600s) twice for P-20 — fresh critic instances completed them; one cron fire absorbed into gate completion · Critic gate quality note: both returns were real musical defects caught before commit - 2026-07-08 · iteration 4/24 · done: P-21 (
6ea108912 licks blues/jazz/funk — every note pitch-verified), P-22 (9e2567cjazz piano cell, KB's first authored piano pack, 126 plays — returned once: 6 prose voice-leading overclaims on fifths-apart dominants, fixed + arithmetic-verified, PASS on re-gate), L-22 (78706ceKnowledge Center shell LIVE — 4-section dock, level filter, licks grid; App.jsx +1 line, audio contract grep-clean) · filed: C-22 (validator span check), L-24 scoped out of P-22 (authored-pack rendering) · promoted: L-24, C-22, P-23 · iteration 5 batch already in flight: D-23 ‖ D-24 ‖ P-24 - 2026-07-09 · iteration 8/24 — SPRINT
sprint-knowledge-centerCOMPLETE · done: C-21 (sprint-end sweep — build/validator/smoke all green on 72c6d45; full-App SSR renders; authored vs computed piano paths both proven; zero dead imports; audio contract +1 line since seed) · PR #3 opened: https://github.com/whattheflat/JamBuddy/pull/3 (supersedes PR #2 — main hadn't absorbed it) · all 21 sprint tasks done, 4 returned-then-fixed by the gate, 0 unresolved · loop cron deleted after 8 of 24 budgeted iterations (board empty) · remaining backlog: EducationPanel retirement, FAMOUS_PROGRESSIONS level tags, smoke drift guards, pianoVoicing rootPc, negative-fret unify, L-12, bass renderer - 2026-07-09 · iterations 6–7/24 · done: L-25 (
e24aa4binstrument-scoped modal tabs), C-22 (b4e8f12validator hand-span rule, smoke 799), P-23 (564a9e0gospel piano cell, 140 plays — returned once: one improv-row scale claim false for vi7/iii7, split into exact rows, PASS re-gate; 39/40 first-pass claims held), L-24 (2165bb5authored piano packs render at stations — implementer agent hung at verification after ~1 h, killed, completion-pass agent audited + finished; Critic PASS with 0 resolver drift) · incidents: P-23 stalled once mid-authoring (resumed from transcript, no loss); L-24 hung silently (diff intact, completed by fresh agent) · backlog: resolveDegree drift guard filed · board empty except C-21 → sprint-end sweep + PR - 2026-07-08/09 · iteration 5/24 · done: D-23 (
db397f6VoicingBrowser show prop + LickCard stack-guard), D-24 (e2110aeMiniPiano thumbs crop to voicing span, 266→142 px), P-24 (11 licks rock/country/reggae — KB now 23 licks across 6 styles, every note pitch-verified) — Critic PASS all three, zero returns · D-24 gate raised a false alarm on the D-21 rootPc fix (its harness bypassed VoicingBrowser; Maestro verified line 297 intact — no regression); hardening idea backlogged (pianoVoicingreturn rootPc) · promoted L-25 · next ready (all file-disjoint): L-24 ‖ L-25 ‖ C-22 ‖ P-23, then C-21 closes the sprint - 2026-07-10 · iteration 4/24 — SPRINT
sprint-glance-and-loopCOMPLETE · done: P-31 (81cd230blues piano cell, 164 plays — returned once: jump-kicks bars 3-4 dyad orientations flipped + 2 prose rewordings, fixed, PASS scoped re-gate), C-31 (sprint-end sweep at81cd230— build/validator/smoke 817 all green; full-App SSR renders with rail+gallery+strip coexisting; whole-sprint App.jsx diff = ONE hunk in the progression effect, contract grep 0 hits; no dead imports; every gate-promised follow-up verified filed) · all 11 sprint tasks done, 2 returned-then-fixed (D-31, P-31), 0 unresolved · PR #3 updated with the sprint summary; loop cron deleted after 4 of 24 budgeted iterations (board empty) · new backlog: loop-fixtures header line-ref drift; kb-backlog needs rnb+blues done entries - 2026-07-10 · iteration 3/24 · done: L-33 (
c78baf4glance mode LIVE — playhead accordion, licks strip, heard-live fallback; gate SSR 37/37, dense-less VoicingBrowser byte-identical to0945a08, token matcher proven hostile-proof, App.jsx untouched by construction), L-31 (ce24d54commit layer 2/3/6 — gate re-traced all five scenarios independently + 3 hostile traces; REPLACE_VOTES=3 proven load-bearing; audio contract grep-clean) · all three user asks now end-to-end on the branch · P-31 (blues piano, 164 plays) authored — gate in flight; its verifier self-caught 3 prose overclaims pre-review · C-31 promoted (holds until P-31 lands so the sweep sees a settled tree) · next: gate P-31 → C-31 closes the sprint - 2026-07-10 · iteration 2/24 · done: P-30 (
b51daa1rnb piano cell, KB 154 plays — PASS first try, a piano-pack first; found+fixed its own 36-key-window stacking defect pre-review), L-30 (4cc0009detector rewrite: dup-collapse, weak-period ghost rejection, len 2–8, ≤1 edit/cycle with ≥2-exact evidence gate, recency-weighted coverage — smoke 817/817, gate ran 15 novel probes, 0.2–0.7ms/call) · L-33 built (playhead accordion + LicksStrip + heard-live fallback, SSR 24/24 self-checked) — gate in flight · L-31 dispatched with both gates' findings folded (flap-survival constraint, docstring ride-along) · both watchdog-stalled agents recovered cleanly via resume · promoted: P-31 · next: gate L-33, land L-31, then C-31 closes - 2026-07-10 · iteration 1/24 · done: M-04, D-30 (
0945a08VoicingBrowser gallery — all shapes/styles side by side, no chips; PASS first try), C-30 (fdd93c717 loop fixtures + smoke wiring; PASS — found the len² self-overlap artifact as the root cause of the user's missed 3-chord loops, folded into L-30/L-31 DoDs), D-31 (6c7a1a7glance-mode "playhead accordion" doc — returned once on piano-gallery width math, fixed, PASS re-gate) · in flight: L-30 (detector redesign, dispatched early — C-30 contract ready), P-30 (rnb piano) — both stalled once on the 600s API watchdog near completion, both resumed via SendMessage · promoted: L-33 (ready, locks per D-31 doc) · finding worth noting: "5 chords then 2 others" passes at pure-function level — the live failure is the ghost-pattern flapping starving the 2-vote commit layer (L-31's trace case) - 2026-07-10 · new sprint
sprint-glance-and-loopseeded on the SAME branch (commits extend PR #3) · user asks: all voicing variations side-by-side with no button pushing; fix loop detection (misses a returning 3-chord loop and a 5-chords-then-2-others shape); glanceable zero-click learn session that follows the live jam · loop scheduled: /jam-loop every 30 min × 24 iterations (12 h, cron 13,43) · ready now (file-disjoint): C-30 ‖ D-30 ‖ D-31 ‖ P-30, then C-30→L-30→L-31 and D-30+D-31→L-33 - 2026-07-08 · iteration 3/24 · done: L-21 (
951d544VoicingBrowser live in ChordDetailModal Guitar/Piano tabs + JamGuide enlarged stations — the "playable voicings per chord" user ask is now end-to-end), L-23 (f4e0ac6getGuitarVoicings base-fret fix — 252 movable-shape placements corrected, A-shape C was labeled fret 1 not 3) — Critic PASS both, zero returns this round · follow-ups filed: VoicingBrowsershowprop (Muse), negative-fret handling inconsistency (Luthier), stale JamGuide header comment · P-21 lock narrowed to the 3 guitar.js files → P-22 now disjoint · next ready (file-disjoint): P-21 ‖ P-22 ‖ L-22 (licks section may land empty-state-first per D-20 doc)