feat(cli): --rhythm-* — the transport syntax reaches the generator (S16 Phase 2, slice 3) - #116
Conversation
…wns unit representability SWG0305 (zero/unrepresentable bar), SWG0306 (an expansion with no onsets is a deliberate typed error, not a mysterious empty candidate set — the #115 review's first obligation), SWG0307 (empty kernel literal). A unit unrepresentable in whole ticks at the score's PPQN is the same incompatibility SWG0301 already names. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM
Fifteen failing tests and the adapter they call: cli::rhythm_pattern compiles the --rhythm-* flags against the seed score's master timeline into an explicit palette plus the versioned expansion artifact. All behavioral bodies unimplemented!(). What they pin, from docs/swang/spec.md §2 and the #115 review: - the kernel literal is a transport contract: ragged is SWG0101 at --rhythm-kernel, a foreign cell SWG0102, whitespace SWG0103 (never normalized), an empty literal or row SWG0307; - the unit literal parses to whole ticks at the score's PPQN — 1/16 at 480 is 120 — and malformed, zero, or unrepresentable units are all SWG0301 with the PPQN named in the message; - bar geometry comes from the master timeline: a meter change is SWG0304, a unit that does not divide the bar SWG0301; - a silent expansion is SWG0306 — a deliberate typed error, never a mysterious empty candidate set (the review's first obligation); - budget breaches map to SWG0201 at --rhythm-max-cells; - the spec kernel compiles into one rest-padded 4/4 bar with offsets 0 240 360 480 840 960; the artifact is byte-stable, newline- terminated, and carries schema/version/ppqn/meter/bar geometry and the activity line; - artifact fingerprints equal explicit_rhythm_diagnostics — no duplicated hashing anywhere (spec acceptance 16); - density without a rhythm seed is SWG0303 in the module too, so no caller can smuggle an unseeded pruning past clap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM
…ase 2) The --rhythm-* flags land on griff generate, wired through the pieces every earlier slice prepared: the kernel literal parses under its registry codes, bar geometry resolves from the seed score's master timeline (constant meter or SWG0304; whole-tick bar or SWG0305), the expansion runs under its budgets, a silent expansion stops at SWG0306 before any generation, the lowering cuts bars under the tail policy, and the palette enters ranked_candidates as the explicit override the #115 slice built. The versioned griff.pattern-expansion artifact (alphabetical keys, pretty-printed, newline-terminated) is written before pitch generation, its fingerprints taken from the public explicit diagnostics; the generate summary prints the explicit palette uncompressed, silent bars included. Fifteen module tests green; two blessed integration goldens prove the end-to-end path: a depth-1 kernel at 8000 bps over simple_4_4 ranks ten candidates over a six-template palette whose four silent bars survive verbatim (their fingerprint is the FNV offset basis — an empty grid), the artifact is byte-stable, --seed leaves it untouched, --rhythm-seed changes it, and a ragged kernel exits with error[SWG0101] at --rhythm-kernel before anything is written. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM
|
Warning Review limit reached
Next review available in: 43 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthrough
ChangesExplicit rhythm generation
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant GriffCLI
participant RhythmPattern
participant GriffPattern
participant GriffSwang
participant CandidateRanking
User->>GriffCLI: griff generate --rhythm-* options
GriffCLI->>RhythmPattern: compile_pattern(args, score, bars)
RhythmPattern->>GriffPattern: expand and linearize kernel
RhythmPattern->>GriffSwang: lower rhythm expansion
GriffSwang-->>RhythmPattern: rhythm templates
RhythmPattern-->>GriffCLI: PatternPlan and artifact JSON
GriffCLI->>CandidateRanking: rank candidates with explicit templates
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Architecture/code review — blockers before Phase 2 can closeThe main path is well assembled: the CLI adapter is separate from the future grammar, unit/tail/kernel errors map to stable SWG codes, geometry comes from PPQN + master-bar meter, the artifact is produced before pitch generation, and fingerprints reuse I found one functional blocker and two contract/test blockers. P1 — SWG0306 still permits the exact mysterious empty candidate set it was introduced to prevent
Concrete reproducer: This compiles to Add a red integration test for this case and reject it before artifact writing and before P1 — diagnostics location contract still contradicts the implementationSpec §1.5 still says every pre-grammar diagnostic location is a Rewrite §1.5 to distinguish locations explicitly, for example:
Do not leave the constitution saying one thing while the public error type says another. Software already has enough organized mythology. P2 — claimed red coverage does not exist for two newly registered codesThe final
Both codes are introduced by this PR and both paths should have red tests asserting code and location. Add at least a direct test for PPQN/meter producing zero/non-whole bar duration and a CLI/module test for density Also note that P2 — RepeatVariation exception is not reflected in user-facing proseThe PR body records the exception, but stdout currently says: unconditionally. That is false for CI is still in progress on |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f66aac1c7a
ℹ️ 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".
§1.5 demanded a NodePath for every pre-grammar diagnostic while the Phase-2 boundary honestly reports the offending flag or INPUT. Name all three location kinds — structural NodePath, transport flag/INPUT, future source span — so the contract matches what each layer can know (#116 review, comment 4974708085). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM
…hole expansion The #116 review's blocker, reproducible: 17 cells at 16 slots per bar rest-pad into [silent, sounding]; with --bars 1 only the silent template is ever used, every strategy emits silence, the reranker drops every candidate, and the user meets the old mysterious "no candidate survived scoring" — after the artifact was already written. The new test demands SWG0306 name the --bars window instead, and passes bars into compile_pattern so the check can exist. Also landed with it: the missing SWG0305 test (an empty master timeline), the SWG0308 tests that go past u16 — the transport type widens to u32 so an out-of-scale density meets its registry code instead of a bare clap range error — and the plumbing both need. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM
…writing fiction check_bars_window runs after the lowering and before the artifact: the scheduler rotates the palette over --bars, so with fewer bars than templates only a prefix is ever used, and a silent prefix now stops at SWG0306 naming the window — no orphaned artifact, no "no candidate survived scoring" archaeology. The density transport widens to u32 end to end so 70000 bps meets error[SWG0308] instead of a bare clap range message, and the explicit-palette summary line now tells the whole truth: per-bar strategies rotate the palette verbatim, RepeatVariation holds the first grid. Goldens re-blessed accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM
|
Review fixes landed (
Gate: clippy 🤖 Generated with Claude Code |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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 676-677: Validate emit_rhythm_expansion in the surrounding
generation flow before the fs::write call, rejecting paths that alias input or
output, including equivalent existing symlink/canonical paths. Perform this
distinct-path check before any artifact or MIDI writes, and preserve normal
generation only when all paths are distinct.
In `@cli/src/rhythm_pattern.rs`:
- Around line 572-593: Update the duration calculation in seed_score_with_meters
so each master bar uses 480 ticks per quarter note: compute 4 × numerator /
denominator quarter-note units, yielding 1920 ticks for 4/4 and 1680 for 7/8.
Preserve the existing start accumulation and TickRange construction.
- Around line 498-539: The parse_unit calculation must avoid overflow when
multiplying ppqn, the beat constant, and numerator. Replace the unchecked
multiplication used to compute whole with checked arithmetic, and return the
existing malformed SWG0301 diagnostic if any multiplication overflows before the
representability check.
In `@cli/tests/cli.rs`:
- Around line 317-319: Clean up global temporary artifacts before each relevant
CLI test run: at cli/tests/cli.rs lines 317-319, remove dst with
fs::remove_file(&dst).ok() before invoking griff; at cli/tests/cli.rs lines
275-281, remove art inside the run closure before calling griff. Preserve the
existing assertions and artifact-reading behavior.
🪄 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: 2fe2b8e1-c6dc-4fa2-b3c6-9bdc6dcef42b
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (8)
cli/Cargo.tomlcli/src/lib.rscli/src/main.rscli/src/rhythm_pattern.rscli/tests/cli.rscli/tests/snapshots/generate__rhythm_pattern.txtcli/tests/snapshots/generate__rhythm_pattern_ragged.txtdocs/swang/spec.md
Re-review of
|
…tic lottery parse_unit multiplies the user's u64 numerator unchecked: 9607679205057059/13 at PPQN 480 panics in debug and wraps in release. A syntactically valid unit must meet its registry code with the unit and the PPQN named (#116 review, comment 4975910403). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM
…ying The product is u128 over u16 × 4 × u64 inputs — at most 2^82 — so no syntactically valid numerator can overflow it; a too-large unit falls out of the u32 fit check as SWG0301 naming the unit and the PPQN. The lint allow's reason now states the real invariant instead of claiming the user's numerator was validated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM
…s stop lying Three findings from the #116 re-review threads: - critical: --emit-rhythm-expansion writes before generation, so a path aliasing INPUT would clobber the user's tab and one aliasing OUTPUT would be silently overwritten by the MIDI moments later. Both are rejected before anything is written (canonical paths when they resolve, lexical otherwise), and the new integration test proves the input survives byte-identical while no riff is written; - the test fixture's master-bar length formula produced 480-tick "4/4 bars" — harmless only because geometry reads the meter, not the tick range — and now says 1920 like it means it; - both golden tests clean their temp files before running, so a stale artifact can never mask a failed write. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM
|
Re-review fixes landed —
Gate: clippy 🤖 Generated with Claude Code |
Summary
The final Phase 2 slice: the namespaced
--rhythm-*transport syntax ongriff generate, the SWG diagnostic boundary, and the versioned expansion artifact. A fractal kernel now drives the unchanged S6 generator end to end from one command line.Commit sequence (TDD)
de81bc3) — registry appends SWG0305 (zero/unrepresentable bar), SWG0306 (a silent expansion is a deliberate typed error, never an empty candidate set — the feat(core): the explicit rhythm scheduler — silent bars survive the rotation (S16 Phase 2, slice 2) #115 review's first obligation), SWG0307 (empty kernel literal), SWG0308 (density out of range); SWG0301 explicitly owns unit representability.fd92d20) — fifteen failing tests forcli::rhythm_pattern: every kernel-literal failure at its code and flag, unit parsing to whole ticks with the PPQN named, bar geometry from the master timeline (SWG0304/0305), the silent-expansion stop (SWG0306), budget mapping (SWG0201/0202), the spec kernel compiling to offsets0 240 360 480 840 960, artifact byte-stability with geometry fields, fingerprints equal toexplicit_rhythm_diagnostics(spec acceptance 16), and SWG0303 defense-in-depth behind clap'srequires.f66aac1) — the module implementation, clap wiring (requireschains; max-cells default 4096 documented as a frontend default),CliError::Pattern, the explicit-palette summary line (uncompressed, per law 4), the artifact write before pitch generation, and two blessed integration goldens.The goldens tell the story
The end-to-end golden ranks ten candidates over a six-template palette whose four silent bars survive verbatim (their fingerprint
cbf29ce484222325is the FNV offset basis — an empty grid, in the rotation, by law). The artifact is byte-stable across runs,--seedleaves it untouched,--rhythm-seedchanges it. The ragged-kernel golden exitserror[SWG0101] (--rhythm-kernel)before anything is written.Scope notes
grids[0]— with an explicit palette that is the palette's first template, silent or not.-D warningsclean, workspace green except the pre-existing Windows-localemissing_file_golden.After this merges, Phase 2's remaining act is purely musical: run the pipeline against a Dance Gavin Dance riff from the corpus and listen.
Refs #108, ADR-0029, S16 Phase 2.
🤖 Generated with Claude Code
https://claude.ai/code/session_01NkqJUU6d1sW1RAfvyHrqVM
Summary by CodeRabbit
New Features
griff generate, including kernel, density, seed, traversal, unit, depth, and tail options.Bug Fixes
Documentation