#534 B: Schema 21: project_config column; bind at open; Implementation#project #538

Closed
opened 2026-09-08 20:14:57 +00:00 by jared · 2 comments
Owner

Context

Child of #534 (ADR-0169). Parent design points and comments on #534. Lands after #535.

Tasks

  • Set SCHEMA_VERSION = 21 in db.rb (currently 20)
  • Add String :project_config, text: true, null: false to implementations table
  • In open_implementation.rb, load project and pass project_config: project.to_json to Implementation.open
  • Add Implementation#project(root) method that rebuilds Project from project_config using Project.from_json
  • Add owned_dispatch! guard method to Implementation class
  • In completion_intake.rb, guard Lookup#dispatch_by_id! to check ownership via implementation.owned_dispatch!

Pseudo-Ruby:

# implementation.rb
class StaleDispatch < StandardError; end
def owned_dispatch!(dispatch_id)
  row = Dispatch[dispatch_id]
  raise UnknownDispatch, "no dispatch #{dispatch_id}" unless row
  raise StaleDispatch, "dispatch #{row.id} belongs to implementation #{row.implementation_id}" unless row.implementation_id == id
  row
end

# completion_intake.rb Lookup
def dispatch_by_id! = implementation.owned_dispatch!(@request.dispatch_id)

Acceptance criteria

  • open on the multi-target fixture stores JSON containing the selected target's test_path
  • Implementation#project rebuilds a Project equal to the one loaded at open
  • editing project.yaml after open does not change implementation.project
  • a subagent-stop keyed by a dispatch id that belongs to another implementation raises StaleDispatch and writes nothing

Blocking edges

Blocked by: #535 and #537

Origin

  • Trigger: Agent-initiated from ticket-skeptic gate (CREATE verdict)
  • Improvised this session: none
  • Chain: DESIGN ← ADR-0169
  • Root candidate: #534
  • Where: n/a
  • Session: 1a3b7fd0-0319-465b-8414-0ab70560de3d
  • Transcript: (from session context)
  • Judge: claude-sonnet-5 on 2026-09-08; user-decided reframe recorded in ADR-0169; former child G merged into B
## Context Child of #534 (ADR-0169). Parent design points and comments on #534. Lands after #535. ## Tasks - [ ] Set SCHEMA_VERSION = 21 in db.rb (currently 20) - [ ] Add String :project_config, text: true, null: false to implementations table - [ ] In open_implementation.rb, load project and pass project_config: project.to_json to Implementation.open - [ ] Add Implementation#project(root) method that rebuilds Project from project_config using Project.from_json - [ ] Add owned_dispatch! guard method to Implementation class - [ ] In completion_intake.rb, guard Lookup#dispatch_by_id! to check ownership via implementation.owned_dispatch! Pseudo-Ruby: ```ruby # implementation.rb class StaleDispatch < StandardError; end def owned_dispatch!(dispatch_id) row = Dispatch[dispatch_id] raise UnknownDispatch, "no dispatch #{dispatch_id}" unless row raise StaleDispatch, "dispatch #{row.id} belongs to implementation #{row.implementation_id}" unless row.implementation_id == id row end # completion_intake.rb Lookup def dispatch_by_id! = implementation.owned_dispatch!(@request.dispatch_id) ``` ## Acceptance criteria - [ ] open on the multi-target fixture stores JSON containing the selected target's test_path - [ ] Implementation#project rebuilds a Project equal to the one loaded at open - [ ] editing project.yaml after open does not change implementation.project - [ ] a subagent-stop keyed by a dispatch id that belongs to another implementation raises StaleDispatch and writes nothing ## Blocking edges Blocked by: #535 and #537 ## Origin - Trigger: Agent-initiated from ticket-skeptic gate (CREATE verdict) - Improvised this session: none - Chain: DESIGN ← ADR-0169 - Root candidate: #534 - Where: n/a - Session: 1a3b7fd0-0319-465b-8414-0ab70560de3d - Transcript: (from session context) - Judge: claude-sonnet-5 on 2026-09-08; user-decided reframe recorded in ADR-0169; former child G merged into B
Author
Owner

