Pipeline briefs read the caller's directory, not the bound worktree root #1164
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#1164
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
os-sdlc-briefderives the project root from the caller's cwd (boot/inputs.rb:10Input.new(dir: io.cwd)->boot/project_bind.rb:11RootSearch.outermost(dir)). A subagent orchestrator runs in the main checkout, sodispatch/brief/facts.rb:118and:122readtest_changesandcode_changesfrom the main checkout, not the bound worktree. Hook admission (admission.rb:7) and the submit path have the same cwd dependence.Example: implementation 78 (ticket #1159, dispatch 734) bound worktree
/home/jared/dev/cc-os/.claude/worktrees/crc-token-levers. The test-reviewer gotMISSING: test_changes.andverdict:error.Ruling
Option C, decided AFK by the orchestrator on 2026-10-27 (reversible). Store the worktree root on the
implementationsrow at implementation open. ADR-0055 scopes "stores NO paths" to.sdlc/project.yaml: "Project.load(dir) walks up ... to find .sdlc/project.yaml, and root is the directory containing that .sdlc/". It does not governpipeline.db. No superseding ADR. Option A (match branchticket-<n>) fails because the #1159 branch iscrc-token-levers. Option B is not needed.Approach
Slice 1 of 2. Store the bound root on the
implementationsrow and make the brief read it. Every other cwd-dependent path moves in #1436.Add a nullable
worktree_rootcolumn toimplementations.Implementation::Openwrites the root it bound:Open#root(implementation/open.rb:25), whichBoot::ProjectBind#callfound withProject::RootSearch.outermost(cwd). That search stops at the git top level, so an open fromW/libstoresW, notW/lib.Implementation#work_root(fallback)returnsworktree_root, orfallbackwhen the column is null.Dispatch::Brief.forbuilds the project fromimplementation.work_root(root), soBrief::Facts(facts.rb:118,:122) readstest_changesandcode_changesfrom the stored worktree.Brief.foris the one composition point for bothos-sdlc-brief(Dispatch::BriefLookup) and the SubagentStart brief payload (Dispatch::SubagentStart#hook_payload), so both briefs get the stored root. Admission's other root uses stay in #1436.Migration mechanism: today
Db.file_dbarchives and recreates a file whosePRAGMA user_versiondiffers fromDb::SCHEMA_VERSION(30), and refuses while an implementation is live. A version bump is therefore destructive, and a worktree binary that bumps it wipes the shared.sdlc/pipeline.dbthrough the symlink (ADR-0253). Do not bumpSCHEMA_VERSION. Instead:Db.add_implementation_binding_columnsaddst.String :worktree_root(nullable, no default), so new files and:memory:databases have the column.Db.file_db, after the stale-version check, runsdb.alter_table(:implementations) { add_column :worktree_root, String }only whendb[:implementations].columnslacks:worktree_root. SQLiteADD COLUMNis additive: it keeps every row and sets the new column to NULL.ADR check done:
/os-adr:createjudged the column a habit (only os-sdlc reads it); ADR-0109 (SQLite via Sequel) allows it. ADR-0055 is not affected (see Ruling).Required work:
Db.add_implementation_binding_columnsadds a nullableworktree_rootString column (proven by AC 1).Db.file_dbaddsworktree_rootto an existing current-version file that lacks it, withalter_table ... add_column, and keeps its rows (proven by AC 1).SCHEMA_VERSION = 30inlib/os_sdlc/db.rbImplementation::Open#open_implementationpassesworktree_root: roottoImplementation.open(proven by AC 2).Implementation::Targetingaddswork_root(fallback): the storedworktree_root, elsefallback(proven by AC 3).Dispatch::Brief.forbuilds the project fromimplementation.work_root(root)(proven by AC 3).Acceptance criteria
.sdlc/pipeline.dbfile stamped with the currentuser_versionwhoseimplementationstable has noworktree_rootcolumn and holds one row, whenDb.openopens it, then the table has aworktree_rootcolumn, the row is still there, and nopipeline.db.stalefile is made..sdlc/project.yamlat its top level, whenimplementation-openruns with cwdW/lib, then the newimplementationsrow hasworktree_rootequal to W.test_changes, and an uncommitted test filetest/foo_test.rbin W, whenos-sdlc-brief --dispatch-id <id>runs with cwd set to a different checkout M that has no changes, then the brief'stest_changesnamesfoo_test.rb.Owner sketch
Dbimplementations.worktree_rootin new databases, and adds it in place to an existing current-version file that lacks it, without a version bump.Implementation::OpenOpen#root) asworktree_rootwhen it creates the row.Implementation(Implementation::Targeting)work_root(fallback)answers the storedworktree_root, else the fallback.Dispatch::Brief.forimplementation.work_root(root)instead of the caller's root.No new object:
Implementationowns the column data, andDbowns the schema.tests/db_worktree_root_column_test.rbtests/pipeline/cli_implementation_open_worktree_root_test.rbtests/pipeline/cli_brief_worktree_root_test.rbRed at HEAD (run on 2026-10-27, main
bb8ff3a3), each for the intended reason:test_opening_a_current_version_file_adds_worktree_root_and_keeps_its_rows:Expected [:id, :session_id, :completed_at] to include :worktree_root.test_open_from_a_subdirectory_stores_the_worktree_root_not_the_cwd: expected the tmpdir path, actualnil.test_brief_run_from_the_main_checkout_reads_test_changes_from_the_stored_worktree:Expected /foo_test\.rb/ to match "".All three pass against a spike of Required work 1, 2, 4 and 6 (no code committed).
Out of scope
admission.rb:7,boot.rb:57), the submit path, gate runs (X3), andDispatch::Settlement.build_repo(X4): #1436.git worktree list.worktreecreates worktrees.worktree_rootfor closed implementations.Occurrence: Briefs and submits read the implementation's recorded worktree, not the hook cwd
Seen: plugins/os-sdlc/lib/os_sdlc/dispatch/admission.rb:7 (event.cwd) -> subagent_start.rb:30 -> brief.rb:7 -> project/snapshot.rb -> brief/facts.rb:91,97; submit side boot/inputs.rb:33-38 and hook_reading.rb:22
Run: session c843bd27-b3bf-4e36-9243-df1697457146; takedown runs docs/takedown/1415-20261027-123629 and docs/takedown/1415-20261027-125443; implementation 178 of #1111
Adds: Two candidate designs (worktree_root column on implementations, graded cause_removed, with open defects X3 gate runs, X4 Settlement.build_repo, X5 open records any cwd; or a root key in project_config JSON, graded defect_remains), the shared pipeline.db migration risk (additive, apply from main checkout, run /os-adr:find on ADR-0109), and the next step: re-run /os-sdlc:ticket-takedown #1164 after the tickets_bin_test.rb fix lands.
Takedown relevance: needs a ruling
Harm: A pipeline agent that runs os-sdlc-brief from a directory outside the implementation's worktree gets a dispatch brief computed from the main checkout, so test_changes and code_changes come back empty and the test-reviewer stops with verdict error.
Protects: Briefs must describe the change the implementation actually produced, so each pipeline agent judges the real diff and the pipeline can run from a subagent orchestrator without a human re-running it by hand.
Harm path: The os-sdlc-brief CLI (bin/os-sdlc-brief) resolves its project root from the caller's cwd via ProjectBind and RootSearch, and Facts then reads test_changes and code_changes from that root. implementation-open also derives its root from the caller's cwd and stores no worktree path, so the brief reads whatever checkout the caller is in. (live: true)
Evidence:
Conflicting ADRs:
The ticket is waiting for Jared's ruling on the ADRs above.
Ruling: option C (decided AFK 2026-10-27)
implementationsrow at open (earlier takedown Design 1, graded cause_removed)..sdlc/project.yaml; it does not governpipeline.db, so no superseding ADR is needed.crc-token-levers, notticket-<n>, and ADR-0157 has no file in docs/adr.Takedown relevance: needs a ruling
Harm: A pipeline agent that runs os-sdlc-brief from the main checkout gets test_changes and code_changes read from that checkout, not the worktree the implementation is bound to, so the test-reviewer reports MISSING: test_changes and verdict error.
Protects: Pipeline briefs, hook admission, and submit must judge the work in the implementation's bound worktree, so that a review verdict reflects the code actually under review.
Harm path: The os-sdlc-brief command: Boot::Inputs.brief takes io.cwd as the directory, ProjectBind resolves the root with RootSearch.outermost, and Dispatch::Brief::Facts builds Changes and Codebase from @project.root for test_changes and code_changes. The same cwd-derived root feeds boot.rb:57 (pipeline_db? for hook launch). (live: true)
Evidence:
18a4a82c).Conflicting ADRs:
The ticket is waiting for Jared's ruling on the ADRs above.
ADR check (2026-10-27, AFK): /os-adr:create rejected an ADR for the worktree_root column. Judge verdict, verbatim: "The new worktree_root column on implementations is read only by os-sdlc's own code (brief, admission, submit, open). A column that only one plugin reads is a habit, because the reversing commit can drop it and change those readers. ... Record this nowhere; put the reason in the commit message." So ADR-0055's one-way-door content does not cover this column: ADR-0055's decision text governs .sdlc/project.yaml only ("It stores NO paths"), and the column is a habit, not ADR content. Logged in docs/decision-system/afk-adr-log.md.
Takedown relevance: needs a ruling
Harm: A pipeline brief run from the main checkout reads test_changes and code_changes from the main checkout instead of the implementation's bound worktree, so the test-reviewer receives MISSING: test_changes and settles error.
Protects: Pipeline agents judge the change that was actually made in the bound worktree, so verdicts and gates reflect the real implementation rather than the caller's checkout.
Harm path:
os-sdlc-brief --dispatch-id N(bin/os-sdlc-brief:6) enters Boot.brief, which builds Input from io.cwd (boot/inputs.rb:14), then ProjectBind derives the root with RootSearch.outermost(cwd) (boot/project_bind.rb:11), and Dispatch::Brief::Facts reads changes from that root (dispatch/brief/facts.rb:118, :122). (live: true)Evidence:
76880dcc(2026-10-27, the AFK ADR log row for #1164), with no later commit that removes the cwd root derivation.Conflicting ADRs:
The ticket is waiting for Jared's ruling on the ADRs above.
Takedown relevance blocked twice on ADR-0055 (runs docs/takedown/1164-20261027-134934 and 1164-20261027-135509), even after /os-adr:create judged the column a habit. Proceeding with /os-sdlc:implement 1164 on the current body. Relevance defect filed separately.
Work started on branch ticket-1164 via /os-sdlc:implement (poodr-ticket-implementation), slice 1 per the current body. Slice 2 is #1436.
Resolution
Done: implementation-open stores the bound git top level in implementations.worktree_root (added in place, schema version unchanged, double-checked under an immediate transaction). Brief.for builds the brief project from the stored root and falls back to the caller root. A brief run from the main checkout now reads test_changes and code_changes from the bound worktree.
Evidence: main
d2f8a213(merged via worktree finish, fast-forward to71e1818e). Tests: db_worktree_root_column_test, cli_implementation_open_worktree_root_test, cli_brief_worktree_root_test. os-sdlc suite 2790 runs, 0 failures. Rubocop clean. Implementation 193 escalated (test defect: two Bound stubs lacked work_root). It was hand-finished per the escalation procedure, with an opus design audit (no must-fix; the should-fix race is fixed). No ADR: /os-adr:create judged the column a habit. The AFK ruling is logged in docs/decision-system/afk-adr-log.md.Follow-ups: #1436 (slice 2: admission, submit, gate runs, Settlement) already filed with skeptic verdict CREATE. #1435 (relevance slug) fixed and merged this session.