Declare the dispatch preload on the association and delete Dispatch.for_summary #816

Closed
opened 2026-09-28 21:17:44 +00:00 by jared · 2 comments
Owner

Problem

Dispatch.for_summary is named for its one caller, not for what it returns. It returns every dispatch of an implementation, sorted by id, with three associations preloaded. It does not filter anything. The preload list is knowledge about the implementation's dispatches, but it lives in a dataset method on Dispatch. .oldest repeats the order: :id that the association already declares.

lib/os_sdlc/model/dispatch/queries.rb:9          def for_summary = eager(:agent, :step_results, :created_handoff).oldest
lib/os_sdlc/presenter/implementation/summary.rb:12  @dispatches = implementation.dispatches_dataset.for_summary.all
lib/os_sdlc/model/implementation.rb:7            one_to_many :dispatches, class: "OsSdlc::Dispatch", key: :implementation_id, order: :id

Reproduce

n/a: refactor with no behavior change.

Approach

Declare the preload on the association with Sequel's eager: association option. The presenter reads implementation.dispatches. Delete for_summary.

# model/implementation.rb
one_to_many :dispatches, class: "OsSdlc::Dispatch", key: :implementation_id, order: :id,
                         eager: %i[agent step_results created_handoff]

# presenter/implementation/summary.rb
@dispatches = implementation.dispatches

The eager: option applies only when code loads the cached association implementation.dispatches. It does not apply to dispatches_dataset. No code under lib/ calls implementation.dispatches today, so the summary presenter is the only reader that pays for the preload.

Required work:

  1. Add eager: %i[agent step_results created_handoff] to one_to_many :dispatches in model/implementation.rb — check: cd plugins/os-sdlc && grep -n "eager: %i\[agent step_results created_handoff\]" lib/os_sdlc/model/implementation.rb
  2. Change presenter/implementation/summary.rb to read implementation.dispatches — check: cd plugins/os-sdlc && grep -c "for_summary" lib/os_sdlc/presenter/implementation/summary.rb prints 0
  3. Delete for_summary from model/dispatch/queries.rb — check: cd plugins/os-sdlc && grep -rc "for_summary" lib | grep -v ":0" prints nothing

Rejected: a query-count test that pins the eager list on for_summary — it tests where the preload lives, not what the summary shows. Rejected: an Implementation#summary_dispatches or #dispatch_summary method — both name the reader, and DispatchSummary already exists as the presenter that takes these dispatches.

Acceptance criteria

  1. Given an implementation with dispatches, when Implementation#summary runs, then it lists the same dispatches in the same id order, with the same agent, step, and handoff fields, as before.
  2. Given an implementation with no dispatches, when Implementation#summary runs, then it returns an empty dispatch list, as before.

Owner sketch

class Implementation < Sequel::Model
  one_to_many :dispatches, ..., order: :id, eager: %i[agent step_results created_handoff]
end

class Implementation::Summary
  def initialize(implementation)
    @dispatches = implementation.dispatches
end

