Migrate remaining case/when bins to Thor (follow-on to #422) #423

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

Context

ADR-0123 (amending ADR-0025) moves plugin bin CLIs onto Thor. #422 converts bin/os-backlog and bin/decision-sweep as the reference implementation; this ticket migrates the remaining hand-rolled case/when bins: os-sdlc, os-sdlc-runner, os-sdlc-workspace, wakeup-poll, adr-find.

Blocked by #422 — the reference conversion establishes the entrypoint + lib/cli.rb pattern to copy.

Tasks

  • Decompose per bin when picked up (this ticket has no checklist yet by design — /os-backlog:ticket-decompose re-triggers lazily)

Acceptance criteria

  • Each listed bin is a thin entrypoint (require + LoadError install message + CLI.start) with dispatch in a Thor subclass under its plugin's lib/
  • Existing subprocess CLI tests for each bin pass unchanged

Origin

  • Trigger: decomposition of #422 (ADR-0123 adoption); the migration slice needs its own per-bin decomposition
  • Chain: same as #422 — hand-rolled dispatcher pattern ← DESIGN (ADR-0025), superseded by ADR-0123
  • Root candidate: #422
  • Ticket-skeptic verdict: inherits #422's CREATE verdict (2026-08-17); split out of an already-gated ticket
## Context ADR-0123 (amending ADR-0025) moves plugin bin CLIs onto Thor. #422 converts bin/os-backlog and bin/decision-sweep as the reference implementation; this ticket migrates the remaining hand-rolled case/when bins: os-sdlc, os-sdlc-runner, os-sdlc-workspace, wakeup-poll, adr-find. Blocked by #422 — the reference conversion establishes the entrypoint + lib/cli.rb pattern to copy. ## Tasks - [ ] Decompose per bin when picked up (this ticket has no checklist yet by design — /os-backlog:ticket-decompose re-triggers lazily) ## Acceptance criteria - [ ] Each listed bin is a thin entrypoint (require + LoadError install message + CLI.start) with dispatch in a Thor subclass under its plugin's lib/ - [ ] Existing subprocess CLI tests for each bin pass unchanged ## Origin - Trigger: decomposition of #422 (ADR-0123 adoption); the migration slice needs its own per-bin decomposition - Chain: same as #422 — hand-rolled dispatcher pattern ← DESIGN (ADR-0025), superseded by ADR-0123 - Root candidate: #422 - Ticket-skeptic verdict: inherits #422's CREATE verdict (2026-08-17); split out of an already-gated ticket
Author
Owner

#423 decomposition — Thor migration of remaining case/when bins (per ADR-0123, reference conversion #422)

Decomposed 2026-08-17 via parallel per-bin investigation agents. Decisions locked with the user:

  • Output policy: dispatch-only. No output reformatting — ADR-0123's JSON-first clause is tracker-wrapper-specific. All existing stdout formats stay byte-identical; subprocess contracts unmodified.
  • os-sdlc global --target: Thor class_option :target, with OS_SDLC_TARGET env fallback resolved in command bodies (flag wins over env), never as a Thor option default where precedence is tested.
  • Excluded from scope: lint-worklist, dead-code-sweep, dup-sweep — no case/when dispatch, outside ADR-0123's scope language.
  • Ordering: smallest-first to re-prove the pattern before the big dispatcher: 1) os-sdlc-workspace, 2) os-sdlc-runner, 3) adr-find, 4) wakeup-poll, 5) os-sdlc.
  • Cross-cutting hazard #1: exit-code fidelity. os-sdlc has a documented 0/1/2/3 contract; runner and workspace use exit 3. Thor's exit_on_failure?/error handling must never remap these to 1. Every bin's conversion carries explicit exit-code tests.
  • Cross-cutting hazard #2: thor is a new runtime dependency on every machine running these plugins. Thin bins carry the rescue LoadError → "gem install thor" guard from bin/os-backlog.
  • Existing subprocess tests are the behavior contract everywhere they exist — assertions never weakened to make Thor pass. After every source edit: bin/refresh-plugins.

# #423 decomposition — Thor migration of remaining case/when bins (per ADR-0123, reference conversion #422) Decomposed 2026-08-17 via parallel per-bin investigation agents. Decisions locked with the user: - **Output policy: dispatch-only.** No output reformatting — ADR-0123's JSON-first clause is tracker-wrapper-specific. All existing stdout formats stay byte-identical; subprocess contracts unmodified. - **os-sdlc global `--target`: Thor `class_option :target`**, with `OS_SDLC_TARGET` env fallback resolved in command bodies (flag wins over env), never as a Thor option default where precedence is tested. - **Excluded from scope:** `lint-worklist`, `dead-code-sweep`, `dup-sweep` — no case/when dispatch, outside ADR-0123's scope language. - **Ordering: smallest-first** to re-prove the pattern before the big dispatcher: 1) os-sdlc-workspace, 2) os-sdlc-runner, 3) adr-find, 4) wakeup-poll, 5) os-sdlc. - **Cross-cutting hazard #1: exit-code fidelity.** os-sdlc has a documented 0/1/2/3 contract; runner and workspace use exit 3. Thor's `exit_on_failure?`/error handling must never remap these to 1. Every bin's conversion carries explicit exit-code tests. - **Cross-cutting hazard #2: thor is a new runtime dependency** on every machine running these plugins. Thin bins carry the `rescue LoadError` → "gem install thor" guard from `bin/os-backlog`. - Existing subprocess tests are the behavior contract everywhere they exist — assertions never weakened to make Thor pass. After every source edit: `bin/refresh-plugins`. ---
Author
Owner

1. os-sdlc-workspace (plugins/os-sdlc/bin/os-sdlc-workspace)

  • Create plugins/os-sdlc/lib/os_sdlc/workspace_cli.rbOsSdlc::WorkspaceCLI < Thor, mirroring plugins/os-backlog/lib/backlog/cli.rb (exit_on_failure?, self.start override with rescue).
  • Rewrite the bin as a thin entrypoint: require_relative "../lib/os_sdlc", thor-guarded require of the CLI, OsSdlc::WorkspaceCLI.start(ARGV).
  • Move inline TextIssueSource into lib/os_sdlc/text_issue_source.rb.
  • Move load_or_bootstrap_project(command, target) into the CLI as a private method; keep the bootstrap-only-on-setup guard exactly.
  • setup <ticket>: method_option :ticket_text, :ticket_file, :target (env fallback OS_SDLC_TARGET); preserve the if/elsif issue_source chain, Workspace.for, puts workspace.setup.
  • teardown <ticket>: method_option :force, type: :boolean, default: false; tear_down_without_check vs tear_down per --force.
  • Preserve rescue OsSdlc::HarnessError → warn os-sdlc-workspace: <msg> + exit 3 around both command bodies (or in self.start).
  • Do NOT add a shell-runner seam — none exists today; direct construction stays.
  • Behavior contract (unmodified): tests/os_sdlc_workspace_bin_test.rb (+ tests/support/multi_target_repo_scenario.rb fixture). Dirty-worktree refusal test is the sharpest regression signal.
  • New direct unit tests for WorkspaceCLI: setup with --ticket-text/--ticket-file/neither/--target; teardown ±--force; HarnessError→exit-3 in-process.
  • Verify exit codes end-to-end: no-tracker setup → 3 (stderr matches /tracker/); check whether bare invocation needs the os-backlog "exit 1" override.

