Refactor plugin bin CLIs onto Thor (ADR-0123) #422

Closed
opened 2026-08-17 13:00:35 +00:00 by jared · 2 comments
Owner

Context

bin/os-backlog is 543 lines: ~325 lines of hand-rolled case/when dispatch (219–543), a 40-line help clause, and helpers (fail_soft, cwd_tracker, require_cwd_tracker) duplicated verbatim into bin/decision-sweep; six bins repo-wide repeat the pattern, and dispatch is only exercised via subprocess CLI tests. ADR-0123 (amending ADR-0025) decides the fix: Thor-based CLIs.

Tasks

  • Extract os-backlog dispatch into a Thor subclass at lib/backlog/cli.rb with per-command lib classes; bin/os-backlog becomes a thin entrypoint (require + rescue LoadError install message + CLI.start)
  • Move shared helpers into lib; bin/decision-sweep becomes an entrypoint delegating to lib
  • Unit-test command classes directly; keep existing subprocess CLI tests green as the behavior contract
  • Normalize output JSON-first from backends; render YAML via Psych on request; never proxy raw backend bytes
  • Close-out: remaining bin migrations tracked in #423 (blocked by #423)

Acceptance criteria

  • bin/os-backlog and bin/decision-sweep contain no dispatch or business logic
  • All existing CLI subprocess tests pass unchanged
  • os-backlog help output comes from Thor, not a hand-maintained when clause
  • Missing thor gem fails with a one-line install message, exit nonzero

Evidence (code-probe, 2026-08-17)

Brief: .sdlc/tickets/422/evidence-brief.md

  • 14 commands in the case/when; most already delegate to lib/backlog/ classes; close, inspect, config-write, projects need orchestrating command classes.
  • CLI contract tests (comment_cli_test.rb, labels_cli_test.rb, issue_show_cli_test.rb, close_protocol_test.rb, issues_routing_test.rb) shell out to the literal bin/os-backlog path — preserve that path and its stdout/exit-code contract.
  • No raw tea/gh byte proxying at the dispatch layer today; output is JSON via pretty_generate/generate — the JSON-first task means moving that rendering into command classes, not new behavior.
  • No Gemfile/gemspec in the plugin; thor is a system gem, currently required nowhere — the LoadError guard in the entrypoint is the only dependency handling.

