Move the close family onto Ticket and Resolution #1618

Closed
opened 2026-11-06 20:06:23 +00:00 by jared · 3 comments
Owner

Problem

close, review, occurrence, and decision-sweep each apply close rules by hand. The rules differ between them, and that difference causes the defects below.

Approach

Move the rules to Ticket#close, Ticket#request_review, Ticket#record_occurrence, and Resolution. Owned rules: inventory 1.1, 1.2, and 1.8. Keep ## Resolution and **Follow-ups:** unchanged.

Required work:

  1. Add the three Ticket methods — check: present def record_occurrence in plugins/os-backlog/lib/backlog/**/*.rb
  2. Route close, close --needs-review, occurrence, and decision-sweep through Ticket.
  3. Fix inventory defect 5 in close.rb and defect 6.
  4. Fix inventory defects 14, 15, and 17.

Acceptance criteria

  1. Given a recurring ticket, when close or decision-sweep runs, then it refuses before any other check.
  2. Given a closed-out ticket with a complete Resolution, when close repeats, then it adds no comment and still closes.
  3. Given a repeat of close --needs-review, when it runs, then no second comment appears.
  4. Given a failed comment write on --needs-review, when the command ends, then the review label is absent.
  5. Given a failed comment read, when close runs, then the failure reaches the caller and no duplicate comment appears.
  6. Given no valid tracker, when decision-sweep runs, then the error names decision-sweep once.
  7. Given a bad argument, when close runs, then the error carries the same prefix as categorize.
  8. Given an occurrence on a recurring ticket, when it runs, then one comment appears and the ticket stays open.

Owner sketch

class Backlog::Ticket
  def close(resolution)
  def request_review(reason, resolution)
  def record_occurrence(resolution)
class Backlog::Tracker
  def save(ticket) # state is the last step
class Backlog::Host::Forgejo
  def close(number)

Non-goals

Do not rename a command before slice 9. Do not change ## Resolution, **Follow-ups:**, the body headings, the check form, the label names, or the issue-show JSON keys. Do not make a behavior change that this ticket does not name.

Blocking edges

Blocked by #1617

Origin

  • Trigger: port plan, section 5 of docs/system-design-format/proof/2026-11-06-os-backlog-domain-objects.md, slice 5
  • Improvised this session: none
  • Chain: os-backlog code has no domain objects ← commands own their own reads and writes ← DESIGN (ADR-0307, plugins/os-backlog/CONTEXT.md)
  • Root candidate: none found; searched close, Resolution, decision-sweep, occurrence
  • Where: plugins/os-backlog/lib/backlog/close.rb, plugins/os-backlog/lib/backlog/decision_sweep.rb, plugins/os-backlog/lib/backlog/resolution.rb
  • Session: 9d8c2e15-00c1-4dec-b177-e749fa05ec67
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/9d8c2e15-00c1-4dec-b177-e749fa05ec67.jsonl

VERDICT: CREATE

## Problem `close`, review, `occurrence`, and `decision-sweep` each apply close rules by hand. The rules differ between them, and that difference causes the defects below. ## Approach Move the rules to `Ticket#close`, `Ticket#request_review`, `Ticket#record_occurrence`, and `Resolution`. Owned rules: inventory 1.1, 1.2, and 1.8. Keep `## Resolution` and `**Follow-ups:**` unchanged. Required work: 1. Add the three `Ticket` methods — check: present `def record_occurrence` in `plugins/os-backlog/lib/backlog/**/*.rb` 2. Route `close`, `close --needs-review`, `occurrence`, and `decision-sweep` through `Ticket`. 3. Fix inventory defect 5 in `close.rb` and defect 6. 4. Fix inventory defects 14, 15, and 17. ## Acceptance criteria 1. Given a `recurring` ticket, when `close` or `decision-sweep` runs, then it refuses before any other check. 2. Given a closed-out ticket with a complete Resolution, when `close` repeats, then it adds no comment and still closes. 3. Given a repeat of `close --needs-review`, when it runs, then no second comment appears. 4. Given a failed comment write on `--needs-review`, when the command ends, then the `review` label is absent. 5. Given a failed comment read, when `close` runs, then the failure reaches the caller and no duplicate comment appears. 6. Given no valid tracker, when `decision-sweep` runs, then the error names `decision-sweep` once. 7. Given a bad argument, when `close` runs, then the error carries the same prefix as `categorize`. 8. Given an `occurrence` on a `recurring` ticket, when it runs, then one comment appears and the ticket stays open. ## Owner sketch ```ruby class Backlog::Ticket def close(resolution) def request_review(reason, resolution) def record_occurrence(resolution) class Backlog::Tracker def save(ticket) # state is the last step class Backlog::Host::Forgejo def close(number) ``` ## Non-goals Do not rename a command before slice 9. Do not change `## Resolution`, `**Follow-ups:**`, the body headings, the check form, the label names, or the `issue-show` JSON keys. Do not make a behavior change that this ticket does not name. ## Blocking edges Blocked by #1617 ## Origin - Trigger: port plan, section 5 of `docs/system-design-format/proof/2026-11-06-os-backlog-domain-objects.md`, slice 5 - Improvised this session: none - Chain: os-backlog code has no domain objects ← commands own their own reads and writes ← DESIGN (ADR-0307, `plugins/os-backlog/CONTEXT.md`) - Root candidate: none found; searched close, Resolution, decision-sweep, occurrence - Where: plugins/os-backlog/lib/backlog/close.rb, plugins/os-backlog/lib/backlog/decision_sweep.rb, plugins/os-backlog/lib/backlog/resolution.rb - Session: 9d8c2e15-00c1-4dec-b177-e749fa05ec67 - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/9d8c2e15-00c1-4dec-b177-e749fa05ec67.jsonl VERDICT: CREATE
Author
Owner

From #1615: add the state step to Tracker#save here, last in the order.

From #1615: add the state step to Tracker#save here, last in the order.
Author
Owner

Work started on branch ticket-1618.

Work started on branch ticket-1618.
Author
Owner

Resolution

Done: close, close --needs-review, occurrence, and decision-sweep run through Ticket and Resolution. State is the last step of Tracker#save. Close is deleted and Ticket::Refused replaces Close::Failed. Defects 5 (close.rb), 6, 14, 15, and 17 are fixed. After the Runner finished, I fixed a behavior change it missed: a repeat close with missing parts refuses again, with a pin.

Evidence: Implementation 254 complete, commit e0e1e358, follow-up commit on the same branch. os-backlog 497 runs on seed 19992, os-sdlc 3508 runs, ticket-takedown 623 runs (before the follow-up edit), 0 failures. This close ran on the new code.

Follow-ups: none. Lens A11 is a code defect: required work added to #1621.

## Resolution **Done:** close, close --needs-review, occurrence, and decision-sweep run through Ticket and Resolution. State is the last step of Tracker#save. Close is deleted and Ticket::Refused replaces Close::Failed. Defects 5 (close.rb), 6, 14, 15, and 17 are fixed. After the Runner finished, I fixed a behavior change it missed: a repeat close with missing parts refuses again, with a pin. **Evidence:** Implementation 254 complete, commit e0e1e358, follow-up commit on the same branch. os-backlog 497 runs on seed 19992, os-sdlc 3508 runs, ticket-takedown 623 runs (before the follow-up edit), 0 failures. This close ran on the new code. **Follow-ups:** none. Lens A11 is a code defect: required work added to #1621.
jared closed this issue 2026-11-06 23:20:43 +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#1618
No description provided.