IssueCreate drops its svc dependency; the CLI helper words the scope-label refusal lazily #777

Open
opened 2026-09-27 16:13:29 +00:00 by jared · 0 comments
Owner

Problem

Backlog::IssueCreate (ADR-0234) takes a svc: argument whose only use is scope_label_names, which words the scope-label refusal message.
No decision in the validator depends on the tracker service.
The deciding object therefore changes when the tracker service changes, which breaks lens heuristic A11.
The contract-auditor on #765 proposed a lens edit; the lens challenge on 2026-09-27 ruled the heuristic holds and the code is at fault.

Approach

IssueCreate raises Backlog::IssueCreate::MissingScopeLabel < Refused with the message body only.
The CLI helper validate_issue_create rescues MissingScopeLabel before the generic Refused rescue and appends the available scope labels, fetched lazily from ctx[:svc] only when this refusal fires.
scope_label_names moves back to cli_command_helpers.rb with its CommandFailed rescue.
IssueCreate.new takes tracker: only.

Required work:

  1. Add Backlog::IssueCreate::MissingScopeLabel in plugins/os-backlog/lib/backlog/issue_create/missing_scope_label.rb and raise it from the scope-label check.
  2. Rescue MissingScopeLabel in validate_issue_create and append the lazily fetched label list.
  3. Remove svc from IssueCreate.

Rejected: editing lens heuristic A11 with a NOT clause — the challenge found the cost named by the proposal belongs to an eager design nobody needs.

Acceptance criteria

  1. Given no scope label, when issue-create runs on a forgejo tracker, then the refusal names the available scope labels, as today.
  2. Given Backlog::IssueCreate.new(tracker: "forgejo:x/y") with no svc:, when validate! runs on a compliant body, then it passes.

Owner sketch

class Backlog::IssueCreate
  MissingScopeLabel = Class.new(Refused)
  def initialize(tracker:)
  end
end

Origin

  • Trigger: LENS line from contract-auditor dispatch 556, implementation 53 (#765), 2026-09-27; challenged by an opus lens-challenge agent
  • Improvised this session: none
  • Chain: validator depends on tracker service ← refusal message formatting placed inside the deciding object ← DESIGN (plugins/os-backlog/lib/backlog/issue_create.rb, ADR-0234)
  • Root candidate: this ticket
  • Where: plugins/os-backlog/lib/backlog/issue_create.rb, cli_command_helpers.rb
  • Session: 17688436-99ef-4a59-9eec-74e4f87e9c1f
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/17688436-99ef-4a59-9eec-74e4f87e9c1f.jsonl

VERDICT: CREATE
REASON: Root-cause fix confirmed by lens-challenge (code defect, heuristic holds), Origin chain ends in DESIGN not IMPROVISATION, this ticket is the named root, and it is the only ticket touching this file this session.

## Problem `Backlog::IssueCreate` (ADR-0234) takes a `svc:` argument whose only use is `scope_label_names`, which words the scope-label refusal message. No decision in the validator depends on the tracker service. The deciding object therefore changes when the tracker service changes, which breaks lens heuristic A11. The contract-auditor on #765 proposed a lens edit; the lens challenge on 2026-09-27 ruled the heuristic holds and the code is at fault. ## Approach `IssueCreate` raises `Backlog::IssueCreate::MissingScopeLabel < Refused` with the message body only. The CLI helper `validate_issue_create` rescues `MissingScopeLabel` before the generic `Refused` rescue and appends the available scope labels, fetched lazily from `ctx[:svc]` only when this refusal fires. `scope_label_names` moves back to `cli_command_helpers.rb` with its `CommandFailed` rescue. `IssueCreate.new` takes `tracker:` only. Required work: 1. Add `Backlog::IssueCreate::MissingScopeLabel` in plugins/os-backlog/lib/backlog/issue_create/missing_scope_label.rb and raise it from the scope-label check. 2. Rescue `MissingScopeLabel` in `validate_issue_create` and append the lazily fetched label list. 3. Remove `svc` from `IssueCreate`. Rejected: editing lens heuristic A11 with a NOT clause — the challenge found the cost named by the proposal belongs to an eager design nobody needs. ## Acceptance criteria 1. Given no scope label, when issue-create runs on a forgejo tracker, then the refusal names the available scope labels, as today. 2. Given `Backlog::IssueCreate.new(tracker: "forgejo:x/y")` with no `svc:`, when `validate!` runs on a compliant body, then it passes. ## Owner sketch ```ruby class Backlog::IssueCreate MissingScopeLabel = Class.new(Refused) def initialize(tracker:) end end ``` ## Origin - Trigger: LENS line from contract-auditor dispatch 556, implementation 53 (#765), 2026-09-27; challenged by an opus lens-challenge agent - Improvised this session: none - Chain: validator depends on tracker service ← refusal message formatting placed inside the deciding object ← DESIGN (plugins/os-backlog/lib/backlog/issue_create.rb, ADR-0234) - Root candidate: this ticket - Where: plugins/os-backlog/lib/backlog/issue_create.rb, cli_command_helpers.rb - Session: 17688436-99ef-4a59-9eec-74e4f87e9c1f - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os/17688436-99ef-4a59-9eec-74e4f87e9c1f.jsonl VERDICT: CREATE REASON: Root-cause fix confirmed by lens-challenge (code defect, heuristic holds), Origin chain ends in DESIGN not IMPROVISATION, this ticket is the named root, and it is the only ticket touching this file this session.
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#777
No description provided.