Project.load plus Crc::Run entry: every CRC class takes project #1093
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#1093
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
Twenty-one bins in
plugins/os-sdlc/binhave two entry contracts.Fourteen
os-sdlc-*bins enter throughOsSdlc::Boot.run(name, ProcessIO.from_process, ARGV).That path uses the
Boot::Commands::TABLEregistry,Boot::Inputstyped parsing,Boot::ProjectBindroot lookup, andProcessIO::Outcomeexit handling.The seven other bins (crc-census, crc-file, crc-jobs, crc-records, crc-sweep, crc-tickets, collaborator-pass) enter through
Command.new(ARGV, $stdout, $stderr, Dir.pwd).run.CommandLine(#1088) andCommandController(#1090) re-implement Boot in small.These commands take
--root,--test-root, and a positionalLIB_ROOT.Those values are project.yaml facts that
Projectalready loads.The commands thread the three path strings into TestLookup, Files, PathLookup, Requirers, RequiringFile, and Settings.
Run 20261017T165147Z reports this as eleven root-family
data_clumpfindings.Examples: root+test_root (21), lib_root+test_root (15), lib_root+root (10).
The
argv+cwd+err+outclump, ruled rejected-expected, is a copy ofProcessIO::Invocation.Reproduce
n/a: design ticket
Approach
Each crc parser keeps that command's own value options (
--loader,--exclude,--write, and the rest) throughArgvOption.take!; only--root,--test-root, and the positionalLIB_ROOTgo away.A parser that sees
-hor--helpraisesRefusalError.new(usage_text, 0)with the usage text on stdout; a parser that sees a missing positional raisesRefusalError.new(usage_text, 2).Boot::RefusalErrorgains an optional status argument, default 1, so the fourteen existing commands do not change.Boot::Inputgains an optionaltargetfield.When
targetis set,Boot#preparedbinds aProjectthroughProjectBind#projectand passes it as the third argument; a missing project root is aRefusalErrorwith exit 3.The fourteen existing commands leave
targetnil and keep receiving the root path;ProjectBind#calldoes not change.Project.load(root, target:)reads.sdlc/project.yamlunderrootthroughProject::ConfigandProject.from_data, then binds the named target, soproject.targetwith no argument returns it even on a shaped file.Project#codebasereturnstarget.codebase(root), the existingProject::Codebase.new(code:, test:, root:).The seven commands are: crc-census, crc-file, crc-jobs, crc-records, crc-sweep, crc-tickets, collaborator-pass.
The seven commands become
Runobjects that take(io, project, run).CrcRunPathstays. It is the run, not the project.collaborator-passkeeps its seven subcommands with their own OPTIONS, POSITIONAL, and INJECT tables and the clock fromwith_clock.Inputs.collaborator_passshifts the subcommand name and returns[name, argv]; the action isCollaboratorPass::Run.new(io, project, clock).call(name, argv), and each subcommand parses its own argv withOptionParserdirectly instead of throughCommandLine.Delete
command_controller.rbandcommand_line.rb.Delete the seven
Commandclasses, their USAGE strings, and theiroptions(parser)hooks.Delete the
lib_root:andtest_root:keywords from TestLookup, Files, PathLookup, Requirers, RequiringFile, and Settings.The
Crc::namespace move belongs to #1092.This ticket may land on the unmoved tree (
CrcCensus::Runand so on).#1092 moves it afterwards.
Required work:
Boot::Commands::TABLEfor the crc commands — check: present"crc-census"inplugins/os-sdlc/lib/os_sdlc/boot/commands.rbBoot::Inputsparsers that take--target NAME— check: presentdef self.crc_censusinplugins/os-sdlc/lib/os_sdlc/boot/inputs.rbBoot::Inputcarries an optionaltarget;Boot#preparedpasses it tobound— check: presenttargetinplugins/os-sdlc/lib/os_sdlc/boot/input.rbBoot::ProjectBind#project(dir, target:)returns a boundProjectand refuses with exit 3 when no root exists;#callis unchanged — check: presentProject.loadinplugins/os-sdlc/lib/os_sdlc/boot/project_bind.rbProject.load(root, target:)andProject#codebase = target.codebase(root)— check: presentdef self.loadinplugins/os-sdlc/lib/os_sdlc/project.rbBoot.run— check: absentCommand.new(ARGVinplugins/os-sdlc/bin/*command_controller.rbandcommand_line.rbdeleted — check: absentclass CommandControllerinplugins/os-sdlc/lib/os_sdlc/*.rbtest_root:orlib_root:keywords — check: absenttest_root:inplugins/os-sdlc/lib/os_sdlc/crc_*/**/*.rbcollaborator_pass/command.rbno longer inheritsCommandControllerand no file under it buildsCommandLine— check: absentCommandLineinplugins/os-sdlc/lib/os_sdlc/collaborator_pass/**/*.rbBoot::RefusalError.new(message, status = 1)— check: presentstatusinplugins/os-sdlc/lib/os_sdlc/boot/refusal_error.rb-hwith exit 0 and a missing positional with exit 2 throughRefusalError— check: presentRefusalError.newinplugins/os-sdlc/lib/os_sdlc/boot/inputs.rbOrchestrator work: run
/os-adr:findon the seven bins andBoot::ProjectBindbefore the first edit, because the CLI contract changes.After merge, run
collaborator-pass measureanddelta-checkagainst run 20261017T165147Z.Re-rule
argv+cwd+err+outwithrecord-ruling.Acceptance criteria
.sdlc/project.yamlwith targetos-sdlc, whenProject.load(root, target: "os-sdlc")runs, thenproject.target.pathandproject.target.test.pathmatch the yaml.--target os-sdlcand its existing positional arguments minus LIB_ROOT, when it runs on the fixture repo, then its stdout and exit code equal today's run with explicit--root,--test-root, and LIB_ROOT.-hon any of the seven bins, when it runs, then it prints that command's usage and exits 0.no .sdlc/project.yaml at or above <cwd>on stderr and exits 3; the fourteen existing Boot scripts keep their current fallback.collaborator-pass measureruns, then no data_clump finding namestest_rootorlib_root, and no finding namesCommandControllerorCommandLine.Owner sketch
Retired tests
plugins/os-sdlc/tests/command_controller_test.rb
plugins/os-sdlc/tests/command_line_test.rb
Non-goals
Crc::namespace move (#1092).ProjectBind#call, and their tests: unchanged.Origin
plugins/os-sdlc/skills/collaborator-pass/SKILL.md)Reshape from Jared 2026-10-17: Crc::Run is not a new entry contract. Fourteen os-sdlc-* bins already enter through Boot.run(name, ProcessIO.from_process, ARGV): Boot::Commands::TABLE registry, Boot::Inputs typed parsing, Boot::ProjectBind root lookup, ProcessIO::Outcome exit handling. The seven crc bins and collaborator-pass use Command.new(ARGV, $stdout, $stderr, Dir.pwd) instead; CommandLine (#1088) and CommandController (#1090) re-implemented Boot in small. Do this instead: register each crc command in Boot::Commands::TABLE as a script command with an Inputs.crc_* parser; ProjectBind returns a bound Project (Project.load(config, target:) lives there); Crc::Run takes (io, project, run_config); delete CommandController and CommandLine once the seven commands are on Boot. The argv+cwd+err+out clump ruling (rejected-expected) was wrong: that clump is a copy of ProcessIO::Invocation. Update the Approach and Required work before implementation-open.
Work started in session 909d1bcd on branch ticket-1093 (worktree), via /os-sdlc:implement 1093 --target os-sdlc. ADR find: no one-way door; keep ADR-0166 bin boot line, no Thor (0123/0232), --target through Project#target (0210).
Resolution
Done: Seven bins (crc-census, crc-file, crc-jobs, crc-records, crc-sweep, crc-tickets, collaborator-pass) enter through Boot.run with --target; Boot::Inputs parsers plus Inputs::CrcArgv; Boot::ProjectBind#project binds Project.load(root, target:) and refuses with exit 3 outside a project; RefusalError takes a status (-h exit 0, missing positional exit 2); Project#codebase; Run objects replace the Command classes; CommandController, CommandLine and six Crc*::Command deleted; CRC classes take project: (no lib_root/test_root/root+target keywords); CollaboratorPass::Run and Subcommand replace the dispatcher; docs in crc-refactor and collaborator-pass skills updated.
Evidence: main 2026-10-17:
06341507,2b93c66a, merge of ticket-1093 after main batch #1095; suite 2069 runs 0 failures; rubocop 0 offenses in changed files; collaborator-pass runs 20261017T215950Z and 20261017T220414Z: root-family clumps (root+test_root 21, lib_root+test_root 15, lib_root+root 10, paths+root 9, file+root 6, test_root+write 6) all 0, argv+cwd+err+out gone, data_clump 263 to 230; rulings recorded: io+project+run reject-expected, argv+cwd+err+out superseded; contract-auditor hand-finish audit findings 1-4,6 applied.Follow-ups: (1) CollaboratorPass::Command::Measure still takes cwd: and builds the ledger path from it; should depend on project.root; behavior change when run from a subdirectory; to be captured with a skeptic verdict. (2) root+target clump remains at 3 pre-existing sites (Boot::Input, DiffTestPlan, Gate::Commands), score 9; next loop iteration will surface it. (3) Boot#prepared selects the stream from RefusalError#status; a RefusalError#stream(io) would be cleaner; note only. (4) Workflow defect: the worktree command guard refused a pipeline agent's os-sdlc-subagent-stop call four times and a placeholder pass was recorded; to be captured. (5) {{LIB_ROOT}} placeholders in crc-refactor references/ledger.md and parameters.md may be stale after the --target change.
Measure still takes cwd: instead of project.root (auditor finding 7).