os-sdlc entry: decide and build Thor for argument parsing behind the fixed os-sdlc-* script names (ADR-0232) #1646

Closed
opened 2026-11-09 16:08:28 +00:00 by jared · 4 comments
Owner

Problem

36 bin/ scripts and 3 hooks call OsSdlc::Boot.run. Boot and its helpers are about 840 lines, and about 375 of them (Boot::Inputs, Arguments, ArgvOption, CommandSpec) parse arguments by hand. Jared asked on 2026-11-09 why Thor does not do this: "Feels like we should be able to respond to the hook or agent from the Thor call directly... So the IO portion never leaves Thor." No ruling exists yet.

Observed

os-backlog has the shape: Backlog::CLI.start(ARGV, state_dir:, runner:, env:). os-sdlc has one Thor class with injected streams: Boot::Onboarding.start(args, invocation: io). ADR-0232 fixes eight script names (gate, subagent-stop, brief, implementation-open, next, implementation-report, subagent-start, retired-tests-check), their flags, byte-identical stdin, argv, and stdout, and exit 3 for harness errors. The os plugin calls os-sdlc-implementation-report by name. ADR-0123 keeps Thor for bin/os-sdlc and excludes the dispatch commands. Thor prints its own argument errors, so the usage text can differ from the fixed bytes. Adapter injection does not need Thor: commit 737d2e13 passes the tracker source through ProcessIO.

Reproduce

n/a: structure ticket.

Approach

First get a ruling: does Thor replace the hand-written parsing? If yes: record a superseding ADR through /os-adr:create (ADR-0232 and the exclusion clause of ADR-0123), update the Hook contract section of plugins/os-sdlc/CLAUDE.md, and convert in stages with the script names kept. Keep three behaviors: bind the database before a model class loads; exit 0 and create no database in a directory with no project; exit 3 for a harness error.

Origin

  • Trigger: Jared's question about Boot on 2026-11-09, and /os-adr:find on lib/os_sdlc/boot.rb
  • Improvised this session: none
  • Chain: tests could not pass a fake tracker ← the entry built adapters inside the library ← DESIGN (Boot command table and hand-written parser; no ADR records them; ADR-0232)
  • Root candidate: none found; searched Thor, Boot, argument parsing, optparse, Boot::Inputs
  • Where: plugins/os-sdlc/lib/os_sdlc/boot.rb, plugins/os-sdlc/lib/os_sdlc/boot/inputs.rb
  • Session: 19f78576-9fa5-4fd3-9984-a9e58ef897ad
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os-plugins-os-sdlc/19f78576-9fa5-4fd3-9984-a9e58ef897ad.jsonl

VERDICT: CREATE (ticket-skeptic, 2026-11-09): the user asked for this Thor/Shell/IO work on 2026-11-09; no open ticket covers Thor in place of the hand-written Boot argument parsing.

## Problem 36 `bin/` scripts and 3 hooks call `OsSdlc::Boot.run`. `Boot` and its helpers are about 840 lines, and about 375 of them (`Boot::Inputs`, `Arguments`, `ArgvOption`, `CommandSpec`) parse arguments by hand. Jared asked on 2026-11-09 why Thor does not do this: "Feels like we should be able to respond to the hook or agent from the Thor call directly... So the IO portion never leaves Thor." No ruling exists yet. ## Observed os-backlog has the shape: `Backlog::CLI.start(ARGV, state_dir:, runner:, env:)`. os-sdlc has one Thor class with injected streams: `Boot::Onboarding.start(args, invocation: io)`. ADR-0232 fixes eight script names (`gate`, `subagent-stop`, `brief`, `implementation-open`, `next`, `implementation-report`, `subagent-start`, `retired-tests-check`), their flags, byte-identical stdin, argv, and stdout, and exit 3 for harness errors. The `os` plugin calls `os-sdlc-implementation-report` by name. ADR-0123 keeps Thor for `bin/os-sdlc` and excludes the dispatch commands. Thor prints its own argument errors, so the usage text can differ from the fixed bytes. Adapter injection does not need Thor: commit 737d2e13 passes the tracker source through `ProcessIO`. ## Reproduce n/a: structure ticket. ## Approach First get a ruling: does Thor replace the hand-written parsing? If yes: record a superseding ADR through `/os-adr:create` (ADR-0232 and the exclusion clause of ADR-0123), update the Hook contract section of `plugins/os-sdlc/CLAUDE.md`, and convert in stages with the script names kept. Keep three behaviors: bind the database before a model class loads; exit 0 and create no database in a directory with no project; exit 3 for a harness error. ## Origin - Trigger: Jared's question about `Boot` on 2026-11-09, and `/os-adr:find` on `lib/os_sdlc/boot.rb` - Improvised this session: none - Chain: tests could not pass a fake tracker ← the entry built adapters inside the library ← DESIGN (`Boot` command table and hand-written parser; no ADR records them; ADR-0232) - Root candidate: none found; searched Thor, Boot, argument parsing, optparse, Boot::Inputs - Where: `plugins/os-sdlc/lib/os_sdlc/boot.rb`, `plugins/os-sdlc/lib/os_sdlc/boot/inputs.rb` - Session: 19f78576-9fa5-4fd3-9984-a9e58ef897ad - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os-plugins-os-sdlc/19f78576-9fa5-4fd3-9984-a9e58ef897ad.jsonl VERDICT: CREATE (ticket-skeptic, 2026-11-09): the user asked for this Thor/Shell/IO work on 2026-11-09; no open ticket covers Thor in place of the hand-written Boot argument parsing.
Author
Owner

