Fix ScopePolicy.load so the pre-tool-use write guard is active [capture] #571
Labels
No labels
P0
P1
P2
P3
bug
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
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#571
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?
Context
The responsibility audit found that the pre-tool-use write guard never
blocks a write. ScopePolicy.load calls OsSdlc::Project.load without the
required target: keyword. The rescue on the next line swallows the error.
Observed
Project.load(dir = Dir.pwd, target:) requires target:.
lib/os_sdlc/scope_policy.rb:15 calls OsSdlc::Project.load.test_path. Line 16
rescue StandardError swallows the ArgumentError: missing keyword: :target.
So test_path is always nil, out_of_scope? always returns false, and the
guard at hooks/pre_tool_use.rb:26 never blocks a test-writer from writing
production code.
Reproduce
cd plugins/os-sdlc && ruby -Ilib -e 'require "os_sdlc/project";
OsSdlc::Project.load'
Expected
A Minitest snippet test_scope_policy_load_reads_test_path_from_project that
asserts ScopePolicy.load.test_path equals the project's configured test_path
when .sdlc/project.yaml exists, and a second assertion that out_of_scope?
returns true for a production path when the role is test-writer.
Origin
• Trigger: /os-sdlc:responsibility-audit run 13 on plugins/os-
sdlc/lib/os_sdlc/project.rb, 2026-09-14
• Improvised this session: none
• Chain: guard inert ← test_path nil ← swallowed ArgumentError ← Project.
load signature changed to require target: without updating ScopePolicy.load
(DESIGN, lib/os_sdlc/scope_policy.rb:15)
• Root candidate: this ticket
• Where: lib/os_sdlc/scope_policy.rb
• Session: 23a382aa-f78e-495f-9cbd-0934e163b37d
• Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/23a382aa-
f78e-495f-9cbd-0934e163b37d.jsonl
Tasks
ScopePolicy.loadreadstest_pathfromimplementation.project(ADR-0169), never fromProject.load.rescue StandardErrorthat swallowed the load error; a missing implementation yieldstest_path: nilexplicitly.Project.upsertcallsensure_creatable!whenproject.yamlis absent (git-repo check and overwrite refusal in one place).Project.create(no sender outside lib and tests; verified 2026-09-14).os-sdlc project-config NAME, notOsSdlc::Project.create.Acceptance criteria
test_pathistest, a test-writer role Write tolib/foo.rbisout_of_scope?true.Project.upserton a non-git directory raises the not-a-git-repo error.Project.upserton an existingproject.yamlmerges keys and does not raise.OsSdlc::Project.respond_to?(:create)is false.MissingProjectmessage includesos-sdlc project-config.Structural follow-through
tests/support/project_scenario.rb:90andtests/runner/brief_facts_enrichment_facts_test.rb:173switch fromProject.createtoProject.upsert.rg -n 'Project\.create' plugins/os-sdlcreturns nothing.ADR case
Completes ADR-0169 (scope_policy.rb reads
implementation.project). Completes ADR-0156. Amends ADR-0177 (Project.upsertis the sole creator of project.yaml); create the amending ADR when this ticket lands.Batch
Map: #570. Position 1 of 4. Followed by #573. Map: maps/poodr-ticket-implementation.yaml.
Work started via /os-sdlc:responsibility-refactor batch 2 (map #570). Branch: ticket-571, worktree .claude/worktrees/ticket-571, map poodr-ticket-implementation.yaml.
Resolution
Done: ScopePolicy.load resolves the project from cwd (Project::Yaml.containing + Project.load with OS_SDLC_TARGET), rescues only TargetSelectionError; scope_policy.rb requires what the hook process needs. Project.create deleted; Project.upsert calls ensure_creatable! on the create branch; missing-project message names os-sdlc project-config. ADR-0178 records it.
Evidence: Merged to main
8daffca(code9b41175). Suite: 1220 runs, 0 failures. Rubocop clean on 7 touched files. Hand-verified: judge-role Edit denied; test-writer Write to lib denied and to tests allowed with OS_SDLC_TARGET=os-sdlc. Pipeline: 8 dispatches, 901 s, bound_exhausted after 3 programmer-repair rounds; deviations: hand-moved test-side Project.create callers to upsert, removed the obsolete clobber-refusal test, added six require_relative lines to scope_policy.rb (hook has no Zeitwerk). Position 1 of 4 on map #570.Follow-ups: #575 hook cannot learn the target at a multi-target root (guard permissive there; skeptic CREATE). Structural follow-through: done (rg 'Project.create' returns only the removal test).