Cut Handoff -> Dispatch: Handoff.unclaimed takes the claimed ids #1171

Closed
opened 2026-10-19 20:13:18 +00:00 by jared · 2 comments
Owner

Problem

The Handoff concept calls into the Dispatch concept. Handoff.unclaimed excludes handoff ids that some dispatch received. It queries Dispatch for them (handoff.rb:16). The only caller is Implementation#claim_handoff (implementation.rb:92). The edge Handoff -> Dispatch lies on 21 concept cycles. Dispatch should own the query for claimed ids.

Reproduce

n/a: structure-wave cut, nothing to reproduce

Approach

Required work:

  1. In plugins/os-sdlc/lib/os_sdlc/dispatch/queries.rb, add claimed_handoff_ids to Dispatch::Queries. It returns exclude(received_handoff_id: nil).select(:received_handoff_id). Move the comment about NOT IN and NULL with it — check: present claimed_handoff_ids in plugins/os-sdlc/lib/os_sdlc/dispatch/queries.rb
  2. In plugins/os-sdlc/lib/os_sdlc/handoff.rb, change to def unclaimed(claimed_ids) = exclude(id: claimed_ids) — check: absent Dispatch.exclude in plugins/os-sdlc/lib/os_sdlc/handoff.rb
  3. In plugins/os-sdlc/lib/os_sdlc/implementation.rb, change claim_handoff to handoffs_dataset.targeting(agent_type).unclaimed(Dispatch.claimed_handoff_ids).oldest.first — check: present claimed_handoff_ids in plugins/os-sdlc/lib/os_sdlc/implementation.rb
  4. Update the unclaimed calls in plugins/os-sdlc/tests/handoff_test.rb to pass Dispatch.claimed_handoff_ids.

Acceptance criteria

  1. Given the suite, when run after the change, then it passes with no new failures.
  2. Given the lib tree, when bin/crc-cycle-edges runs, then no edge Handoff -> Dispatch lists handoff.rb:16.
  3. Given two handoffs for one agent type and a dispatch that received the older one, when claim_handoff runs, then it returns the other handoff.
  4. Given a handoff that a dispatch received, when unclaimed runs with the claimed ids, then the handoff is not in the result.

Owner sketch

module OsSdlc::Dispatch::Queries
  def claimed_handoff_ids = exclude(received_handoff_id: nil).select(:received_handoff_id)
end

class OsSdlc::Handoff
  def unclaimed(claimed_ids) = exclude(id: claimed_ids)
end

Pinning tests: tests/handoff_test.rb, tests/pipeline/cli_subagent_start_test.rb.

Non-goals

S8 lands before S7. S8 and S7 share lib/os_sdlc/handoff.rb and tests/handoff_test.rb.

Retired tests

plugins/os-sdlc/tests/handoff_test.rb#test_unclaimed_targeting_only_includes_the_matching_implementation_and_agent_type
plugins/os-sdlc/tests/handoff_test.rb#test_a_claimed_handoff_reaches_its_receiving_dispatch_and_leaves_unclaimed

Origin

  • Trigger: os-sdlc CRC run 3, structure-ruling wave step 1 (bin/crc-cycle-edges on main 049a7820)
  • Improvised this session: none
  • Chain: concept cycle Handoff -> Dispatch (cycles_through 21) ← handoff.rb:16 ← DESIGN (docs/crc/os-sdlc/wave0/structure-rulings.tsv S7)
  • Root candidate: none found; searched Handoff.unclaimed, claimed ids, Dispatch
  • Where: plugins/os-sdlc/lib/os_sdlc/handoff.rb
  • Ledger: docs/crc/os-sdlc/ledger.tsv
  • Rulings: docs/crc/os-sdlc/wave0/structure-rulings.tsv
  • Session: 2e167079-f404-4139-9cfa-6c0c937ce9f0
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/2e167079-f404-4139-9cfa-6c0c937ce9f0.jsonl

VERDICT: CREATE