Origin

  • Trigger: review of item 10 in /tmp/os-sdlc-sequel-handoff.md; the user ruled that a query-count test answered a question that exists only because the code is in the wrong place
  • Improvised this session: none
  • Chain: proposed query-count test ← preload list named for its reader and far from the rows it loads ← DESIGN (lib/os_sdlc/model/dispatch/queries.rb)
  • Root candidate: none
  • Where: lib/os_sdlc/model/dispatch/queries.rb, lib/os_sdlc/presenter/implementation/summary.rb, lib/os_sdlc/model/implementation.rb
  • Session: 82d3162b-0035-4225-ad81-3dc5c0e11a47
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-sequel-runner/82d3162b-0035-4225-ad81-3dc5c0e11a47.jsonl
## Problem `Dispatch.for_summary` is named for its one caller, not for what it returns. It returns every dispatch of an implementation, sorted by id, with three associations preloaded. It does not filter anything. The preload list is knowledge about the implementation's dispatches, but it lives in a dataset method on `Dispatch`. `.oldest` repeats the `order: :id` that the association already declares. ``` lib/os_sdlc/model/dispatch/queries.rb:9 def for_summary = eager(:agent, :step_results, :created_handoff).oldest lib/os_sdlc/presenter/implementation/summary.rb:12 @dispatches = implementation.dispatches_dataset.for_summary.all lib/os_sdlc/model/implementation.rb:7 one_to_many :dispatches, class: "OsSdlc::Dispatch", key: :implementation_id, order: :id ``` ## Reproduce n/a: refactor with no behavior change. ## Approach Declare the preload on the association with Sequel's `eager:` association option. The presenter reads `implementation.dispatches`. Delete `for_summary`. ```ruby # model/implementation.rb one_to_many :dispatches, class: "OsSdlc::Dispatch", key: :implementation_id, order: :id, eager: %i[agent step_results created_handoff] # presenter/implementation/summary.rb @dispatches = implementation.dispatches ``` The `eager:` option applies only when code loads the cached association `implementation.dispatches`. It does not apply to `dispatches_dataset`. No code under `lib/` calls `implementation.dispatches` today, so the summary presenter is the only reader that pays for the preload. Required work: 1. Add `eager: %i[agent step_results created_handoff]` to `one_to_many :dispatches` in `model/implementation.rb` — check: `cd plugins/os-sdlc && grep -n "eager: %i\[agent step_results created_handoff\]" lib/os_sdlc/model/implementation.rb` 2. Change `presenter/implementation/summary.rb` to read `implementation.dispatches` — check: `cd plugins/os-sdlc && grep -c "for_summary" lib/os_sdlc/presenter/implementation/summary.rb` prints 0 3. Delete `for_summary` from `model/dispatch/queries.rb` — check: `cd plugins/os-sdlc && grep -rc "for_summary" lib | grep -v ":0"` prints nothing Rejected: a query-count test that pins the `eager` list on `for_summary` — it tests where the preload lives, not what the summary shows. Rejected: an `Implementation#summary_dispatches` or `#dispatch_summary` method — both name the reader, and `DispatchSummary` already exists as the presenter that takes these dispatches. ## Acceptance criteria 1. Given an implementation with dispatches, when `Implementation#summary` runs, then it lists the same dispatches in the same id order, with the same agent, step, and handoff fields, as before. 2. Given an implementation with no dispatches, when `Implementation#summary` runs, then it returns an empty dispatch list, as before. ## Owner sketch ```ruby class Implementation < Sequel::Model one_to_many :dispatches, ..., order: :id, eager: %i[agent step_results created_handoff] end class Implementation::Summary def initialize(implementation) @dispatches = implementation.dispatches end ``` ## Origin - Trigger: review of item 10 in /tmp/os-sdlc-sequel-handoff.md; the user ruled that a query-count test answered a question that exists only because the code is in the wrong place - Improvised this session: none - Chain: proposed query-count test ← preload list named for its reader and far from the rows it loads ← DESIGN (`lib/os_sdlc/model/dispatch/queries.rb`) - Root candidate: none - Where: lib/os_sdlc/model/dispatch/queries.rb, lib/os_sdlc/presenter/implementation/summary.rb, lib/os_sdlc/model/implementation.rb - Session: 82d3162b-0035-4225-ad81-3dc5c0e11a47 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-sequel-runner/82d3162b-0035-4225-ad81-3dc5c0e11a47.jsonl
Author
Owner

Work started on branch ticket-816 (os-sdlc implementation, coding map).

Work started on branch ticket-816 (os-sdlc implementation, coding map).
Author
Owner

Resolution

Done: one_to_many :dispatches on Implementation now declares eager: %i[agent step_results created_handoff]. Implementation::Summary reads implementation.dispatches. Dispatch.for_summary deleted.

Evidence: Commit cf8d8873 on branch ticket-816. os-sdlc implementation 70 (coding map): programmer gate diff-test+lint pass (dispatch 704), reviewer pass (705), suite gate pass in 17.9 s (706). tests/presenter/implementation/summary_test.rb covers both criteria.

Follow-ups: 1. Reviewer: implementation.dispatches caches after first load; only the summary reads it today; dropped, no current reader at risk. 2. A stray plugins/os-sdlc/lib/os_sdlc/.sdlc/ (pipeline.db plus a 0-byte pipeline.db.stale) appeared during the run; evidence for the fresh-db-archived-to-stale defect, recorded in the session handoff, ticket to follow.

## Resolution **Done:** one_to_many :dispatches on Implementation now declares eager: %i[agent step_results created_handoff]. Implementation::Summary reads implementation.dispatches. Dispatch.for_summary deleted. **Evidence:** Commit cf8d8873 on branch ticket-816. os-sdlc implementation 70 (coding map): programmer gate diff-test+lint pass (dispatch 704), reviewer pass (705), suite gate pass in 17.9 s (706). tests/presenter/implementation/summary_test.rb covers both criteria. **Follow-ups:** 1. Reviewer: implementation.dispatches caches after first load; only the summary reads it today; dropped, no current reader at risk. 2. A stray plugins/os-sdlc/lib/os_sdlc/.sdlc/ (pipeline.db plus a 0-byte pipeline.db.stale) appeared during the run; evidence for the fresh-db-archived-to-stale defect, recorded in the session handoff, ticket to follow.
jared closed this issue 2026-09-28 21:20:35 +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#816
No description provided.