Owner ruling, Jared, 2026-11-10 (session a48658d5): Thor is the entry for os-sdlc commands; Boot.run and its command table go. A command and the classes below it take a Project; project.repo is lazy; project.connect(:db) connects the database only for commands that use a model; a Run object returns a result that the command prints. The ADR judge classed the Thor entry choice as a habit (no ADR). ADR-0123 lost its os-sdlc exclusion (commit 01137062); ADR-0232 stays in force for script names, output shapes, and exit 3. ADR-0312 accepts activemodel in os-sdlc. Done: #1672 (Project is an ActiveModel class). Next slice: crc-sweep on Thor.

Owner ruling, Jared, 2026-11-10 (session a48658d5): Thor is the entry for os-sdlc commands; Boot.run and its command table go. A command and the classes below it take a Project; project.repo is lazy; project.connect(:db) connects the database only for commands that use a model; a Run object returns a result that the command prints. The ADR judge classed the Thor entry choice as a habit (no ADR). ADR-0123 lost its os-sdlc exclusion (commit 01137062); ADR-0232 stays in force for script names, output shapes, and exit 3. ADR-0312 accepts activemodel in os-sdlc. Done: #1672 (Project is an ActiveModel class). Next slice: crc-sweep on Thor.
Author
Owner

Follow-up dropped by ticket-skeptic (root-versus-symptom test): the detector traces for the three hook entries (hooks/*.rb call OsSdlc::Hook class methods) are empty by code reading (detector/constructor_graph/call.rb:14-16); the detector was not run to observe it. The fix belongs to this ticket, not to a new one. Draft: session a48658d5-b566-40ce-8257-ebeabf56f7e1.

Follow-up dropped by ticket-skeptic (root-versus-symptom test): the detector traces for the three hook entries (hooks/*.rb call OsSdlc::Hook class methods) are empty by code reading (detector/constructor_graph/call.rb:14-16); the detector was not run to observe it. The fix belongs to this ticket, not to a new one. Draft: session a48658d5-b566-40ce-8257-ebeabf56f7e1.
Author
Owner

Check of the earlier comment about hook-entry detector traces (2026-11-12, main dd2c51786).

The claim was wrong. The traces of the three hook entries are not empty. A probe that builds Detector::Measures and walks constructor_edges from each entry constant reports, for each of hooks/subagent_start.rb, hooks/subagent_stop.rb, and hooks/post_tool_use.rb: constant OsSdlc::Hook, 3 direct edges (AsyncLaunchTrigger at hook.rb:46, ArtifactDir at hook.rb:49, CLI::Invocation at hook.rb:54), 21 reachable objects.

Cause of the wrong claim: the entry is the first constant in the script that resolves to a source file (lib/os_sdlc/detector/entry_points.rb:27-30), and the trace starts at that constant (clump_traces.rb:13-16). Call#constructor? (constructor_graph/call.rb:14-16) filters edges inside the lib class only. The Hook.subagent_start call in the script is not read as an edge and does not need to be.

Two bin entries do have no edges: OsSdlc::CLI::PipelineScript::SubagentStop and OsSdlc::CollaboratorPass::CLI (0 direct, 0 reachable). Nobody checked why. The one consumer effect found: collaborator_pass.rb:32-37 prints no "born at" line for a data-clump finding under such an entry. No cop reads the traces. No ticket is filed for this; it is not shown to be a defect.

Check of the earlier comment about hook-entry detector traces (2026-11-12, main dd2c51786). The claim was wrong. The traces of the three hook entries are not empty. A probe that builds `Detector::Measures` and walks `constructor_edges` from each entry constant reports, for each of `hooks/subagent_start.rb`, `hooks/subagent_stop.rb`, and `hooks/post_tool_use.rb`: constant `OsSdlc::Hook`, 3 direct edges (`AsyncLaunchTrigger` at hook.rb:46, `ArtifactDir` at hook.rb:49, `CLI::Invocation` at hook.rb:54), 21 reachable objects. Cause of the wrong claim: the entry is the first constant in the script that resolves to a source file (`lib/os_sdlc/detector/entry_points.rb:27-30`), and the trace starts at that constant (`clump_traces.rb:13-16`). `Call#constructor?` (`constructor_graph/call.rb:14-16`) filters edges inside the lib class only. The `Hook.subagent_start` call in the script is not read as an edge and does not need to be. Two bin entries do have no edges: `OsSdlc::CLI::PipelineScript::SubagentStop` and `OsSdlc::CollaboratorPass::CLI` (0 direct, 0 reachable). Nobody checked why. The one consumer effect found: `collaborator_pass.rb:32-37` prints no "born at" line for a data-clump finding under such an entry. No cop reads the traces. No ticket is filed for this; it is not shown to be a defect.
Author
Owner

Resolution

Done: The 14-item plan of 2026-11-10 is complete. Each bin script starts a Thor class and Boot is deleted (session a48658d5, to 031244657). Close-out on 2026-11-12: ruling 139 records Jared's ruling that Project holds the collaborators (plan item 11); ProcessIO has no git member, Project builds git through its lazy reader, entries take optional collaborators for tests, the three entries with no project read project.git from an unconfigured project, and seven dispatch, implementation, and gate classes take the project (plan item 9, ruling 140); the hook contract in plugins/os-sdlc/CLAUDE.md matches the code.

Evidence: Commits on main: b52b09d7d, dd2c51786, 6d68ed6e2, 8affdc640, 61994c3a5, 604b54d1d, 39c877a11, 634df9030, 86417907c, 6cc5095e4. Suite on main: 5326 runs, 0 failures, 0 errors. Smoke in the cc-os project with the refreshed plugin cache: os-sdlc-brief, os-sdlc-gate, and os-sdlc-next connect the database and refuse an unknown dispatch or session with exit 3; the subagent_start, post_tool_use, and lint_changed hooks run. os-sdlc-lint and the lint hook ran with real git. The hook-entry detector traces are not empty (earlier comment).

Follow-ups: Captured: #1715 (the ADR tool cannot remove ADR-0232; plan item 12 said ADR-0232 stays, and its text is still stale). Open tickets from this work: #1687, #1688, #1689, #1690, #1678, #1381. Dropped, reported to Jared: (1) shell, lint_process, mirror_sync, trackers, and backlog_process still travel on ProcessIO; the approved plan named only git. (2) A repo read before Project#with(root:) keeps the old root; no code does this (ruling 140 leaves it). (3) No guard fails a test that builds the real git factory without running git; ProcessStartGuard fails a test that runs git. (4) Two bin entries have no detector constructor edges (PipelineScript::SubagentStop, CollaboratorPass::CLI); not shown to be a defect.

## Resolution **Done:** The 14-item plan of 2026-11-10 is complete. Each bin script starts a Thor class and Boot is deleted (session a48658d5, to 031244657). Close-out on 2026-11-12: ruling 139 records Jared's ruling that Project holds the collaborators (plan item 11); ProcessIO has no git member, Project builds git through its lazy reader, entries take optional collaborators for tests, the three entries with no project read project.git from an unconfigured project, and seven dispatch, implementation, and gate classes take the project (plan item 9, ruling 140); the hook contract in plugins/os-sdlc/CLAUDE.md matches the code. **Evidence:** Commits on main: b52b09d7d, dd2c51786, 6d68ed6e2, 8affdc640, 61994c3a5, 604b54d1d, 39c877a11, 634df9030, 86417907c, 6cc5095e4. Suite on main: 5326 runs, 0 failures, 0 errors. Smoke in the cc-os project with the refreshed plugin cache: os-sdlc-brief, os-sdlc-gate, and os-sdlc-next connect the database and refuse an unknown dispatch or session with exit 3; the subagent_start, post_tool_use, and lint_changed hooks run. os-sdlc-lint and the lint hook ran with real git. The hook-entry detector traces are not empty (earlier comment). **Follow-ups:** Captured: #1715 (the ADR tool cannot remove ADR-0232; plan item 12 said ADR-0232 stays, and its text is still stale). Open tickets from this work: #1687, #1688, #1689, #1690, #1678, #1381. Dropped, reported to Jared: (1) shell, lint_process, mirror_sync, trackers, and backlog_process still travel on ProcessIO; the approved plan named only git. (2) A repo read before Project#with(root:) keeps the old root; no code does this (ruling 140 leaves it). (3) No guard fails a test that builds the real git factory without running git; ProcessStartGuard fails a test that runs git. (4) Two bin entries have no detector constructor edges (PipelineScript::SubagentStop, CollaboratorPass::CLI); not shown to be a defect. <!-- os-backlog kind: resolution -->
jared closed this issue 2026-11-12 18:28:29 +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#1646
No description provided.