os-sdlc takedown: move the claude -p path onto llm-stack #1439
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#1439
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
The takedown eval harness runs
claude -pthrough four objects underplugins/os-sdlc/eval/ticket-takedown/lib/takedown/.Takedown::ModelRequestbuilds the argv.Takedown::ProcessRunnerruns the process, feeds stdin, and kills the process group on timeout.Takedown::ClaudeExecutorjoins the two.Takedown::ClaudeReplyparses the JSON reply for cost, turns, and token usage.The
llm-stackgem now holds the same work in itsclaude_codeprovider (ADR-0301).Was blocked by #1437 and #1438, both merged 2026-10-27.
Reproduce
n/a: this is a feature, not a defect.
Approach
Required work:
gem "llm-stack", git: "ssh://git@forgejo.swansoncloud.com:2222/jared/llm-stack.git", require: "llm"toplugins/os-sdlc/Gemfile(the takedown harness has no Gemfile of its own) and commitplugins/os-sdlc/Gemfile.lock(ADR-0166) — check: presentllm-stackinplugins/os-sdlc/Gemfile.lockClaudeExecutor#callbuild aLLM::Clientper call with aclaude_codeprofile from theModelRequestfields and callLLM::Client#chatwithsystemfromcard, theprompt, and theschema; the profile carriesmodel,cwd,tools,allowed_tools,disallowed_tools,budget_usdfromcap,persist_session,resume,settings_jsonfrom the constructor,executablefrom the constructor, and a timeout of 900 seconds; the client uses an emptyLLM::PriceTableso the CLI-reported cost is kept — check: presentchat(inplugins/os-sdlc/eval/ticket-takedown/lib/takedown/adapter/claude_executor.rbClaudeExecutorfrom usingProcessRunner; keepProcessRunneritself, becauseSuiteRunner,LintRun,ScratchRepo, andRunEnvironmentstill use it for git, suite, and lint commands — check: absentrunnerinplugins/os-sdlc/eval/ticket-takedown/lib/takedown/adapter/claude_executor.rbModelRequest#claude_argvand its helper methods; keepModelRequestas the value that holds the step inputs — check: absentclaude_argvinplugins/os-sdlc/eval/ticket-takedown/lib/**/*.rbClaudeReply.parsewith a mapping from the gemResponse: token counts fromResponse#usage, cost fromResponse#cost,rawfrommeta["raw"],session_idfrommeta["session_id"],turnsfrommeta["num_turns"],modelsfrommeta["models"], andstructuredfrom parsingResponse#text; keepStepOutcomefields unchanged — check: presentResponseinplugins/os-sdlc/eval/ticket-takedown/lib/takedown/parser/claude_reply.rbLLM::TimedOutandLLM::ProviderErrorinClaudeExecutorand build the failed reply frome.message(reported <subtype>: <result>orexit N: <stderr>), so the CLI result text still reachesnote;claude_error_note_testmay change its expected text but must keep asserting that result text reaches the note — check: presentLLM::TimedOutinplugins/os-sdlc/eval/ticket-takedown/lib/**/*.rbclaudethrough the profileexecutablesetting — check: absentFakeRunner.newinplugins/os-sdlc/eval/ticket-takedown/test/adapter/claude_executor_test.rbOrchestrator work: compare one takedown run before and after the change for the same case, run
bin/refresh-plugins, and add one History row to the os-sdlc leaf underdocs/implementation-status/.Acceptance criteria
claudethat returns usage and cost, whenClaudeExecutor#callruns, then the reply holds the token counts and the cost from the gemResponse.claudethat never answers, whenClaudeExecutor#callruns, then the reply is a failure with a timeout note.ModelRequestwithresumeset, whenClaudeExecutor#callruns, then the fakeclauderecords the resume session ID.ModelRequestwithhiddenpaths, whenClaudeExecutor#callruns, then the fakeclauderecords the matching disallowed-tool rules.Owner sketch
Non-goals
StepOutcomeshape.claudebinary in any test.claude -p.Origin
VERDICT: CREATE
REASON: Implements human-ruled ADR-0301 and spec step 3 for the takedown caller; no open ticket covers it.
Work started on branch ticket-1439 via /os-sdlc:implement (session 375f16d0). Gem prerequisites shipped: llm-stack a708188 (Response#meta, settings_json).
Resolution
Done: Takedown ClaudeExecutor calls LLM::Client#chat on a claude_code profile. ModelRequest#settings holds the step inputs. ClaudeReply.from_response reads text, usage, cost and meta from LLM::Response. The claude -p argv builder and JSON reply parser are deleted. plugins/os-sdlc/Gemfile pins llm-stack from Forgejo with a committed lockfile.
Evidence: Implementation 198 on branch ticket-1439, commit
d6c7f1e7: change-auditor, seam-designer, test-writer, test-reviewer, programmer, behavior-verifier, suite-check, contract-auditor and refactorer all passed. Required-work checks green. Lens lines challenged: one code defect fixed by the refactorer, one heuristic holds.Follow-ups: none. Gem follow-ups already filed as llm-stack #1-#4.