Dissolve RunnerCLI into one bin script per live command; delete the four uncalled subcommands (supersedes ADR-0123 for os-sdlc) #768
Labels
No labels
P0
P1
P2
P3
bug
category/code-change
category/cross-repo
category/eval-run
category/investigation
category/no-test-target
category/owner-ruling
category/prose-artifact
category/recurring-chore
category/structure
category/umbrella
crc-refactor
create
delete
enhancement
filed-by/agent
filed-by/user
frozen
lint-rule
needs-info
needs-triage
next
plugin/cc-architect
plugin/os
plugin/os-adr
plugin/os-aidd-lint
plugin/os-backlog
plugin/os-context
plugin/os-doc-hygiene
plugin/os-sdlc
plugin/os-vault
project/cc-os
ready-for-agent
ready-for-human
recurring
review
rule-proposal
update
waiting
wayfinder:grilling
wayfinder:map
wayfinder:map
wayfinder:research
wayfinder:task
wayfinder:task
wontfix
worklist/deviations
worklist/lint-rule
worklist/new-implement-build
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
jared/cc-os#768
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
RunnerCLIis a Thor CLI with subcommands for every dispatch command. A 2026-09-27 caller inventory shows every live caller is a map file or an agent prompt, never a human typing the command, so Thor's subcommand map and--helpserve no reader. Four subcommands have no caller anywhere; brief looked uncalled but is named at runtime by the hook-cap message.Observed
Live subcommands and callers:
gate— 12 map gate lines inmaps/*.yaml, 5 agent prompts, 3 skill docs; no options.subagent-stop— 10 agent prompts; see #766 for the double-path question this raises.lib/os_sdlc/presenter/hook_payload.rb:32prints "Brief exceeds the hook cap. Run: os-sdlc-runner brief --dispatch-id N" and six agent prompts tell the agent to run that command once; live.implementation-open—skills/implement/SKILL.md:52;--target.next—implementandpipeline-state-investigateskills; no options.implementation-report—implementandresponsibility-refactorskills;--sweep-only.subagent-start—implementskill manual note.No caller anywhere:
retired-tests-check,implementation-close,violations,durations.Reproduce
n/a: design and refactor ticket, not a reproducible bug.
Approach
VERDICT: CREATE (user-approved 2026-09-27)
One bin script per live command, stdlib option parsing, no Thor. Shape:
Flags such as
--targetand--sweep-onlygo through stdlibOptionParser.Required work:
gate,subagent-stop,brief,implementation-open,next,implementation-report,subagent-start).retired-tests-check,implementation-close,violations,durations); delete each uncalled subcommand and its tests if the tests exercise only the CLI layer.os-sdlc-runner <sub>to the new script names, and add a test overmaps/*.yamlthat checks the new names resolve. Include the ten agent-prompt subagent-stop lines, the seven gate lines, and the hook-cap message inlib/os_sdlc/presenter/hook_payload.rb:32; all renames land in the same commit as the script that replaces them, so no agent ever reads a command name that does not resolve.bin/os-sdlc-runnerand theRunnerCLIclass..rubocop.yml:305to match the new one-script-per-command layout.Rejected: keep Thor and prune only the five uncalled subcommands — rejected because the caller inventory shows no human reader for any subcommand, so the subcommand map itself, not just the dead ones, has no purpose.
Acceptance criteria
maps/*.yamland the agent prompts, when this ticket is done, then none referenceos-sdlc-runner.Owner sketch
Non-goals
lsp-probeand the evidence Thor CLIs — left for a later ticket, not touched here.Changing which path settles a dispatch. The prompt-driven dispatch-id keyed subagent-stop stays authoritative; the native hook stays the safety net (#766).
Origin
Depends on #767 (Hooks call DispatchCommands directly). Investigated after #766.
Dissolve RunnerCLI into one bin script per live command; delete the five uncalled subcommands (supersedes ADR-0123 for os-sdlc)to Dissolve RunnerCLI into one bin script per live command; delete the four uncalled subcommands (supersedes ADR-0123 for os-sdlc)Amended after #766 (2026-09-27): brief is live via the hook-cap message; uncalled set is four; prompt lines and hook_payload.rb:32 rename in the same commit; acceptance is a stdout diff per command.
Caller inventory corrected again on 2026-09-27 before implementation: retired-tests-check is live (lib/os_sdlc/query/gate/commands.rb:39 emits it as a gate command whenever a ticket has a Retired tests section), so the dead set is three: implementation-close, violations, durations. Live set is eight. plugins/os/lib/worktree/usage_sweep.rb:8 hardcodes the path to bin/os-sdlc-runner for implementation-report --sweep-only; it and its five finish_command tests change in the same commit. Script names: bin/os-sdlc-, prefixed to avoid PATH collisions for bare words such as next and brief. .rubocop.yml:305 names tests/bin_thor_migration_test.rb which does not exist; the stale exclude goes.
Resolution
Done: RunnerCLI dissolved. Eight scripts bin/os-sdlc- (gate, subagent-stop, brief, implementation-open, next, implementation-report, subagent-start, retired-tests-check) over one thin DispatchScripts class with stdlib OptionParser. Deleted bin/os-sdlc-runner, cli/runner_cli.rb, and the three uncalled commands implementation-close, violations, durations with their report chains. Every caller renamed in the same commit: ten agent prompts, four skill files, three maps, the hook-cap message in presenter/hook_payload.rb, the retired-tests gate command in query/gate/commands.rb, plugins/os usage_sweep and its five finish tests, CONTEXT.md, deterministic-gates.md, CLAUDE.md. Stale .rubocop.yml exclude removed.
Evidence: Commit
9efa4ef0on main (fast-forwarded 2026-09-27). Stdout byte-identical per command against the old runner on the same fixture stdin, recorded in tests/fixtures/command_scripts/stdout.yaml and pinned by tests/cli/command_scripts_stdout_test.rb; tests/cli/command_script_names_resolve_test.rb checks every command name in maps and agent prompts resolves to a script. Suites: os-sdlc 1310 runs, 2868 assertions, 0 failures; os 27 runs, 0 failures. rubocop 71 offenses vs 72 baseline. grep os-sdlc-runner under plugins/ returns nothing. Live smoke after refresh: which os-sdlc-gate resolves via ~/.claude/plugins/os-sdlc/bin; os-sdlc-brief --dispatch-id 99999 prints 'no dispatch 99999' exit 3. ADR-0232; ADR-0123 stays Accepted with a partial-supersession note.Follow-ups: Not ticketed by user choice (noted in HANDOFF.md Session 10): Implementation#closed? and CorrectionRound.for_implementation have no production callers; tests/support/dispatch_240_fixture.rb is dead; the retired-tests gate command resolves through PATH rather than an absolute path. Operational: Claude sessions open during the merge hold old prompts naming os-sdlc-runner and must be restarted before /os-sdlc:implement.