Repository navigation
refactor: dedupe command, client and Remote Script layers without moving the public surface - #130
Merged
Merged
Conversation
Seven require_* helpers in commands/_validation.py had no caller outside their own tests, and CLIENT_METHOD_SPEC_BY_NAME was built only for its import-time duplicate check. The volume and pan tests now pin the helpers that commands actually call, and the duplicate check is a test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159HyNwc4JV7ocTay3N3KL4
Seven device commands (parameters list, active get, preset list, sidechain get, delete, chains list, macro list) repeated the same 13-option signature and body. They now come from _register_device_target_command, and macro set uses the shared _run_device_target_command. The command surface snapshot is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159HyNwc4JV7ocTay3N3KL4
synth.py and effect.py were parallel copies that differed only in the
family name, the wrapped device types and the client method names, which
all follow the {family} pattern. _device_family.py now builds both
groups from a DeviceFamily. Only find stays per module, because its
--type parameter name (synth_type, effect_type) is part of the command
surface snapshot.
The adapter tests for the deleted per-module helpers move to the shared
run_track_device_command; the unused validators hook goes with them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159HyNwc4JV7ocTay3N3KL4
TrackArgument, ClipArgument, ProjectOption and the note source and filter options were spelled out in full at 150 call sites across 14 modules. They now live in commands/_params.py. With the signatures shared, clip notes get/clear and arrangement clip notes get/clear each come from one filter-command factory. The help text and parameter shapes are unchanged; the command surface snapshot is byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159HyNwc4JV7ocTay3N3KL4
set_device_parameter, set_synth_parameter_safe and set_effect_parameter_safe were hand-written pass-throughs, which is exactly what CLIENT_METHOD_SPECS generates; they now come from the spec table and _call_parameter_command is gone. The clip and arrangement note-args builders differed only in the clip key and are now one _note_args. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159HyNwc4JV7ocTay3N3KL4
No test asserted the message or hint of the family error paths (unsupported device, type mismatch, unknown key, unknown type name). These pass on the current code and hold the contract for the next change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159HyNwc4JV7ocTay3N3KL4
The Remote Script carried two copies of every synth/effect step: the supported-device check, the parameter payload, the standard key resolution, seven backend methods and seven handlers. A DeviceFamily table now holds what differs (type list, canonicalizer, detector, key catalog, unsupported-device hint) and one implementation reads it. The public backend methods and handler names are unchanged. The handler factory takes each backend method as an explicit attribute so the CommandBackend parity test still sees every call. An old-vs-new run of 156 backend calls (63 of them error paths) gives byte-identical results. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159HyNwc4JV7ocTay3N3KL4
runner.py and dependencies.py each carried an identical _expand_globstar. It now lives in quality_harness/globs.py. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159HyNwc4JV7ocTay3N3KL4
The accepted debt went down: 428 baselined warnings become 416, with 0 failures. On main the live count had drifted to 447, 19 over the baseline and one short of the fail threshold for warning_delta. The new baseline records the current state so the next regression is caught from here. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159HyNwc4JV7ocTay3N3KL4
The three parameter-setter specs added earlier sat before set_clip_name; the table is documented as sorted by name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159HyNwc4JV7ocTay3N3KL4
Owner
Author
Live verification (Ableton Live 12.4.6, macOS)The PR's Remote Script ( Preflight: Synth
Effect
CLI parity: Before the Remote Script swap, I ran 14 read-only synth/effect commands from both the Afterwards I reinstalled Existing issues on
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes for you
Nothing on the command line or the wire. Command names, options, help text, JSON envelopes, exit codes and the TCP protocol are unchanged. The command surface snapshot, the public contract snapshot, the generated skill docs and the generated client all regenerate with no diff.
The work cuts duplicated code. Synth and effect behaviour now lives in one place in the CLI and one place in the Remote Script, instead of two copies that could drift apart. 43 files changed, +1759 / −3117. Quality harness warnings fall from 447 to 416 and duplicate groups from 97 to 66, with 0 failures.
Commits, in order
require_*validators that only their own tests called, and the unreadCLIENT_METHOD_SPEC_BY_NAME. Its import-time duplicate check becomes a test.devicecommands. Seven commands that take only the track and device selectors repeated the same 13-option signature. They now come from one registration factory.synth/effectcommands. The two modules were parallel copies.commands/_device_family.pybuilds both groups from aDeviceFamily.findstays in each module because its--typeparameter name (synth_type,effect_type) is part of the command surface snapshot.TrackArgument,ClipArgument,ProjectOptionand the note source and filter options were spelled out at about 150 call sites. They now live incommands/_params.py, applied by a codemod. Clip and arrangementnotes get/notes cleareach come from one filter-command factory.CLIENT_METHOD_SPECS, so the generator writes them. The clip and arrangement note-args builders become one_note_args.device_families.pyreplaces the second copy of each step: the supported-device check, the parameter payload, standard key resolution, seven backend methods and seven handlers. The handler factory passes each backend method as an explicit attribute, sotest_backend_protocol_has_no_unused_methodsstill sees every call.quality_harness/globs.pyreplaces two identical_expand_globstarcopies. The quality harness baseline is regenerated, and the client spec table is kept in name order.How it was verified
ruff check,ruff format --check, the full pytest suite (1435 passed), the quality harness with the baseline (exit 0), and the Remote Script Python 3.11 compatibility check.ableton-cli --help,--versionandpython -m buildpass. The wheel containsdevice_families.py.2b1921d:ableton_cli.cli:main, covering argument-validation failures and unreachable-Live failures. Identical JSON envelopes and exit codes.Not run: a manual check against a running Ableton Live. One
synthand oneeffectcommand on a real device is worth a minute before merging.For the reviewer
_device_family.pylooks up client methods by string template, asCommandSpec.client_methodalready does across the CLI. The Remote Script side uses explicit attributes instead, because a parity test reads them statically. The one small call-style change is thatsynth <type> keysnow passessynth_typeby keyword rather than position. The real client's parameter has that name.main. The live count there was 447 against 428 baselined. About 8 new entries come from_device_family.pyitself, from its Typer signatures.run_client_commandwrappers. Tests monkeypatchget_clienton each module, so these wrappers are how the tests inject their fakes.Generated by Claude Code