feat(cli): generate subcommand — tab-seeded riff generation (S6) - #59
Conversation
A golden test that runs `griff generate <fixture> <out.mid>` and snapshots its summary line. Fails until the subcommand exists: clap rejects the unknown subcommand and no snapshots are blessed yet.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
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 (6)
✅ Files skipped from review due to trivial changes (4)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds a Changesgriff generate subcommand
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 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.
Actionable comments posted: 2
🤖 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 `@cli/src/main.rs`:
- Around line 504-505: The success message is printing the raw CLI argument
value instead of the clamped value. The bar_count is set using bars.max(1) to
ensure a minimum of 1, but the format string at lines 504-505 prints the
unclamped bars variable, causing output to show 0 bars generated when 1 was
actually generated. Replace the bars variable reference in the format string
with the clamped bar_count variable. Apply the same fix to the second affected
location at lines 528-529 where the same issue occurs.
- Around line 587-612: The first_bar_rhythm function currently only examines the
first master bar in the score, but should instead find the first bar that
actually contains notes (the "first sounding bar"). Modify the function to
iterate through all master_bars sequentially until finding one that contains
notes in any track/voice combination, then extract the rhythm from that first
bar with content. If no bars contain any notes at all, fall back to the four
quarter notes default. This ensures the rhythm template matches the actual first
sounding bar semantics rather than potentially using silence from an empty first
bar.
🪄 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: 5bc8d4e9-3d13-4966-a506-e4a98c9e1caf
📒 Files selected for processing (7)
cli/src/main.rscli/tests/cli.rscli/tests/snapshots/generate__multi_track.txtcli/tests/snapshots/generate__seven_eight.txtcli/tests/snapshots/generate__simple_4_4.txtcli/tests/snapshots/generate__tempo_change.txtcli/tests/snapshots/generate__two_phrases.txt
Surface the S6 rule generator (generate::generate, ADR-0011) on the .gpx/.mid front door. `griff generate <input> <out.mid> [--seed N] [--bars N]` seeds the generator from the source's own material — its distinct pitch classes as the scale, the rhythm of its first sounding bar as the template, and its meter, tempo, and pitch range — then writes a fresh riff (RhythmCopyPitchSubstitute) to MIDI. Deterministic under a fixed seed. Greens the generate_golden test by blessing its summary snapshots. On a real GP6 tab: an 8-bar riff in the tab's key and groove, playable MIDI.
dbb5575 to
06bc4d0
Compare
What
griff generate <input> <out.mid> [--seed N] [--bars N]— the S6 rule generator surfaced on the.gpx/.midfront door. The engine writes a fresh riff, seeded from your tab's own material, and saves it as playable MIDI.The request is built from the source so the riff sits in the tab's world:
Then
RhythmCopyPitchSubstitutelays a new line over that rhythm. Deterministic under a fixed--seed.How
Thin CLI wiring over the already-tested core
generate::generate; builds aRuleGenerationRequestfrom the importedScore, exports the result viamidi::export_score(same path asexport). No core changes. Adds aCliError::Generatevariant for generation failures.Verified
On the real GP6 tab (Dance Gavin Dance):
→ an 8-bar riff in the tab's 4/4 / 122 BPM, drawing on its full chromatic palette; it re-imports cleanly (8 bars, 128 notes).
Golden-snapshot tested (
generate_golden, mirroringexport's path-scrubbing — the summary line is pinned, the MIDI bytes are deterministic via the byte count). TDD red → green (golden fails first on the missing subcommand, then the command greens it). 20 cli tests green;clippy --all-targets -D warningsclean;fmtclean.Scope
CLI surface only — the generation logic and its tests already live in
core::generate. The tab→request adaptation (scale/rhythm/range extraction) lives in the CLI as request-construction glue, covered by the golden snapshots. Third of three (S4 phrases ✓, S14 structure ✓); S13 (complement arranger) is the remaining one.https://claude.ai/code/session_01TTUbGjzD8ysnVnCJnZJE95
Generated by Claude Code
Summary by CodeRabbit
griff generateCLI subcommand that converts MIDI/Guitar-Pro input into generated riff MIDI output, with--seedand--barsoptions and an on-screen generation summary.generatecommand across multiple fixtures, asserting successful execution, expected stdout, and creation of the generated MIDI output file.