ledger: seed sprint-jamguide-piano; L-10 done (Critic PASS); promote D-10/C-10; log iteration
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+19
-1
@@ -7,7 +7,23 @@ The shared queue all agents read and write. Lifecycle and rules: [`PROTOCOL.md`]
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Active sprint: `sprint-jam-guide` (branch: `sprint-jam-guide`)
|
## Active sprint: `sprint-jamguide-piano` (branch: `sprint-jamguide-piano`)
|
||||||
|
|
||||||
|
**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 | `src/components/MiniPiano.jsx` — SVG mini-keyboard (~2 octaves) highlighting a voicing's notes (root in accent), thumb/full sizes, design tokens, AA contrast | design | ready | L-10 | `src/components/MiniPiano.jsx` | renders any `pianoVoicing` output in any key; compiles standalone; legible at thumb size |
|
||||||
|
| L-11 | Wire piano into `JamGuide.jsx`: Piano tab active; per station render `MiniPiano` from `pianoVoicing`; keep the guitar path intact | engineering | backlog | L-10, D-10 | `src/components/JamGuide.jsx` | piano tab shows per-station keyboards synced to the loop; guitar unchanged; build green |
|
||||||
|
| 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 | ready | L-10 | `scripts/smoke.mjs` | smoke covers the piano resolver; exits non-zero on regression |
|
||||||
|
|
||||||
|
> 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.
|
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.
|
||||||
|
|
||||||
@@ -49,6 +65,7 @@ Emphasis this sprint: **ship the Jam Guide MVP** (put the 8 guitar style packs o
|
|||||||
> 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) · **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-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.jsx` is purely additive — exactly (a) one new `useState(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** for `handleNote|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, `null` on deselect; the existing `selectedStation→null` reset effect (loop/style/instrument change) flows through the new cross-link effect and clears the highlight; an unmount-cleanup effect also clears; all guarded `onFocusChord?.` so JamGuide stays standalone. Fretboard **null path verified unchanged** (`hasFocus=false` ⇒ `tag` always null ⇒ `if(!color&&!tag)` collapses to original `if(!color)`; no halo/badge/legend). Emphasis is visually distinct (purple ring `DOT_R+3` + degree badge, accent token `#a855f7`). Triad labeling **correct** for maj/min/dim/aug/sus4/sus2 (all `hasSeventh:false` → badge/legend read "5"). **DEFECT (blocking)**: `guideTones`' secondary-anchor heuristic is `hasSeventh = ints.length >= 4`, so the **4-tone non-seventh** KB qualities `add9` `[0,2,4,7]`, `maj6`/`min6` `[0,4,7,9]` return `hasSeventh:true` with `seventh = ints[last]` = the **5th** (add9) or **6th** (maj6/min6). D-03's `focusLabel` trusts 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**: `add9` is in gospel progression qualities (×4), `min6` in bossa + rnb qualities — tapping those stations mislabels a non-7th. Verified by running `guideTones(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 tighten `guideTones` so a chord with no minor/major 7th reports `hasSeventh:false` and falls back to the 5th (root cause, L-01b owns theory.js), or have `focusLabel`/the badge derive the actual interval of `seventh` above 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 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.jsx` is purely additive — exactly (a) one new `useState(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** for `handleNote|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, `null` on deselect; the existing `selectedStation→null` reset effect (loop/style/instrument change) flows through the new cross-link effect and clears the highlight; an unmount-cleanup effect also clears; all guarded `onFocusChord?.` so JamGuide stays standalone. Fretboard **null path verified unchanged** (`hasFocus=false` ⇒ `tag` always null ⇒ `if(!color&&!tag)` collapses to original `if(!color)`; no halo/badge/legend). Emphasis is visually distinct (purple ring `DOT_R+3` + degree badge, accent token `#a855f7`). Triad labeling **correct** for maj/min/dim/aug/sus4/sus2 (all `hasSeventh:false` → badge/legend read "5"). **DEFECT (blocking)**: `guideTones`' secondary-anchor heuristic is `hasSeventh = ints.length >= 4`, so the **4-tone non-seventh** KB qualities `add9` `[0,2,4,7]`, `maj6`/`min6` `[0,4,7,9]` return `hasSeventh:true` with `seventh = ints[last]` = the **5th** (add9) or **6th** (maj6/min6). D-03's `focusLabel` trusts 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**: `add9` is in gospel progression qualities (×4), `min6` in bossa + rnb qualities — tapping those stations mislabels a non-7th. Verified by running `guideTones(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 tighten `guideTones` so a chord with no minor/major 7th reports `hasSeventh:false` and falls back to the 5th (root cause, L-01b owns theory.js), or have `focusLabel`/the badge derive the actual interval of `seventh` above 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 build` green (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 real `guideTones`**: `hasSeventh` now keys on the actual presence of interval 10 or 11 (`ints.find(i=>i===10||i===11)`), not `length>=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**: `focusSeventhLabel` derives 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 → `maj` fallback, no crash. **Null-focus path byte-equivalent**: `jamFocusChord=null` ⇒ `hasFocus=false` ⇒ `tag` always null ⇒ `if(!color&&!tag)` collapses to the original `if(!color) return null`; no halo/badge/legend; `focusSeventhLabel` is dead-but-harmless. **No collateral**: `voiceLeadingPairs`/`soloScale` signatures untouched (theory.js diff hits only `guideTones` body+jsdoc); ii–V–I rails still correct (Dm7→G7 C→B [0→11,−1]; G7→Cmaj7 F→E [5→4,−1]) and `voiceLeadingPairs` does 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.jsx` purely additive (one `useState(jamFocusChord/null)` outside the callback/ref block + an additive `jamFocusChord=` prop on `<Fretboard>` + `onFocusChord=setJamFocusChord` on `<JamGuide>`); grep of changed lines for `handleNote|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):* `guideTones` uses `ints[1]` for the 3rd, so `add9` `[0,2,4,7]` reports its **9th (pc 2)** as `third`, 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) · **D-03 PASS (re-gate)** — the returned defect is fixed at the root cause and hardened. `npm run build` green (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 real `guideTones`**: `hasSeventh` now keys on the actual presence of interval 10 or 11 (`ints.find(i=>i===10||i===11)`), not `length>=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**: `focusSeventhLabel` derives 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 → `maj` fallback, no crash. **Null-focus path byte-equivalent**: `jamFocusChord=null` ⇒ `hasFocus=false` ⇒ `tag` always null ⇒ `if(!color&&!tag)` collapses to the original `if(!color) return null`; no halo/badge/legend; `focusSeventhLabel` is dead-but-harmless. **No collateral**: `voiceLeadingPairs`/`soloScale` signatures untouched (theory.js diff hits only `guideTones` body+jsdoc); ii–V–I rails still correct (Dm7→G7 C→B [0→11,−1]; G7→Cmaj7 F→E [5→4,−1]) and `voiceLeadingPairs` does 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.jsx` purely additive (one `useState(jamFocusChord/null)` outside the callback/ref block + an additive `jamFocusChord=` prop on `<Fretboard>` + `onFocusChord=setJamFocusChord` on `<JamGuide>`); grep of changed lines for `handleNote|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):* `guideTones` uses `ints[1]` for the 3rd, so `add9` `[0,2,4,7]` reports its **9th (pc 2)** as `third`, 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 build` green (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: exports `pianoVoicing({rootPc,quality},opts?)`→`{notes,pcs,bass,style,label}` plus `pianoVoicingChain`, `hasTrueSeventh`, `voicingToneSet` (and re-exports `guideTones`); imports ONLY `{CHORD_TYPES, guideTones}` from `./theory`; no `Date`/`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 — every `pcs ⊆ 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, all `notes ∈ [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), so `hasTrueSeventh('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.prev` slides 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 → graceful `maj` fallback, no crash. **One non-blocking nit (NOT a defect):** forcing `rootlessB` (or `rootlessA`) 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/`pianoVoicingChain` use 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.js` NOT 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) % 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.
|
> 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.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -74,3 +91,4 @@ _(Maestro appends one line per completed iteration: `<date> · <task ids done>
|
|||||||
- 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-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
|
- 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
|
||||||
- 2026-06-15 · done: D-03 (tap station → guide tones on the main Fretboard; root-cause fix to `guideTones` hasSeventh + 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 · done: D-03 (tap station → guide tones on the main Fretboard; root-cause fix to `guideTones` hasSeventh + 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-piano`** cut off sprint-jam-guide (keeps PR #2 stable) · done: M-02 (seed), L-10 (`src/lib/piano.js` voicing 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
|
||||||
|
|||||||
Reference in New Issue
Block a user