Origin

  • Trigger: user review of commits c2b23aa/ce66705 (#420/#421) surfaced the 543-line bin and bin-level duplication
  • Improvised this session: none
  • Chain: duplicated bin helpers and untestable dispatch ← hand-rolled single-file dispatcher pattern ← DESIGN (ADR-0025); superseding decision recorded as ADR-0123
  • Root candidate: this ticket

User-approved this session (skeptic gate not applicable).

VERDICT: CREATE (ticket-skeptic, 2026-08-17) — user-requested work backed by Accepted ADR-0123; root-cause fix, not symptom move.

## Context bin/os-backlog is 543 lines: ~325 lines of hand-rolled case/when dispatch (219–543), a 40-line help clause, and helpers (fail_soft, cwd_tracker, require_cwd_tracker) duplicated verbatim into bin/decision-sweep; six bins repo-wide repeat the pattern, and dispatch is only exercised via subprocess CLI tests. ADR-0123 (amending ADR-0025) decides the fix: Thor-based CLIs. ## Tasks - [ ] Extract os-backlog dispatch into a Thor subclass at lib/backlog/cli.rb with per-command lib classes; bin/os-backlog becomes a thin entrypoint (require + rescue LoadError install message + CLI.start) - [ ] Move shared helpers into lib; bin/decision-sweep becomes an entrypoint delegating to lib - [ ] Unit-test command classes directly; keep existing subprocess CLI tests green as the behavior contract - [ ] Normalize output JSON-first from backends; render YAML via Psych on request; never proxy raw backend bytes - [ ] Close-out: remaining bin migrations tracked in #423 (blocked by #423) ## Acceptance criteria - [ ] bin/os-backlog and bin/decision-sweep contain no dispatch or business logic - [ ] All existing CLI subprocess tests pass unchanged - [ ] `os-backlog help` output comes from Thor, not a hand-maintained when clause - [ ] Missing thor gem fails with a one-line install message, exit nonzero ## Evidence (code-probe, 2026-08-17) Brief: .sdlc/tickets/422/evidence-brief.md - 14 commands in the case/when; most already delegate to lib/backlog/ classes; close, inspect, config-write, projects need orchestrating command classes. - CLI contract tests (comment_cli_test.rb, labels_cli_test.rb, issue_show_cli_test.rb, close_protocol_test.rb, issues_routing_test.rb) shell out to the literal bin/os-backlog path — preserve that path and its stdout/exit-code contract. - No raw tea/gh byte proxying at the dispatch layer today; output is JSON via pretty_generate/generate — the JSON-first task means moving that rendering into command classes, not new behavior. - No Gemfile/gemspec in the plugin; thor is a system gem, currently required nowhere — the LoadError guard in the entrypoint is the only dependency handling. ## Origin - Trigger: user review of commits c2b23aa/ce66705 (#420/#421) surfaced the 543-line bin and bin-level duplication - Improvised this session: none - Chain: duplicated bin helpers and untestable dispatch ← hand-rolled single-file dispatcher pattern ← DESIGN (ADR-0025); superseding decision recorded as ADR-0123 - Root candidate: this ticket User-approved this session (skeptic gate not applicable). VERDICT: CREATE (ticket-skeptic, 2026-08-17) — user-requested work backed by Accepted ADR-0123; root-cause fix, not symptom move.
Author
Owner

Starting os-sdlc implement pipeline on branch worktree-ticket-422

Starting os-sdlc implement pipeline on branch worktree-ticket-422
Author
Owner

Resolution

Done: bin/os-backlog and bin/decision-sweep are thin Thor entrypoints; dispatch/business logic extracted to Backlog::CLI plus Close/ConfigWriteCommand/InspectCommand/ProjectsCommand/DecisionSweepCommand; shared fail_soft/cwd_tracker helpers de-duplicated into CliSupport; JSON-first rendering with --format yaml via Psych; missing-thor LoadError fails soft with a one-line install message. issue-show (#420) and positional comment body (#421) ported into the Thor CLI at merge.

Evidence: os-sdlc pipeline report .sdlc/tickets/422/briefs/018-review-to-done.md (reviewer APPROVE round 5); suite green post-merge: 217 runs, 571 assertions, 0 failures (ruby plugins/os-backlog/tests/all.rb); six pre-existing subprocess CLI contract tests pass unchanged.

Follow-ups: DecisionSweepCommand has no direct unit tests; test_issue_create_on_a_repo_tracker_skips_the_scope_gate passes vacuously (FakeRunner aborts before the assertion); class-level mutable Backlog::CLI.runner= seam could be instance-injected; os-backlog target lint debt under root .rubocop.yml (1400+ offenses, lint gate skipped by human decision)

## Resolution **Done:** bin/os-backlog and bin/decision-sweep are thin Thor entrypoints; dispatch/business logic extracted to Backlog::CLI plus Close/ConfigWriteCommand/InspectCommand/ProjectsCommand/DecisionSweepCommand; shared fail_soft/cwd_tracker helpers de-duplicated into CliSupport; JSON-first rendering with --format yaml via Psych; missing-thor LoadError fails soft with a one-line install message. issue-show (#420) and positional comment body (#421) ported into the Thor CLI at merge. **Evidence:** os-sdlc pipeline report .sdlc/tickets/422/briefs/018-review-to-done.md (reviewer APPROVE round 5); suite green post-merge: 217 runs, 571 assertions, 0 failures (ruby plugins/os-backlog/tests/all.rb); six pre-existing subprocess CLI contract tests pass unchanged. **Follow-ups:** DecisionSweepCommand has no direct unit tests; test_issue_create_on_a_repo_tracker_skips_the_scope_gate passes vacuously (FakeRunner aborts before the assertion); class-level mutable Backlog::CLI.runner= seam could be instance-injected; os-backlog target lint debt under root .rubocop.yml (1400+ offenses, lint gate skipped by human decision)
jared closed this issue 2026-08-17 14:26:48 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#422
No description provided.