Turn the issue-create gates into Ticket validations #1620

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

Problem

The create gates live in their own classes and run outside the ticket they check. --label next and a second priority label pass them, although next is human-only (ADR-0042).

Approach

Move the eight gates to Ticket validations on create only, in the same order. Host#labels? replaces the four repo: checks in submission.rb. Owned rules: inventory 1.5, 1.6, and 1.9. Keep the number key in the issue-create output.

Required work:

  1. Add Ticket.create and Ticket.create! — check: present def self.create in plugins/os-backlog/lib/backlog/**/*.rb
  2. Move the eight gates to validations on the create context.
  3. Route issue-create through Ticket.
  4. Fix inventory defect 11.

Acceptance criteria

  1. Given a body that fails two gates, when issue-create runs, then the first failure is the same one that appears before the port.
  2. Given a repo: tracker, when issue-create runs, then the scope, category, and filed-by validations skip it.
  3. Given --label next, when issue-create runs, then it refuses.
  4. Given --label P0 with --priority P1, when issue-create runs, then it refuses.
  5. Given --priority P2, when the ticket is created, then P2 is the first label.
  6. Given issue-edit on an old ticket that fails a gate, when it runs, then it succeeds.

Owner sketch

class Backlog::Ticket
  def self.create(tracker:, **attributes)
  def self.create!(tracker:, **attributes)
  validate :gate, on: :create
class Backlog::Tracker
  def create(ticket)
class Backlog::Host::Forgejo
  def create(title:, body:, labels:)

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 #1619

Origin

  • Trigger: port plan, section 5 of docs/system-design-format/proof/2026-11-06-os-backlog-domain-objects.md, slice 7
  • 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 issue-create gates, IssueDraft, label next, priority
  • Where: plugins/os-backlog/lib/backlog/issue_create.rb, plugins/os-backlog/lib/backlog/issue_create/, plugins/os-backlog/lib/backlog/issue_draft.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 The create gates live in their own classes and run outside the ticket they check. `--label next` and a second priority label pass them, although `next` is human-only (ADR-0042). ## Approach Move the eight gates to `Ticket` validations on create only, in the same order. `Host#labels?` replaces the four `repo:` checks in `submission.rb`. Owned rules: inventory 1.5, 1.6, and 1.9. Keep the `number` key in the `issue-create` output. Required work: 1. Add `Ticket.create` and `Ticket.create!` — check: present `def self.create` in `plugins/os-backlog/lib/backlog/**/*.rb` 2. Move the eight gates to validations on the create context. 3. Route `issue-create` through `Ticket`. 4. Fix inventory defect 11. ## Acceptance criteria 1. Given a body that fails two gates, when `issue-create` runs, then the first failure is the same one that appears before the port. 2. Given a `repo:` tracker, when `issue-create` runs, then the scope, category, and filed-by validations skip it. 3. Given `--label next`, when `issue-create` runs, then it refuses. 4. Given `--label P0` with `--priority P1`, when `issue-create` runs, then it refuses. 5. Given `--priority P2`, when the ticket is created, then `P2` is the first label. 6. Given `issue-edit` on an old ticket that fails a gate, when it runs, then it succeeds. ## Owner sketch ```ruby class Backlog::Ticket def self.create(tracker:, **attributes) def self.create!(tracker:, **attributes) validate :gate, on: :create class Backlog::Tracker def create(ticket) class Backlog::Host::Forgejo def create(title:, body:, labels:) ``` ## 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 #1619 ## Origin - Trigger: port plan, section 5 of `docs/system-design-format/proof/2026-11-06-os-backlog-domain-objects.md`, slice 7 - 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 issue-create gates, IssueDraft, label next, priority - Where: plugins/os-backlog/lib/backlog/issue_create.rb, plugins/os-backlog/lib/backlog/issue_create/, plugins/os-backlog/lib/backlog/issue_draft.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 #857: cli_issue_create_scope_gate_test status_for passes no fake client, so it sends a real GET to Forgejo. Give it a FakeForgejoClient when this slice touches the gates.

From #857: cli_issue_create_scope_gate_test status_for passes no fake client, so it sends a real GET to Forgejo. Give it a FakeForgejoClient when this slice touches the gates.
Author
Owner

Work started on branch ticket-1620.

Work started on branch ticket-1620.
Author
Owner

Resolution

Done: issue-create runs through Ticket.create and Ticket.create!. The eight gates, next, and the priority rules live in Ticket::CreateGates on the Ticket::Draft create context, in the old first-failure order. Host#labels? replaces the repo: checks, and Host#create joins the role on every host, including Memory. Defect 11 is fixed. Body and LabelSet moved under Ticket; Submission and IssueCreate::Refused are deleted.

Evidence: main 5a9cf4a7 (Runner commit 6b7e1380, corrections 183f3c64). On main: os-backlog 524 runs 0 failures, os-sdlc 3502 runs 0 failures. Takedown suite 623 runs 0 failures before the merge of main, which changed only os-git. Implementation 256. Two output changes stay and are recorded in 183f3c64: the issue-create prefix on a MissingToken during the scope-name read, and one write of a repeated label on a passing ticket.

Follow-ups: #1621 takes the lens A15 and A12 work (delete IssueDraft and IssueCreate). Regenerating plugins/os-backlog/design/generated: comment on #1624.

## Resolution **Done:** issue-create runs through Ticket.create and Ticket.create!. The eight gates, next, and the priority rules live in Ticket::CreateGates on the Ticket::Draft create context, in the old first-failure order. Host#labels? replaces the repo: checks, and Host#create joins the role on every host, including Memory. Defect 11 is fixed. Body and LabelSet moved under Ticket; Submission and IssueCreate::Refused are deleted. **Evidence:** main 5a9cf4a7 (Runner commit 6b7e1380, corrections 183f3c64). On main: os-backlog 524 runs 0 failures, os-sdlc 3502 runs 0 failures. Takedown suite 623 runs 0 failures before the merge of main, which changed only os-git. Implementation 256. Two output changes stay and are recorded in 183f3c64: the issue-create prefix on a MissingToken during the scope-name read, and one write of a repeated label on a passing ticket. **Follow-ups:** #1621 takes the lens A15 and A12 work (delete IssueDraft and IssueCreate). Regenerating plugins/os-backlog/design/generated: comment on #1624.
jared closed this issue 2026-11-07 07:48:45 +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#1620
No description provided.