Work started via /os-sdlc:implement on branch ticket-538 (session d233a2f7-977a-419d-99ea-011b6e1e66f8). Deviation carried from #537: main's brief_facts.rb hot-patched with target: @implementation.target for the run so the SubagentStart hook can write dispatch rows (#534 gap); restored at finish.

Work started via /os-sdlc:implement on branch ticket-538 (session d233a2f7-977a-419d-99ea-011b6e1e66f8). Deviation carried from #537: main's brief_facts.rb hot-patched with target: @implementation.target for the run so the SubagentStart hook can write dispatch rows (#534 gap); restored at finish.
Author
Owner

Resolution

Done: SCHEMA_VERSION 21 adds implementations.project_config. implementation-open loads the project with the selected target and stores Project#to_json on the row; Implementation#project(root) rebuilds it via Project.from_json, so editing project.yaml after open does not change a running implementation. Implementation#owned_dispatch! raises StaleDispatch for a dispatch that belongs to another implementation; CompletionIntake::Lookup#dispatch_by_id! resolves the owning implementation from the dispatch row (or the session's active one when a session is given) and applies the guard, writing nothing on rejection.

Evidence: Pipeline /os-sdlc:implement 538, implementation 5, session d233a2f7-977a-419d-99ea-011b6e1e66f8, dispatches 99-119, ended implementation_complete. Commits 164227d (feat) and 2d7f1c9 (history row) on branch ticket-538, merged to main 2026-09-09. Suite 1093 runs green. New tests: plugins/os-sdlc/tests/runner/implementation_bound_project_test.rb and completion_intake_dispatch_ownership_test.rb. Deviations: (1) first guard resolved the implementation by session and broke session-less dispatch-id stops (5 cli_subagent_stop tests); one programmer-repair round fixed it in production; (2) that repair agent settled against foreign dispatch 5 of implementation 1 (#449) because main's runner had no guard yet, so dispatch 115 was gated and settled by hand; (3) main's brief_facts.rb hot-patched with target: @implementation.target for the run (#534 hook gap), restored at finish; (4) stale live implementation 1 (#449, 2026-09-04) stamped abandoned_at by hand so the schema-21 binary can recreate the shared pipeline.db.

Follow-ups: none new; #539 (no Project.load outside open), #541 (BriefFacts reads the aggregate, removes the hot-patch need), #544 (test-side conflict routing) already cover the rest

## Resolution **Done:** SCHEMA_VERSION 21 adds implementations.project_config. implementation-open loads the project with the selected target and stores Project#to_json on the row; Implementation#project(root) rebuilds it via Project.from_json, so editing project.yaml after open does not change a running implementation. Implementation#owned_dispatch! raises StaleDispatch for a dispatch that belongs to another implementation; CompletionIntake::Lookup#dispatch_by_id! resolves the owning implementation from the dispatch row (or the session's active one when a session is given) and applies the guard, writing nothing on rejection. **Evidence:** Pipeline /os-sdlc:implement 538, implementation 5, session d233a2f7-977a-419d-99ea-011b6e1e66f8, dispatches 99-119, ended implementation_complete. Commits 164227d (feat) and 2d7f1c9 (history row) on branch ticket-538, merged to main 2026-09-09. Suite 1093 runs green. New tests: plugins/os-sdlc/tests/runner/implementation_bound_project_test.rb and completion_intake_dispatch_ownership_test.rb. Deviations: (1) first guard resolved the implementation by session and broke session-less dispatch-id stops (5 cli_subagent_stop tests); one programmer-repair round fixed it in production; (2) that repair agent settled against foreign dispatch 5 of implementation 1 (#449) because main's runner had no guard yet, so dispatch 115 was gated and settled by hand; (3) main's brief_facts.rb hot-patched with target: @implementation.target for the run (#534 hook gap), restored at finish; (4) stale live implementation 1 (#449, 2026-09-04) stamped abandoned_at by hand so the schema-21 binary can recreate the shared pipeline.db. **Follow-ups:** none new; #539 (no Project.load outside open), #541 (BriefFacts reads the aggregate, removes the hot-patch need), #544 (test-side conflict routing) already cover the rest
jared closed this issue 2026-09-09 15:06:58 +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#538
No description provided.