feat: auto-derive chord-quality tags from chord voicings (#75) - #88
Conversation
Failing tests for a new `harmony::derive_harmony` deriver that reads each chord's pitch-class set and tags the voicing: power_chord (a bare-fifth dyad), and maj7/min7/sus2/add9 (exact root-relative templates, inversions included). Presence-only and threshold-free, mirroring the technique deriver. References `griff_core::harmony`, which does not exist yet, so the suite fails to compile until the green step. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
`harmony::derive_harmony` scans a track's chord-bearing groups and tags the voicing the tab spells out: power_chord (a bare perfect-fifth dyad) and maj7/min7/sus2/add9 (exact root-relative pitch-class templates, tried from every chord tone so inversions still match their quality). Presence-only and threshold-free — a pure function of the score (SPEC §6), mirroring `derive_techniques`. Slash-chord detection is deliberately deferred: the common plain-triad slash (e.g. G/B) is not expressible with the seventh/sus/add templates and needs its own bass-vs-root model. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
`build_chunk_meta` now also calls `harmony::derive_harmony` and folds the result into the chunk's tags, additively over the curator's choices — the same merge treatment the derived technique tags already get. Curation reads the chord voicings the tab states instead of asking a human to re-tag them. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
Y-statement for the presence-only, template-exact chord-quality deriver: the prior art (pitch-class-set / chord-template matching), why it stays threshold-free (SPEC §6) rather than a confidence recogniser, why it is distinct from `complement::estimate_harmony` (key, not voicing), and the deferral of slash_chord (plain-triad-over-bass is not template-expressible). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
Collapse an assert_eq! that fits within max_width onto one line — a formatting-only follow-up to the red-test commit; no behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughA new ChangesChord-quality auto-derivation
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ca4501f470
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
cli/src/main.rs (1)
1073-1078: ⚡ Quick winAdd a CLI-level regression test for harmony-tag merge behavior.
build_chunk_metanow changes finaltagscomposition, but the nearby test only asserts curator+technique outcomes. Add a case asserting derived harmony (e.g.,Maj7) is preserved in the same merged tag list.As per coding guidelines, "Write tests before implementation (TDD red-green-refactor cycle): run failing tests first, commit before touching implementation code".Proposed test shape
+#[test] +fn build_chunk_meta_merges_derived_harmony_tags() { + // build a score with a chord-bearing group, e.g. Cmaj7 pitch classes + // call build_chunk_meta(..., Some(track_idx), ...) + // assert curator tag still present + // assert technique-derived tags still present when applicable + // assert meta.tags.contains(&SwancoreTag::Maj7) +}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@cli/src/main.rs` around lines 1073 - 1078, The existing test for tag merging in `build_chunk_meta` does not verify that derived harmony tags (such as `Maj7`) are preserved in the final merged tag list. Add a new CLI-level regression test case that exercises the complete merge flow where curator tags are merged with derived technique tags via the first `technique::merge_tags` call, and then the result is merged with `derived_harmony` via the second `technique::merge_tags` call in `build_chunk_meta`. The test should assert that harmony tags are present alongside curator and technique tags in the final merged result. Add the failing test first before making any implementation changes, following the TDD red-green-refactor cycle.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@core/src/harmony.rs`:
- Line 49: Split the current commit ca4501f into two separate commits with the
correct order: first commit should contain only the tests for derive_harmony
from core/tests/harmony_tags.rs, and the second commit should contain the
implementation of the derive_harmony function in core/src/harmony.rs. This
ensures tests precede the implementation as required by the coding guidelines.
---
Nitpick comments:
In `@cli/src/main.rs`:
- Around line 1073-1078: The existing test for tag merging in `build_chunk_meta`
does not verify that derived harmony tags (such as `Maj7`) are preserved in the
final merged tag list. Add a new CLI-level regression test case that exercises
the complete merge flow where curator tags are merged with derived technique
tags via the first `technique::merge_tags` call, and then the result is merged
with `derived_harmony` via the second `technique::merge_tags` call in
`build_chunk_meta`. The test should assert that harmony tags are present
alongside curator and technique tags in the final merged result. Add the failing
test first before making any implementation changes, following the TDD
red-green-refactor cycle.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 3c7fbb61-42e6-4eea-8c7f-6dbac7dc6d2f
📒 Files selected for processing (5)
cli/src/main.rscore/src/harmony.rscore/src/lib.rscore/tests/harmony_tags.rsdocs/decisions.log.md
The browser/phone capture path (`build_chunk_meta_record`) derived and merged only technique tags, so a GP chord the CLI now serializes with `maj7`/`power_chord` was emitted without those harmony tags — making corpus tags depend on which curation front produced the chunk (Codex P2 on #88). Mirror the CLI: derive harmony tags and merge them additively, with a parity test. Also fixes the adjacent technique-parity test, whose hardcoded `tags_idx` "21" no longer selected Intro: #87's LetRing shifted Intro to index 22 in `all_variants()` (web host tests aren't CI-gated, so it went unnoticed). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
Adds a presence-only chord-quality deriver (
harmony::derive_harmony) that reads each chord group's pitch-class set and tags the voicing the tab already spells out — the next of #75's auto-derivation asks afterlet_ring. The tags existed in the taxonomy but were curator-only.What
build_chunk_meta: derived tags merge additively over the curator's choices, the same treatment the derived technique tags getderive_techniquesDeliberately deferred (see
docs/decisions.log.md)G/B, a plain triad over a non-root bass) is not expressible with the seventh/sus/add templates; it needs its own bass-vs-root passNo
SCHEMA_VERSIONbump — additive tag, per the keep-v7 policy from #87.A note on #75's premise
While scoping this I confirmed the issue's "pull-off — the field exists in the
guitarprocrate, just isn't mapped — easy" is mistaken:guitarprov0.3'sNoteEffecthas only a singlehammer: bool(format bit0x02= "hammer-on/pull-off"), already mapped toHammerOn. Telling a pull-off from a hammer-on needs pitch-direction inference against the same-string neighbour, so it was re-scoped to this (the highest-value, most self-contained ask) instead.TDD
red (
162bcda) → green (c41f3e0) → cli wiring (1c12b9e) → docs (14e0fbb) → fmt fixup (ca4501f).Verification
harmony_tagstests + full workspace suite greencargo clippy --workspace --all-targets -- -D warningsclean--no-default-features(the wasm/web path)🤖 Generated with Claude Code
https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
Generated by Claude Code
Summary by CodeRabbit