2. os-sdlc-runner (plugins/os-sdlc/bin/os-sdlc-runner)

  • Create plugins/os-sdlc/lib/os_sdlc/runner/cli.rbOsSdlc::Runner::CLI < Thor, top-level StandardError rescue in self.start preserving the exact os-sdlc-runner: harness error: <class>: <msg> + exit 3 format.
  • Move build_engine, resolved_target, emit, extract_flag, the validated_* helpers, recover_action into the CLI as private methods.
  • intake <ticket>: options :map, :target (explicit flag wins over OS_SDLC_TARGET env — precedence tested by cli_target_argument_test.rb; resolve in body, not option default).
  • resume <ticket>: :action required (retry|retry-with-guidance|skip|abort, dash→underscore symbol conversion preserved), :note, :target.
  • recover (no positional): booleans :rollback, :reemit, plus :target; preserve recover_action selection behavior exactly.
  • Exit-code 3 on missing ticket id / bad --action — keep explicit warn + exit 3 in command bodies; never let Thor remap to 1.
  • Thin bin: keep $LOAD_PATH.unshift + require "os_sdlc"; must remain load-able (no __FILE__ == $0 guard) for adapter_wiring_test.rb's in-process load BIN driver.
  • emit keeps puts JSON.generate(result); exit 0.
  • Behavior contract (unmodified): tests/runner/cli_map_argument_test.rb, cli_target_argument_test.rb, cli_resume_argument_test.rb, cli_recover_argument_test.rb, adapter_wiring_test.rb.
  • New direct unit tests: dispatch with stubbed EngineFactory, bad --action, missing ticket id, --target vs env precedence, StandardError→exit-3.
  • Confirm recover's boolean options don't gain conflicting --no-* negations vs test expectations.

3. adr-find (plugins/os-adr/bin/adr-find)

  • Create plugins/os-adr/lib/adr/cli.rbAdr::CLI < Thor with a find command.
  • Options: :root (default Dir.pwd), :paths, :components — keep comma-string + manual .split(',') (NOT Thor type: :array, which is space-split) so the invocation in skills/find/SKILL.md stays byte-identical; :"all-statuses" boolean.
  • Move the Repository/Finder/JSON.pretty_generate body verbatim; Adr::Finder/Adr::Repository untouched.
  • Thin bin at the same path; thor LoadError guard.
  • Output purity: stdout must remain JSON-only on the success path ({"candidates": [...]} via pretty_generate) — it feeds the /os-adr:find skill's judgment layer directly. Verify no Thor banner leakage.
  • Scope: this bin ONLY. adr-new/adr-init/adr-migrate/adr-detect are grandfathered (ADR-0025; ADR-0123 affected-paths names adr-find singular).
  • No existing bin-level tests — new direct unit tests are the safety net: default root, --paths, --components, --all-statuses, empty-results shape, registry-driven help. Register in tests/all.rb if not auto-globbed.
  • Regression: tests/finder_test.rb passes unmodified; manually confirm output byte-compat with the documented skill invocation.
  • Check Thor's unknown-option exit behavior doesn't change what the skill interprets as failure.

4. wakeup-poll (plugins/os-backlog/bin/wakeup-poll)

  • Standalone Thor CLI (Backlog::WakeupCLI in lib/backlog/wakeup_cli.rb) — NOT folded into Backlog::CLI (ADR-0025 exemption, ADR-0034/35/36 pilot; converting internals is in scope, merging is not).
  • Move inline procedural logic (list_issues_cmd, label_names, normalize_labels, normalize_issue_row, list_issues, eligibility/spawn loop) into the CLI or a Backlog::WakeupRun orchestration class; Backlog::Wakeup (pure, tested) stays untouched and Thor-unaware.
  • Single default poll command; method_option :spawn, type: :boolean, default: false.
  • Add an injectable runner seam for the Open3.capture3 tea/gh shell-out (parallel to Backlog::CLI.runner) — required for unit tests.
  • Thin bin matching bin/os-backlog pattern.
  • Keep plain-text note(...) output (dispatch-only policy); document the deviation inline.
  • Preserve exactly: exit 0 on empty index / no eligible projects; degrade-never-raise on missing tea/gh login and JSON parse errors.
  • Highest-severity risk: State#record + summary append gated on --spawn only. Dry-run must print "would run"/"would append" and touch nothing. Test both sides.
  • No existing bin-level tests — new in-process unit tests: --spawn parsing/default, dry-run no-mutation, spawn-mode state write + summary append, first-scan baselining without waking, degrade-on-failed-listing, gh-vs-tea row normalization. tests/wakeup_test.rb passes unchanged.
  • Confirm no wrapper/cron depends on the old loose ARGV.include?("--spawn") parsing (header says no cron until ADR-0035 Accepted — likely none).
  • Update the ADR-0025 exemption note in plugins/os-backlog/CLAUDE.md if wording goes stale; one-row History entry in docs/implementation-status/os-backlog.md.

