Summary
Two command families duplicate their structure file-by-file, so any interface or behavior change must be repeated in every sibling:
Proposed fix
- Introduce a shared intermediate base per family (e.g.
MaintenanceCommand < Base providing memoized maintenance_mode + shared OPTIONS; a workload-iteration/wait helper for the ps_* family), keeping each command file as a thin declaration.
- Constraint to verify first: command discovery works by regex-scanning source files for
class X < ...Base (Command::Base.all_commands) — intermediate base classes must still be picked up (the pattern intends to match subclasses of any *Base; add a spec proving discovery still finds all commands, and that the new intermediate classes are NOT registered as commands).
- One PR per family.
Acceptance criteria
Priority / size / dependencies
P3. Size: M. Soft-blocked by #384 (sequence after the Command::Base extraction to avoid repeated churn in the same files; can proceed independently if #384 stalls).
Origin: automated codebase health review, 2026-07-02, against 7c96df9.
Summary
Two command families duplicate their structure file-by-file, so any interface or behavior change must be repeated in every sibling:
maintenance_on.rb(29 lines),maintenance_off.rb(29),maintenance_set_page.rb(34): identical NAME/OPTIONS scaffolding delegating to oneMaintenanceModemethod each.ps_start.rb,ps_stop.rb,ps_restart.rb,ps_wait.rb: each re-implements single-vs-all-workloads resolution and the wait/poll pattern (step+ retry + max attempts).Proposed fix
MaintenanceCommand < Baseproviding memoizedmaintenance_mode+ shared OPTIONS; a workload-iteration/wait helper for theps_*family), keeping each command file as a thin declaration.class X < ...Base(Command::Base.all_commands) — intermediate base classes must still be picked up (the pattern intends to match subclasses of any*Base; add a spec proving discovery still finds all commands, and that the new intermediate classes are NOT registered as commands).Acceptance criteria
ps_*family; maintenance scaffolding exists oncecpflow --helpoutput andcommands.md(rake check_command_docs) unchangedPriority / size / dependencies
P3. Size: M. Soft-blocked by #384 (sequence after the
Command::Baseextraction to avoid repeated churn in the same files; can proceed independently if #384 stalls).Origin: automated codebase health review, 2026-07-02, against 7c96df9.