## Problem The Handoff concept calls into the Dispatch concept. `Handoff.unclaimed` excludes handoff ids that some dispatch received. It queries `Dispatch` for them (handoff.rb:16). The only caller is `Implementation#claim_handoff` (implementation.rb:92). The edge Handoff -> Dispatch lies on 21 concept cycles. `Dispatch` should own the query for claimed ids. ## Reproduce n/a: structure-wave cut, nothing to reproduce ## Approach Required work: 1. In `plugins/os-sdlc/lib/os_sdlc/dispatch/queries.rb`, add `claimed_handoff_ids` to `Dispatch::Queries`. It returns `exclude(received_handoff_id: nil).select(:received_handoff_id)`. Move the comment about NOT IN and NULL with it — check: present `claimed_handoff_ids` in `plugins/os-sdlc/lib/os_sdlc/dispatch/queries.rb` 2. In `plugins/os-sdlc/lib/os_sdlc/handoff.rb`, change to `def unclaimed(claimed_ids) = exclude(id: claimed_ids)` — check: absent `Dispatch.exclude` in `plugins/os-sdlc/lib/os_sdlc/handoff.rb` 3. In `plugins/os-sdlc/lib/os_sdlc/implementation.rb`, change `claim_handoff` to `handoffs_dataset.targeting(agent_type).unclaimed(Dispatch.claimed_handoff_ids).oldest.first` — check: present `claimed_handoff_ids` in `plugins/os-sdlc/lib/os_sdlc/implementation.rb` 4. Update the `unclaimed` calls in `plugins/os-sdlc/tests/handoff_test.rb` to pass `Dispatch.claimed_handoff_ids`. ## Acceptance criteria 1. Given the suite, when run after the change, then it passes with no new failures. 2. Given the lib tree, when `bin/crc-cycle-edges` runs, then no edge Handoff -> Dispatch lists `handoff.rb:16`. 3. Given two handoffs for one agent type and a dispatch that received the older one, when `claim_handoff` runs, then it returns the other handoff. 4. Given a handoff that a dispatch received, when `unclaimed` runs with the claimed ids, then the handoff is not in the result. ## Owner sketch ```ruby module OsSdlc::Dispatch::Queries def claimed_handoff_ids = exclude(received_handoff_id: nil).select(:received_handoff_id) end class OsSdlc::Handoff def unclaimed(claimed_ids) = exclude(id: claimed_ids) end ``` Pinning tests: `tests/handoff_test.rb`, `tests/pipeline/cli_subagent_start_test.rb`. ## Non-goals S8 lands before S7. S8 and S7 share `lib/os_sdlc/handoff.rb` and `tests/handoff_test.rb`. ## Retired tests plugins/os-sdlc/tests/handoff_test.rb#test_unclaimed_targeting_only_includes_the_matching_implementation_and_agent_type plugins/os-sdlc/tests/handoff_test.rb#test_a_claimed_handoff_reaches_its_receiving_dispatch_and_leaves_unclaimed ## Origin - Trigger: os-sdlc CRC run 3, structure-ruling wave step 1 (bin/crc-cycle-edges on main 049a7820) - Improvised this session: none - Chain: concept cycle Handoff -> Dispatch (cycles_through 21) ← handoff.rb:16 ← DESIGN (docs/crc/os-sdlc/wave0/structure-rulings.tsv S7) - Root candidate: none found; searched Handoff.unclaimed, claimed ids, Dispatch - Where: plugins/os-sdlc/lib/os_sdlc/handoff.rb - Ledger: docs/crc/os-sdlc/ledger.tsv - Rulings: docs/crc/os-sdlc/wave0/structure-rulings.tsv - Session: 2e167079-f404-4139-9cfa-6c0c937ce9f0 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/2e167079-f404-4139-9cfa-6c0c937ce9f0.jsonl VERDICT: CREATE
Author
Owner

Work started on branch crc-os-sdlc-run-3 (os-sdlc CRC run 3, structure wave step 1).

Work started on branch crc-os-sdlc-run-3 (os-sdlc CRC run 3, structure wave step 1).
Author
Owner

Resolution

Done: Handoff.unclaimed takes the claimed ids; Dispatch.claimed_handoff_ids supplies them; Implementation#claim_handoff joins the two, so handoff.rb no longer names Dispatch.

Evidence: c338c251 (runner), b134eb31 (restored scoping test); suite 2248 runs 0 failures (42.4s); rubocop on changed files clean; no Handoff -> Dispatch edge in crc-cycle-edges; inward delta 242 -> 242, only the #1174 rename pairs

Follow-ups: none

## Resolution **Done:** Handoff.unclaimed takes the claimed ids; Dispatch.claimed_handoff_ids supplies them; Implementation#claim_handoff joins the two, so handoff.rb no longer names Dispatch. **Evidence:** c338c251 (runner), b134eb31 (restored scoping test); suite 2248 runs 0 failures (42.4s); rubocop on changed files clean; no Handoff -> Dispatch edge in crc-cycle-edges; inward delta 242 -> 242, only the #1174 rename pairs **Follow-ups:** none
jared closed this issue 2026-10-19 21:20:25 +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#1171
No description provided.