5. os-sdlc (plugins/os-sdlc/bin/os-sdlc) — largest, last

  • Create plugins/os-sdlc/lib/os_sdlc/cli.rbOsSdlc::CLI < Thor.
  • Thin bin: $LOAD_PATH setup, require "os_sdlc", thor-guarded CLI require, CLI.start(ARGV).
  • Extract heavy top-level helpers into per-command classes under lib/os_sdlc/ (GateCommand, AcLintCommand, etc., following #422's InspectCommand split); CLI methods stay thin.
  • Global --target: Thor class_option :target (decision locked); load_project/SELECTED_TARGET move from load-time module side effect into command execution. Confirm nothing reads a pre-set top-level SELECTED_TARGET.
  • Map all subcommands (dashed names via desc + map per the Backlog::CLI convention): intake, red-assert, green-assert (two Thor commands sharing a private gate helper), ac-lint, verdict-assert, record-verdict, lint, lint-init, project-config (bare --show becomes an option), preflight, review-packet, shard-plan, workspace-housekeeping, autocorrect, agent-budget.
  • shard-plan / workspace-housekeeping pass raw ARGV to lib classes that self-parse — verify and likely keep passthrough shape rather than Thor options; explicit check, not assumption.
  • Convert each *_OPTION_SPECS/*_DEFAULTS OptionParser pair to method_option declarations; verify --no-lint boolean negation behaves under Thor's --no- convention.
  • Preserve positional args: intake <ticket>, lint <run_id>, project-config <name>, preflight <ticket_path>, with existing fail_soft-style validation.
  • Exit-code contract 0/1/2/3 (header comment) survives verbatim: gate pass/fail 0/1, escalation 2, harness/misconfig 3; outer rescue StandardErroros-sdlc: harness error: ... + exit 3 in self.start. Representative unit test per code.
  • No output reformatting (dispatch-only policy) — agent-budget/autocorrect keep JSON, lint/preflight/review-packet/project-config --show keep plain text.
  • Behavior contract (unmodified): tests/cli_test.rb, cli_intake_test.rb, hardening_preflight_review_packet_test.rb, lint_test.rb, lint_worklist_target_test.rb, agent_budget_test.rb, autocorrect_prepass_test.rb, cops/bin_script_load_in_test_test.rb (check it doesn't assert the old case/when shape), via tests/support/cli_shared_helpers.rb's BIN harness.
  • New direct unit tests for branchy commands (ac_lint, record_verdict, project_config, verdict_assert) and the chosen --target mechanism.
## 1. os-sdlc-workspace (plugins/os-sdlc/bin/os-sdlc-workspace) - [ ] Create `plugins/os-sdlc/lib/os_sdlc/workspace_cli.rb` — `OsSdlc::WorkspaceCLI < Thor`, mirroring `plugins/os-backlog/lib/backlog/cli.rb` (`exit_on_failure?`, `self.start` override with rescue). - [ ] Rewrite the bin as a thin entrypoint: `require_relative "../lib/os_sdlc"`, thor-guarded require of the CLI, `OsSdlc::WorkspaceCLI.start(ARGV)`. - [ ] Move inline `TextIssueSource` into `lib/os_sdlc/text_issue_source.rb`. - [ ] Move `load_or_bootstrap_project(command, target)` into the CLI as a private method; keep the bootstrap-only-on-`setup` guard exactly. - [ ] `setup <ticket>`: `method_option :ticket_text`, `:ticket_file`, `:target` (env fallback `OS_SDLC_TARGET`); preserve the if/elsif issue_source chain, `Workspace.for`, `puts workspace.setup`. - [ ] `teardown <ticket>`: `method_option :force, type: :boolean, default: false`; `tear_down_without_check` vs `tear_down` per `--force`. - [ ] Preserve `rescue OsSdlc::HarnessError` → warn `os-sdlc-workspace: <msg>` + exit 3 around both command bodies (or in `self.start`). - [ ] Do NOT add a shell-runner seam — none exists today; direct construction stays. - [ ] Behavior contract (unmodified): `tests/os_sdlc_workspace_bin_test.rb` (+ `tests/support/multi_target_repo_scenario.rb` fixture). Dirty-worktree refusal test is the sharpest regression signal. - [ ] New direct unit tests for `WorkspaceCLI`: setup with `--ticket-text`/`--ticket-file`/neither/`--target`; teardown ±`--force`; HarnessError→exit-3 in-process. - [ ] Verify exit codes end-to-end: no-tracker setup → 3 (stderr matches /tracker/); check whether bare invocation needs the os-backlog "exit 1" override. ## 2. os-sdlc-runner (plugins/os-sdlc/bin/os-sdlc-runner) - [ ] Create `plugins/os-sdlc/lib/os_sdlc/runner/cli.rb` — `OsSdlc::Runner::CLI < Thor`, top-level StandardError rescue in `self.start` preserving the exact `os-sdlc-runner: harness error: <class>: <msg>` + exit 3 format. - [ ] Move `build_engine`, `resolved_target`, `emit`, `extract_flag`, the `validated_*` helpers, `recover_action` into the CLI as private methods. - [ ] `intake <ticket>`: options `:map`, `:target` (explicit flag wins over `OS_SDLC_TARGET` env — precedence tested by `cli_target_argument_test.rb`; resolve in body, not option default). - [ ] `resume <ticket>`: `:action` required (`retry|retry-with-guidance|skip|abort`, dash→underscore symbol conversion preserved), `:note`, `:target`. - [ ] `recover` (no positional): booleans `:rollback`, `:reemit`, plus `:target`; preserve `recover_action` selection behavior exactly. - [ ] Exit-code 3 on missing ticket id / bad `--action` — keep explicit `warn` + `exit 3` in command bodies; never let Thor remap to 1. - [ ] Thin bin: keep `$LOAD_PATH.unshift` + `require "os_sdlc"`; must remain `load`-able (no `__FILE__ == $0` guard) for `adapter_wiring_test.rb`'s in-process `load BIN` driver. - [ ] `emit` keeps `puts JSON.generate(result); exit 0`. - [ ] Behavior contract (unmodified): `tests/runner/cli_map_argument_test.rb`, `cli_target_argument_test.rb`, `cli_resume_argument_test.rb`, `cli_recover_argument_test.rb`, `adapter_wiring_test.rb`. - [ ] New direct unit tests: dispatch with stubbed `EngineFactory`, bad `--action`, missing ticket id, `--target` vs env precedence, StandardError→exit-3. - [ ] Confirm `recover`'s boolean options don't gain conflicting `--no-*` negations vs test expectations. ## 3. adr-find (plugins/os-adr/bin/adr-find) - [ ] Create `plugins/os-adr/lib/adr/cli.rb` — `Adr::CLI < Thor` with a `find` command. - [ ] Options: `:root` (default `Dir.pwd`), `:paths`, `:components` — keep comma-string + manual `.split(',')` (NOT Thor `type: :array`, which is space-split) so the invocation in `skills/find/SKILL.md` stays byte-identical; `:"all-statuses"` boolean. - [ ] Move the `Repository`/`Finder`/`JSON.pretty_generate` body verbatim; `Adr::Finder`/`Adr::Repository` untouched. - [ ] Thin bin at the same path; thor LoadError guard. - [ ] Output purity: stdout must remain JSON-only on the success path (`{"candidates": [...]}` via pretty_generate) — it feeds the `/os-adr:find` skill's judgment layer directly. Verify no Thor banner leakage. - [ ] Scope: this bin ONLY. `adr-new`/`adr-init`/`adr-migrate`/`adr-detect` are grandfathered (ADR-0025; ADR-0123 affected-paths names adr-find singular). - [ ] No existing bin-level tests — new direct unit tests are the safety net: default root, `--paths`, `--components`, `--all-statuses`, empty-results shape, registry-driven help. Register in `tests/all.rb` if not auto-globbed. - [ ] Regression: `tests/finder_test.rb` passes unmodified; manually confirm output byte-compat with the documented skill invocation. - [ ] Check Thor's unknown-option exit behavior doesn't change what the skill interprets as failure. ## 4. wakeup-poll (plugins/os-backlog/bin/wakeup-poll) - [ ] Standalone Thor CLI (`Backlog::WakeupCLI` in `lib/backlog/wakeup_cli.rb`) — NOT folded into `Backlog::CLI` (ADR-0025 exemption, ADR-0034/35/36 pilot; converting internals is in scope, merging is not). - [ ] Move inline procedural logic (`list_issues_cmd`, `label_names`, `normalize_labels`, `normalize_issue_row`, `list_issues`, eligibility/spawn loop) into the CLI or a `Backlog::WakeupRun` orchestration class; `Backlog::Wakeup` (pure, tested) stays untouched and Thor-unaware. - [ ] Single default `poll` command; `method_option :spawn, type: :boolean, default: false`. - [ ] Add an injectable runner seam for the `Open3.capture3` tea/gh shell-out (parallel to `Backlog::CLI.runner`) — required for unit tests. - [ ] Thin bin matching `bin/os-backlog` pattern. - [ ] Keep plain-text `note(...)` output (dispatch-only policy); document the deviation inline. - [ ] Preserve exactly: exit 0 on empty index / no eligible projects; degrade-never-raise on missing tea/gh login and JSON parse errors. - [ ] Highest-severity risk: `State#record` + summary append gated on `--spawn` only. Dry-run must print "would run"/"would append" and touch nothing. Test both sides. - [ ] No existing bin-level tests — new in-process unit tests: `--spawn` parsing/default, dry-run no-mutation, spawn-mode state write + summary append, first-scan baselining without waking, degrade-on-failed-listing, gh-vs-tea row normalization. `tests/wakeup_test.rb` passes unchanged. - [ ] Confirm no wrapper/cron depends on the old loose `ARGV.include?("--spawn")` parsing (header says no cron until ADR-0035 Accepted — likely none). - [ ] Update the ADR-0025 exemption note in `plugins/os-backlog/CLAUDE.md` if wording goes stale; one-row History entry in `docs/implementation-status/os-backlog.md`. ## 5. os-sdlc (plugins/os-sdlc/bin/os-sdlc) — largest, last - [ ] Create `plugins/os-sdlc/lib/os_sdlc/cli.rb` — `OsSdlc::CLI < Thor`. - [ ] Thin bin: `$LOAD_PATH` setup, `require "os_sdlc"`, thor-guarded CLI require, `CLI.start(ARGV)`. - [ ] Extract heavy top-level helpers into per-command classes under `lib/os_sdlc/` (`GateCommand`, `AcLintCommand`, etc., following #422's `InspectCommand` split); CLI methods stay thin. - [ ] Global `--target`: Thor `class_option :target` (decision locked); `load_project`/`SELECTED_TARGET` move from load-time module side effect into command execution. Confirm nothing reads a pre-set top-level `SELECTED_TARGET`. - [ ] Map all subcommands (dashed names via `desc` + `map` per the `Backlog::CLI` convention): `intake`, `red-assert`, `green-assert` (two Thor commands sharing a private gate helper), `ac-lint`, `verdict-assert`, `record-verdict`, `lint`, `lint-init`, `project-config` (bare `--show` becomes an option), `preflight`, `review-packet`, `shard-plan`, `workspace-housekeeping`, `autocorrect`, `agent-budget`. - [ ] `shard-plan` / `workspace-housekeeping` pass raw ARGV to lib classes that self-parse — verify and likely keep passthrough shape rather than Thor options; explicit check, not assumption. - [ ] Convert each `*_OPTION_SPECS`/`*_DEFAULTS` OptionParser pair to `method_option` declarations; verify `--no-lint` boolean negation behaves under Thor's `--no-` convention. - [ ] Preserve positional args: `intake <ticket>`, `lint <run_id>`, `project-config <name>`, `preflight <ticket_path>`, with existing fail_soft-style validation. - [ ] Exit-code contract 0/1/2/3 (header comment) survives verbatim: gate pass/fail 0/1, escalation 2, harness/misconfig 3; outer `rescue StandardError` → `os-sdlc: harness error: ...` + exit 3 in `self.start`. Representative unit test per code. - [ ] No output reformatting (dispatch-only policy) — `agent-budget`/`autocorrect` keep JSON, `lint`/`preflight`/`review-packet`/`project-config --show` keep plain text. - [ ] Behavior contract (unmodified): `tests/cli_test.rb`, `cli_intake_test.rb`, `hardening_preflight_review_packet_test.rb`, `lint_test.rb`, `lint_worklist_target_test.rb`, `agent_budget_test.rb`, `autocorrect_prepass_test.rb`, `cops/bin_script_load_in_test_test.rb` (check it doesn't assert the old case/when shape), via `tests/support/cli_shared_helpers.rb`'s `BIN` harness. - [ ] New direct unit tests for branchy commands (`ac_lint`, `record_verdict`, `project_config`, `verdict_assert`) and the chosen `--target` mechanism.
Author
Owner

#423 decomposition — Thor migration of remaining case/when bins (per ADR-0123, reference conversion #422)

Decomposed 2026-08-17 via parallel per-bin investigation agents. Decisions locked with the user:

  • Output policy: dispatch-only. No output reformatting — ADR-0123's JSON-first clause is tracker-wrapper-specific. All existing stdout formats stay byte-identical; subprocess contracts unmodified.
  • os-sdlc global --target: Thor class_option :target, with OS_SDLC_TARGET env fallback resolved in command bodies (flag wins over env), never as a Thor option default where precedence is tested.
  • Excluded from scope: lint-worklist, dead-code-sweep, dup-sweep — no case/when dispatch, outside ADR-0123's scope language.
  • Ordering: smallest-first to re-prove the pattern before the big dispatcher: 1) os-sdlc-workspace, 2) os-sdlc-runner, 3) adr-find, 4) wakeup-poll, 5) os-sdlc.
  • Cross-cutting hazard #1: exit-code fidelity. os-sdlc has a documented 0/1/2/3 contract; runner and workspace use exit 3. Thor's exit_on_failure?/error handling must never remap these to 1. Every bin's conversion carries explicit exit-code tests.
  • Cross-cutting hazard #2: thor is a new runtime dependency on every machine running these plugins. Thin bins carry the rescue LoadError → "gem install thor" guard from bin/os-backlog.
  • Existing subprocess tests are the behavior contract everywhere they exist — assertions never weakened to make Thor pass. After every source edit: bin/refresh-plugins.

# #423 decomposition — Thor migration of remaining case/when bins (per ADR-0123, reference conversion #422) Decomposed 2026-08-17 via parallel per-bin investigation agents. Decisions locked with the user: - **Output policy: dispatch-only.** No output reformatting — ADR-0123's JSON-first clause is tracker-wrapper-specific. All existing stdout formats stay byte-identical; subprocess contracts unmodified. - **os-sdlc global `--target`: Thor `class_option :target`**, with `OS_SDLC_TARGET` env fallback resolved in command bodies (flag wins over env), never as a Thor option default where precedence is tested. - **Excluded from scope:** `lint-worklist`, `dead-code-sweep`, `dup-sweep` — no case/when dispatch, outside ADR-0123's scope language. - **Ordering: smallest-first** to re-prove the pattern before the big dispatcher: 1) os-sdlc-workspace, 2) os-sdlc-runner, 3) adr-find, 4) wakeup-poll, 5) os-sdlc. - **Cross-cutting hazard #1: exit-code fidelity.** os-sdlc has a documented 0/1/2/3 contract; runner and workspace use exit 3. Thor's `exit_on_failure?`/error handling must never remap these to 1. Every bin's conversion carries explicit exit-code tests. - **Cross-cutting hazard #2: thor is a new runtime dependency** on every machine running these plugins. Thin bins carry the `rescue LoadError` → "gem install thor" guard from `bin/os-backlog`. - Existing subprocess tests are the behavior contract everywhere they exist — assertions never weakened to make Thor pass. After every source edit: `bin/refresh-plugins`. ---
Author
Owner

1. os-sdlc-workspace (plugins/os-sdlc/bin/os-sdlc-workspace)

  • Create plugins/os-sdlc/lib/os_sdlc/workspace_cli.rbOsSdlc::WorkspaceCLI < Thor, mirroring plugins/os-backlog/lib/backlog/cli.rb (exit_on_failure?, self.start override with rescue).
  • Rewrite the bin as a thin entrypoint: require_relative "../lib/os_sdlc", thor-guarded require of the CLI, OsSdlc::WorkspaceCLI.start(ARGV).
  • Move inline TextIssueSource into lib/os_sdlc/text_issue_source.rb.
  • Move load_or_bootstrap_project(command, target) into the CLI as a private method; keep the bootstrap-only-on-setup guard exactly.
  • setup <ticket>: method_option :ticket_text, :ticket_file, :target (env fallback OS_SDLC_TARGET); preserve the if/elsif issue_source chain, Workspace.for, puts workspace.setup.
  • teardown <ticket>: method_option :force, type: :boolean, default: false; tear_down_without_check vs tear_down per --force.
  • Preserve rescue OsSdlc::HarnessError → warn os-sdlc-workspace: <msg> + exit 3 around both command bodies (or in self.start).
  • Do NOT add a shell-runner seam — none exists today; direct construction stays.
  • Behavior contract (unmodified): tests/os_sdlc_workspace_bin_test.rb (+ tests/support/multi_target_repo_scenario.rb fixture). Dirty-worktree refusal test is the sharpest regression signal.
  • New direct unit tests for WorkspaceCLI: setup with --ticket-text/--ticket-file/neither/--target; teardown ±--force; HarnessError→exit-3 in-process.
  • Verify exit codes end-to-end: no-tracker setup → 3 (stderr matches /tracker/); check whether bare invocation needs the os-backlog "exit 1" override.

2. os-sdlc-runner (plugins/os-sdlc/bin/os-sdlc-runner)

  • Create plugins/os-sdlc/lib/os_sdlc/runner/cli.rbOsSdlc::Runner::CLI < Thor, top-level StandardError rescue in self.start preserving the exact os-sdlc-runner: harness error: <class>: <msg> + exit 3 format.
  • Move build_engine, resolved_target, emit, extract_flag, the validated_* helpers, recover_action into the CLI as private methods.
  • intake <ticket>: options :map, :target (explicit flag wins over OS_SDLC_TARGET env — precedence tested by cli_target_argument_test.rb; resolve in body, not option default).
  • resume <ticket>: :action required (retry|retry-with-guidance|skip|abort, dash→underscore symbol conversion preserved), :note, :target.
  • recover (no positional): booleans :rollback, :reemit, plus :target; preserve recover_action selection behavior exactly.
  • Exit-code 3 on missing ticket id / bad --action — keep explicit warn + exit 3 in command bodies; never let Thor remap to 1.
  • Thin bin: keep $LOAD_PATH.unshift + require "os_sdlc"; must remain load-able (no __FILE__ == $0 guard) for adapter_wiring_test.rb's in-process load BIN driver.
  • emit keeps puts JSON.generate(result); exit 0.
  • Behavior contract (unmodified): tests/runner/cli_map_argument_test.rb, cli_target_argument_test.rb, cli_resume_argument_test.rb, cli_recover_argument_test.rb, adapter_wiring_test.rb.
  • New direct unit tests: dispatch with stubbed EngineFactory, bad --action, missing ticket id, --target vs env precedence, StandardError→exit-3.
  • Confirm recover's boolean options don't gain conflicting --no-* negations vs test expectations.

3. adr-find (plugins/os-adr/bin/adr-find)

  • Create plugins/os-adr/lib/adr/cli.rbAdr::CLI < Thor with a find command.
  • Options: :root (default Dir.pwd), :paths, :components — keep comma-string + manual .split(',') (NOT Thor type: :array, which is space-split) so the invocation in skills/find/SKILL.md stays byte-identical; :"all-statuses" boolean.
  • Move the Repository/Finder/JSON.pretty_generate body verbatim; Adr::Finder/Adr::Repository untouched.
  • Thin bin at the same path; thor LoadError guard.
  • Output purity: stdout must remain JSON-only on the success path ({"candidates": [...]} via pretty_generate) — it feeds the /os-adr:find skill's judgment layer directly. Verify no Thor banner leakage.
  • Scope: this bin ONLY. adr-new/adr-init/adr-migrate/adr-detect are grandfathered (ADR-0025; ADR-0123 affected-paths names adr-find singular).
  • No existing bin-level tests — new direct unit tests are the safety net: default root, --paths, --components, --all-statuses, empty-results shape, registry-driven help. Register in tests/all.rb if not auto-globbed.
  • Regression: tests/finder_test.rb passes unmodified; manually confirm output byte-compat with the documented skill invocation.
  • Check Thor's unknown-option exit behavior doesn't change what the skill interprets as failure.

4. wakeup-poll (plugins/os-backlog/bin/wakeup-poll)

  • Standalone Thor CLI (Backlog::WakeupCLI in lib/backlog/wakeup_cli.rb) — NOT folded into Backlog::CLI (ADR-0025 exemption, ADR-0034/35/36 pilot; converting internals is in scope, merging is not).
  • Move inline procedural logic (list_issues_cmd, label_names, normalize_labels, normalize_issue_row, list_issues, eligibility/spawn loop) into the CLI or a Backlog::WakeupRun orchestration class; Backlog::Wakeup (pure, tested) stays untouched and Thor-unaware.
  • Single default poll command; method_option :spawn, type: :boolean, default: false.
  • Add an injectable runner seam for the Open3.capture3 tea/gh shell-out (parallel to Backlog::CLI.runner) — required for unit tests.
  • Thin bin matching bin/os-backlog pattern.
  • Keep plain-text note(...) output (dispatch-only policy); document the deviation inline.
  • Preserve exactly: exit 0 on empty index / no eligible projects; degrade-never-raise on missing tea/gh login and JSON parse errors.
  • Highest-severity risk: State#record + summary append gated on --spawn only. Dry-run must print "would run"/"would append" and touch nothing. Test both sides.
  • No existing bin-level tests — new in-process unit tests: --spawn parsing/default, dry-run no-mutation, spawn-mode state write + summary append, first-scan baselining without waking, degrade-on-failed-listing, gh-vs-tea row normalization. tests/wakeup_test.rb passes unchanged.
  • Confirm no wrapper/cron depends on the old loose ARGV.include?("--spawn") parsing (header says no cron until ADR-0035 Accepted — likely none).
  • Update the ADR-0025 exemption note in plugins/os-backlog/CLAUDE.md if wording goes stale; one-row History entry in docs/implementation-status/os-backlog.md.

5. os-sdlc (plugins/os-sdlc/bin/os-sdlc) — largest, last

  • Create plugins/os-sdlc/lib/os_sdlc/cli.rbOsSdlc::CLI < Thor.
  • Thin bin: $LOAD_PATH setup, require "os_sdlc", thor-guarded CLI require, CLI.start(ARGV).
  • Extract heavy top-level helpers into per-command classes under lib/os_sdlc/ (GateCommand, AcLintCommand, etc., following #422's InspectCommand split); CLI methods stay thin.
  • Global --target: Thor class_option :target (decision locked); load_project/SELECTED_TARGET move from load-time module side effect into command execution. Confirm nothing reads a pre-set top-level SELECTED_TARGET.
  • Map all subcommands (dashed names via desc + map per the Backlog::CLI convention): intake, red-assert, green-assert (two Thor commands sharing a private gate helper), ac-lint, verdict-assert, record-verdict, lint, lint-init, project-config (bare --show becomes an option), preflight, review-packet, shard-plan, workspace-housekeeping, autocorrect, agent-budget.
  • shard-plan / workspace-housekeeping pass raw ARGV to lib classes that self-parse — verify and likely keep passthrough shape rather than Thor options; explicit check, not assumption.
  • Convert each *_OPTION_SPECS/*_DEFAULTS OptionParser pair to method_option declarations; verify --no-lint boolean negation behaves under Thor's --no- convention.
  • Preserve positional args: intake <ticket>, lint <run_id>, project-config <name>, preflight <ticket_path>, with existing fail_soft-style validation.
  • Exit-code contract 0/1/2/3 (header comment) survives verbatim: gate pass/fail 0/1, escalation 2, harness/misconfig 3; outer rescue StandardErroros-sdlc: harness error: ... + exit 3 in self.start. Representative unit test per code.
  • No output reformatting (dispatch-only policy) — agent-budget/autocorrect keep JSON, lint/preflight/review-packet/project-config --show keep plain text.
  • Behavior contract (unmodified): tests/cli_test.rb, cli_intake_test.rb, hardening_preflight_review_packet_test.rb, lint_test.rb, lint_worklist_target_test.rb, agent_budget_test.rb, autocorrect_prepass_test.rb, cops/bin_script_load_in_test_test.rb (check it doesn't assert the old case/when shape), via tests/support/cli_shared_helpers.rb's BIN harness.
  • New direct unit tests for branchy commands (ac_lint, record_verdict, project_config, verdict_assert) and the chosen --target mechanism.
## 1. os-sdlc-workspace (plugins/os-sdlc/bin/os-sdlc-workspace) - [ ] Create `plugins/os-sdlc/lib/os_sdlc/workspace_cli.rb` — `OsSdlc::WorkspaceCLI < Thor`, mirroring `plugins/os-backlog/lib/backlog/cli.rb` (`exit_on_failure?`, `self.start` override with rescue). - [ ] Rewrite the bin as a thin entrypoint: `require_relative "../lib/os_sdlc"`, thor-guarded require of the CLI, `OsSdlc::WorkspaceCLI.start(ARGV)`. - [ ] Move inline `TextIssueSource` into `lib/os_sdlc/text_issue_source.rb`. - [ ] Move `load_or_bootstrap_project(command, target)` into the CLI as a private method; keep the bootstrap-only-on-`setup` guard exactly. - [ ] `setup <ticket>`: `method_option :ticket_text`, `:ticket_file`, `:target` (env fallback `OS_SDLC_TARGET`); preserve the if/elsif issue_source chain, `Workspace.for`, `puts workspace.setup`. - [ ] `teardown <ticket>`: `method_option :force, type: :boolean, default: false`; `tear_down_without_check` vs `tear_down` per `--force`. - [ ] Preserve `rescue OsSdlc::HarnessError` → warn `os-sdlc-workspace: <msg>` + exit 3 around both command bodies (or in `self.start`). - [ ] Do NOT add a shell-runner seam — none exists today; direct construction stays. - [ ] Behavior contract (unmodified): `tests/os_sdlc_workspace_bin_test.rb` (+ `tests/support/multi_target_repo_scenario.rb` fixture). Dirty-worktree refusal test is the sharpest regression signal. - [ ] New direct unit tests for `WorkspaceCLI`: setup with `--ticket-text`/`--ticket-file`/neither/`--target`; teardown ±`--force`; HarnessError→exit-3 in-process. - [ ] Verify exit codes end-to-end: no-tracker setup → 3 (stderr matches /tracker/); check whether bare invocation needs the os-backlog "exit 1" override. ## 2. os-sdlc-runner (plugins/os-sdlc/bin/os-sdlc-runner) - [ ] Create `plugins/os-sdlc/lib/os_sdlc/runner/cli.rb` — `OsSdlc::Runner::CLI < Thor`, top-level StandardError rescue in `self.start` preserving the exact `os-sdlc-runner: harness error: <class>: <msg>` + exit 3 format. - [ ] Move `build_engine`, `resolved_target`, `emit`, `extract_flag`, the `validated_*` helpers, `recover_action` into the CLI as private methods. - [ ] `intake <ticket>`: options `:map`, `:target` (explicit flag wins over `OS_SDLC_TARGET` env — precedence tested by `cli_target_argument_test.rb`; resolve in body, not option default). - [ ] `resume <ticket>`: `:action` required (`retry|retry-with-guidance|skip|abort`, dash→underscore symbol conversion preserved), `:note`, `:target`. - [ ] `recover` (no positional): booleans `:rollback`, `:reemit`, plus `:target`; preserve `recover_action` selection behavior exactly. - [ ] Exit-code 3 on missing ticket id / bad `--action` — keep explicit `warn` + `exit 3` in command bodies; never let Thor remap to 1. - [ ] Thin bin: keep `$LOAD_PATH.unshift` + `require "os_sdlc"`; must remain `load`-able (no `__FILE__ == $0` guard) for `adapter_wiring_test.rb`'s in-process `load BIN` driver. - [ ] `emit` keeps `puts JSON.generate(result); exit 0`. - [ ] Behavior contract (unmodified): `tests/runner/cli_map_argument_test.rb`, `cli_target_argument_test.rb`, `cli_resume_argument_test.rb`, `cli_recover_argument_test.rb`, `adapter_wiring_test.rb`. - [ ] New direct unit tests: dispatch with stubbed `EngineFactory`, bad `--action`, missing ticket id, `--target` vs env precedence, StandardError→exit-3. - [ ] Confirm `recover`'s boolean options don't gain conflicting `--no-*` negations vs test expectations. ## 3. adr-find (plugins/os-adr/bin/adr-find) - [ ] Create `plugins/os-adr/lib/adr/cli.rb` — `Adr::CLI < Thor` with a `find` command. - [ ] Options: `:root` (default `Dir.pwd`), `:paths`, `:components` — keep comma-string + manual `.split(',')` (NOT Thor `type: :array`, which is space-split) so the invocation in `skills/find/SKILL.md` stays byte-identical; `:"all-statuses"` boolean. - [ ] Move the `Repository`/`Finder`/`JSON.pretty_generate` body verbatim; `Adr::Finder`/`Adr::Repository` untouched. - [ ] Thin bin at the same path; thor LoadError guard. - [ ] Output purity: stdout must remain JSON-only on the success path (`{"candidates": [...]}` via pretty_generate) — it feeds the `/os-adr:find` skill's judgment layer directly. Verify no Thor banner leakage. - [ ] Scope: this bin ONLY. `adr-new`/`adr-init`/`adr-migrate`/`adr-detect` are grandfathered (ADR-0025; ADR-0123 affected-paths names adr-find singular). - [ ] No existing bin-level tests — new direct unit tests are the safety net: default root, `--paths`, `--components`, `--all-statuses`, empty-results shape, registry-driven help. Register in `tests/all.rb` if not auto-globbed. - [ ] Regression: `tests/finder_test.rb` passes unmodified; manually confirm output byte-compat with the documented skill invocation. - [ ] Check Thor's unknown-option exit behavior doesn't change what the skill interprets as failure. ## 4. wakeup-poll (plugins/os-backlog/bin/wakeup-poll) - [ ] Standalone Thor CLI (`Backlog::WakeupCLI` in `lib/backlog/wakeup_cli.rb`) — NOT folded into `Backlog::CLI` (ADR-0025 exemption, ADR-0034/35/36 pilot; converting internals is in scope, merging is not). - [ ] Move inline procedural logic (`list_issues_cmd`, `label_names`, `normalize_labels`, `normalize_issue_row`, `list_issues`, eligibility/spawn loop) into the CLI or a `Backlog::WakeupRun` orchestration class; `Backlog::Wakeup` (pure, tested) stays untouched and Thor-unaware. - [ ] Single default `poll` command; `method_option :spawn, type: :boolean, default: false`. - [ ] Add an injectable runner seam for the `Open3.capture3` tea/gh shell-out (parallel to `Backlog::CLI.runner`) — required for unit tests. - [ ] Thin bin matching `bin/os-backlog` pattern. - [ ] Keep plain-text `note(...)` output (dispatch-only policy); document the deviation inline. - [ ] Preserve exactly: exit 0 on empty index / no eligible projects; degrade-never-raise on missing tea/gh login and JSON parse errors. - [ ] Highest-severity risk: `State#record` + summary append gated on `--spawn` only. Dry-run must print "would run"/"would append" and touch nothing. Test both sides. - [ ] No existing bin-level tests — new in-process unit tests: `--spawn` parsing/default, dry-run no-mutation, spawn-mode state write + summary append, first-scan baselining without waking, degrade-on-failed-listing, gh-vs-tea row normalization. `tests/wakeup_test.rb` passes unchanged. - [ ] Confirm no wrapper/cron depends on the old loose `ARGV.include?("--spawn")` parsing (header says no cron until ADR-0035 Accepted — likely none). - [ ] Update the ADR-0025 exemption note in `plugins/os-backlog/CLAUDE.md` if wording goes stale; one-row History entry in `docs/implementation-status/os-backlog.md`. ## 5. os-sdlc (plugins/os-sdlc/bin/os-sdlc) — largest, last - [ ] Create `plugins/os-sdlc/lib/os_sdlc/cli.rb` — `OsSdlc::CLI < Thor`. - [ ] Thin bin: `$LOAD_PATH` setup, `require "os_sdlc"`, thor-guarded CLI require, `CLI.start(ARGV)`. - [ ] Extract heavy top-level helpers into per-command classes under `lib/os_sdlc/` (`GateCommand`, `AcLintCommand`, etc., following #422's `InspectCommand` split); CLI methods stay thin. - [ ] Global `--target`: Thor `class_option :target` (decision locked); `load_project`/`SELECTED_TARGET` move from load-time module side effect into command execution. Confirm nothing reads a pre-set top-level `SELECTED_TARGET`. - [ ] Map all subcommands (dashed names via `desc` + `map` per the `Backlog::CLI` convention): `intake`, `red-assert`, `green-assert` (two Thor commands sharing a private gate helper), `ac-lint`, `verdict-assert`, `record-verdict`, `lint`, `lint-init`, `project-config` (bare `--show` becomes an option), `preflight`, `review-packet`, `shard-plan`, `workspace-housekeeping`, `autocorrect`, `agent-budget`. - [ ] `shard-plan` / `workspace-housekeeping` pass raw ARGV to lib classes that self-parse — verify and likely keep passthrough shape rather than Thor options; explicit check, not assumption. - [ ] Convert each `*_OPTION_SPECS`/`*_DEFAULTS` OptionParser pair to `method_option` declarations; verify `--no-lint` boolean negation behaves under Thor's `--no-` convention. - [ ] Preserve positional args: `intake <ticket>`, `lint <run_id>`, `project-config <name>`, `preflight <ticket_path>`, with existing fail_soft-style validation. - [ ] Exit-code contract 0/1/2/3 (header comment) survives verbatim: gate pass/fail 0/1, escalation 2, harness/misconfig 3; outer `rescue StandardError` → `os-sdlc: harness error: ...` + exit 3 in `self.start`. Representative unit test per code. - [ ] No output reformatting (dispatch-only policy) — `agent-budget`/`autocorrect` keep JSON, `lint`/`preflight`/`review-packet`/`project-config --show` keep plain text. - [ ] Behavior contract (unmodified): `tests/cli_test.rb`, `cli_intake_test.rb`, `hardening_preflight_review_packet_test.rb`, `lint_test.rb`, `lint_worklist_target_test.rb`, `agent_budget_test.rb`, `autocorrect_prepass_test.rb`, `cops/bin_script_load_in_test_test.rb` (check it doesn't assert the old case/when shape), via `tests/support/cli_shared_helpers.rb`'s `BIN` harness. - [ ] New direct unit tests for branchy commands (`ac_lint`, `record_verdict`, `project_config`, `verdict_assert`) and the chosen `--target` mechanism.
Author
Owner

Work starting on branch worktree-ticket-423-os-sdlc-corrections (os-sdlc target only this session; other targets deferred to a follow-up session).

Work starting on branch worktree-ticket-423-os-sdlc-corrections (os-sdlc target only this session; other targets deferred to a follow-up session).
Author
Owner

ticket 423 escalated from lint

ticket 423 escalated from lint
Author
Owner

Session 1 progress (os-sdlc target only, per plan):

DONE — all three os-sdlc bins converted to Thor entrypoint + lib CLI (ADR-0123 pattern): bin/os-sdlc → OsSdlc::CLI (lib/os_sdlc/cli.rb), bin/os-sdlc-runner → OsSdlc::Runner::CLI (lib/os_sdlc/runner/cli.rb), bin/os-sdlc-workspace → OsSdlc::WorkspaceCLI (lib/os_sdlc/workspace_cli.rb). New static test tests/bin_thor_migration_test.rb. Suite green: 963 runs, 2366 assertions, 0 failures. Commit 752d384 on worktree-ticket-423-os-sdlc-corrections.

SCOPE NOTE — adr-find (os-adr) and wakeup-poll (os-backlog) are NOT case/when dispatchers and both carry explicit do-not-drive-by grandfather clauses in their plugins' CLAUDE.md; they stay out of this ticket's os-sdlc portion. Remaining targets deferred to next session.

REMAINING — lint gate + review stage of the pipeline, then merge via /os:worktree-finish.

Session 1 progress (os-sdlc target only, per plan): DONE — all three os-sdlc bins converted to Thor entrypoint + lib CLI (ADR-0123 pattern): bin/os-sdlc → OsSdlc::CLI (lib/os_sdlc/cli.rb), bin/os-sdlc-runner → OsSdlc::Runner::CLI (lib/os_sdlc/runner/cli.rb), bin/os-sdlc-workspace → OsSdlc::WorkspaceCLI (lib/os_sdlc/workspace_cli.rb). New static test tests/bin_thor_migration_test.rb. Suite green: 963 runs, 2366 assertions, 0 failures. Commit 752d384 on worktree-ticket-423-os-sdlc-corrections. SCOPE NOTE — adr-find (os-adr) and wakeup-poll (os-backlog) are NOT case/when dispatchers and both carry explicit do-not-drive-by grandfather clauses in their plugins' CLAUDE.md; they stay out of this ticket's os-sdlc portion. Remaining targets deferred to next session. REMAINING — lint gate + review stage of the pipeline, then merge via /os:worktree-finish.
Author
Owner

Session 2 resumed on branch worktree-ticket-423-os-sdlc-corrections. Thor conversion committed as 752d384 (963 runs / 0 failures). Now running the lint wave (bins autocorrected; workspace_cli/runner cli/cli line-length via lint-fixer rounds), then reviewer stage. Note: adr-find and wakeup-poll carry explicit CLAUDE.md grandfather clauses and are not case/when dispatchers — proposing they be descoped from this ticket.

Session 2 resumed on branch worktree-ticket-423-os-sdlc-corrections. Thor conversion committed as 752d384 (963 runs / 0 failures). Now running the lint wave (bins autocorrected; workspace_cli/runner cli/cli line-length via lint-fixer rounds), then reviewer stage. Note: adr-find and wakeup-poll carry explicit CLAUDE.md grandfather clauses and are not case/when dispatchers — proposing they be descoped from this ticket.
Author
Owner

ticket 423 escalated from lint

ticket 423 escalated from lint
Author
Owner

ticket 423 escalated from lint

ticket 423 escalated from lint
Author
Owner

Resolution

Done: os-sdlc, os-sdlc-runner, os-sdlc-workspace converted to thin Thor entrypoints with dispatch in OsSdlc::CLI / OsSdlc::Runner::CLI / OsSdlc::WorkspaceCLI (ADR-0123). adr-find and wakeup-poll DESCOPED: both carry explicit CLAUDE.md grandfather clauses and are not case/when dispatchers — the ticket premise did not apply to them.

Evidence: Commits 752d384, c7f875f, d808556 on branch worktree-ticket-423-os-sdlc-corrections; suite 963 runs / 2366 assertions / 0 failures; os-sdlc reviewer APPROVE verdict (round 2) in .sdlc/tickets/423/verdict.md; pipeline report briefs/011-review-to-done.md; migration test asserts each CLI class is a Thor subclass.

Follow-ups: #424 (decompose OsSdlc::CLI structural lint debt, ticket-skeptic CREATE 2026-08-17); adr-find/wakeup-poll conversion explicitly dropped (grandfathered per CLAUDE.md clauses).

## Resolution **Done:** os-sdlc, os-sdlc-runner, os-sdlc-workspace converted to thin Thor entrypoints with dispatch in OsSdlc::CLI / OsSdlc::Runner::CLI / OsSdlc::WorkspaceCLI (ADR-0123). adr-find and wakeup-poll DESCOPED: both carry explicit CLAUDE.md grandfather clauses and are not case/when dispatchers — the ticket premise did not apply to them. **Evidence:** Commits 752d384, c7f875f, d808556 on branch worktree-ticket-423-os-sdlc-corrections; suite 963 runs / 2366 assertions / 0 failures; os-sdlc reviewer APPROVE verdict (round 2) in .sdlc/tickets/423/verdict.md; pipeline report briefs/011-review-to-done.md; migration test asserts each CLI class is a Thor subclass. **Follow-ups:** #424 (decompose OsSdlc::CLI structural lint debt, ticket-skeptic CREATE 2026-08-17); adr-find/wakeup-poll conversion explicitly dropped (grandfathered per CLAUDE.md clauses).
jared closed this issue 2026-08-17 18:09:10 +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#423
No description provided.