# Ensemble Ledger — Live Task Board The shared queue all agents read and write. Lifecycle and rules: [`PROTOCOL.md`](PROTOCOL.md). Roster + cadence weights: [`ROSTER.md`](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-jam-guide` (branch: `sprint-jam-guide`) 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 | | 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). `findLoopPosition` extracted byte-identical (verified by diff, no semantic change). matchLoopToProgression verified rotation-invariant with quality tie-break: `[Dm7,G7,Cmaj7]`→`jazz-251-major` rot 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.js` holds only matching/position logic + a small local chord-root parser (theory.js exposes no pc helper — acceptable). Note (non-blocking): banner refactor also adds `onChordClick` click affordances — beyond a pure extract but already wired to `setSelectedChord`/ChordDetailModal in App.jsx and behaviour-preserving for `findLoopPosition`. Minor: `match.js` uses extensionless `import … from './theory'` (works under Vite; matches existing `education.js` convention). > 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). `guideTones` triad fallback flags `hasSeventh:false` and uses the 5th. `soloScale` defaults 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.jsx` is +10 lines, zero deletions — only the `import JamGuide` line and the `` mount (placed last, after the tuner block). `handleNote`/`handleChroma`/`handleOnset` lines do not appear anywhere in the diff; no `useCallback` dep, ref-sync `useEffect`, or `AudioCapture` prop 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 from `style.instruments` keys, style labels from `meta.label`); matched-progression vs. dashed-fallback both render. Disabled instrument tabs marked "soon" with `disabled` + 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 running `guideTones` — C-major **triad** returns `hasSeventh:false`, secondary anchor = the 5th (pc 7), and the Station labels it **"5th"** not "7th" (`seventhKind` gate at line 113). The headline rail picks `voiceLeadingPairs(...)[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; playhead `pct` clamps at 0 when `position=-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). Both `thumb`/`full` sizes; `full` adds 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 build` green (gospel imported by `kb/index.js`, 87 modules, built in 5.65s). Schema: 5 progressions × 2 plays = 10 plays, all ids `gospel-`-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 in `index.js` mirroring 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 via `checkGuitarShape`. **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.md` is 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|linux` all in `package.json`; `scripts/validate-kb.mjs` exists. **No `frontend/` path remains**; build output dir stated as `release/` matches electron-builder `directories.output: "release"`. git clone URL `whattheflat/whattheflat.git` matches actual `origin`. **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 in `index.js`; the transient "pop not registered" mid-batch failure is resolved — `index.js` imports popMeta/popProgressions/popGuitar and exports the `pop` block). Schema: 5 progressions × 2 plays = 10, all ids `pop-`-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 plain `maj`; 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 list `maj,min,dom7,maj7,min7,dim,dim7,half_dim,aug,sus4,sus2,maj6,min6,add9` matches `CHORD_TYPES` keys 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 reads `9 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 REAL `kb/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**: sabotaged `matchLoopToProgression` to 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 inline `module.register` ESM hook retries ONLY on `catch`, ONLY for relative+extensionless specifiers (`/^\.{1,2}\//` && `!/\.[mc]?js$/`) — verified the regex skips `./theory.js`, `react`, `node:url`, `./a.mjs` and retries only `./theory`/`../lib/match`; it cannot mask a genuine missing module (the `.js` retry 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.json` untouched (git: only `src/data/kb/index.js` is 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-02 PASS** — the load-bearing integration is correct. **Independent rotation check**: `canonicalPos = ((position − rotation) % n + n) % n` translates a `findLoopPosition` index (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: thumbnail `rootPc` and RoadmapTrack station root are byte-identical `(((keyRoot+deg)%12)+12)%12`, and `keyInfo.root` (a note *name*, e.g. `detectKey`→"F#") is converted once via `chordRootPC` → pc, guarded `>=0`. stationVoicings `chords[i]` aligns 1:1 with `degrees[i]` (canonical). Auto-scroll is prop-driven off `position` (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 and `tailwind.config.js` edit 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. --- ## Backlog (future sprints) - **Jam Guide phase 2:** `MiniPiano.jsx` + piano recipe resolver (unblocks piano packs); bass pattern renderer. - **Content:** piano packs (jazz → gospel → neo-soul first), then bass packs (blues → jazz → funk first) — see `docs/kb-backlog.md`. - **Jam Guide phase-2 follow-up (D-03, Luthier+Muse):** tap a Roadmap station → highlight that chord's guide tones on the **main Fretboard** (deferred from D-02: needs selected-station state lifted into `App.jsx` without disturbing the audio-callback ref contract). Build-green + audio-contract gate required. - **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: ` · · `.)_ - 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-guide` COMPLETE** → opening PR to main · remaining (next sprint): D-03 fretboard cross-link, piano/bass packs, drills