Require exactly one category per ticket at capture and refuse non-code-change in implement #973

Closed
opened 2026-10-09 17:30:53 +00:00 by jared · 2 comments
Owner

Problem

Tickets have no category, so a non-code ticket (prose, owner ruling, spike, eval run) can enter an implement map and fail there. The owner ruled on 2026-10-09 (handoff docs/handoffs/2026-10-09-takedown-implement-path.md, ruling 4) that capture requires exactly one category and that both implement maps accept only code-change.

Reproduce

n/a: feature ticket.

Approach

Handoff build-order step 7. Categories (one per ticket): code-change, prose-artifact, owner-ruling, investigation, eval-run, no-test-target, cross-repo, umbrella, recurring-chore. A ticket that fits two is an umbrella: split it. Run /os-adr:find and the lens-taxonomy-decisions test to decide whether the rule needs an ADR.

Required work:

  1. issue-create refuses a ticket without exactly one category label — check: present umbrella in plugins/os-backlog/**/*.rb
  2. /os-backlog:capture skill text lists the nine categories.
  3. Backfill categories on open tickets from the triage JSON ({number, category, target, failing_behavior, reason}).
  4. implementation-open for poodr-ticket-implementation and takedown-implement refuses a ticket whose category is not code-change.

Orchestrator work: the backfill touches about 181 tracker labels; run it through a script, not by hand.

Acceptance criteria

  1. Given issue-create with no category label, when it runs, then it refuses and names the nine categories.
  2. Given issue-create with two category labels, when it runs, then it refuses.
  3. Given a ticket in category prose-artifact, when implementation-open runs on either map, then it refuses with the category named.
  4. Given a code-change ticket, when implementation-open runs, then it proceeds.

Owner sketch

class Backlog::TicketCategory
  def self.fetch(labels)
end

Origin

  • Trigger: Owner rulings of 2026-10-09 recorded in docs/handoffs/2026-10-09-takedown-implement-path.md.
  • Improvised this session: none
  • Chain: takedown design ends at a sketch ← ADR-0276 §5 and §9 (DESIGN, docs/adr/0276-ticket-takedown-runs-one-pipeline-the-eval-harness-flow-is-the-production-pipeline-live-mode.md)
  • Root candidate: none
  • Where: plugins/os-sdlc/eval/ticket-takedown/, plugins/os-sdlc/maps/, plugins/os-sdlc/skills/implement/SKILL.md
  • Session: 58499175-8e67-4b3a-8cfe-ed601216e8da
  • Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-prism-architect/58499175-8e67-4b3a-8cfe-ed601216e8da.jsonl

VERDICT: CREATE

## Problem Tickets have no category, so a non-code ticket (prose, owner ruling, spike, eval run) can enter an implement map and fail there. The owner ruled on 2026-10-09 (handoff `docs/handoffs/2026-10-09-takedown-implement-path.md`, ruling 4) that capture requires exactly one category and that both implement maps accept only `code-change`. ## Reproduce n/a: feature ticket. ## Approach Handoff build-order step 7. Categories (one per ticket): `code-change`, `prose-artifact`, `owner-ruling`, `investigation`, `eval-run`, `no-test-target`, `cross-repo`, `umbrella`, `recurring-chore`. A ticket that fits two is an `umbrella`: split it. Run `/os-adr:find` and the lens-taxonomy-decisions test to decide whether the rule needs an ADR. Required work: 1. `issue-create` refuses a ticket without exactly one category label — check: present `umbrella` in `plugins/os-backlog/**/*.rb` 2. `/os-backlog:capture` skill text lists the nine categories. 3. Backfill categories on open tickets from the triage JSON (`{number, category, target, failing_behavior, reason}`). 4. `implementation-open` for `poodr-ticket-implementation` and `takedown-implement` refuses a ticket whose category is not `code-change`. Orchestrator work: the backfill touches about 181 tracker labels; run it through a script, not by hand. ## Acceptance criteria 1. Given `issue-create` with no category label, when it runs, then it refuses and names the nine categories. 2. Given `issue-create` with two category labels, when it runs, then it refuses. 3. Given a ticket in category `prose-artifact`, when `implementation-open` runs on either map, then it refuses with the category named. 4. Given a `code-change` ticket, when `implementation-open` runs, then it proceeds. ## Owner sketch ```ruby class Backlog::TicketCategory def self.fetch(labels) end ``` ## Origin - Trigger: Owner rulings of 2026-10-09 recorded in `docs/handoffs/2026-10-09-takedown-implement-path.md`. - Improvised this session: none - Chain: takedown design ends at a sketch ← ADR-0276 §5 and §9 (DESIGN, `docs/adr/0276-ticket-takedown-runs-one-pipeline-the-eval-harness-flow-is-the-production-pipeline-live-mode.md`) - Root candidate: none - Where: `plugins/os-sdlc/eval/ticket-takedown/`, `plugins/os-sdlc/maps/`, `plugins/os-sdlc/skills/implement/SKILL.md` - Session: 58499175-8e67-4b3a-8cfe-ed601216e8da - Transcript: /home/jared/.claude/projects/-home-jared-dev-cc-os--claude-worktrees-prism-architect/58499175-8e67-4b3a-8cfe-ed601216e8da.jsonl VERDICT: CREATE
Author
Owner

Work started on branch ticket-973 (worktree .claude/worktrees/ticket-973, from main 03a44f31). ADR-0287 amends ADR-0234.

Rulings binding this work:

  • R1: JSON corrected before backfill: #116, #226, #349, #131 -> no-test-target; #946 -> umbrella; #738 stays code-change.
  • R2: labels are prefixed category/; category joins RESERVED_PREFIXES so the scope gate ignores them.
  • R3: implementation-open refuses a ticket with no category too (no exemption). Backfill runs before the check goes live (no merge, no refresh-plugins until then).
  • R4: no new fetch_labels method; the tracker returns the ticket (body + labels) and implementation-open reads the category from it.
Work started on branch ticket-973 (worktree .claude/worktrees/ticket-973, from main 03a44f31). ADR-0287 amends ADR-0234. Rulings binding this work: - R1: JSON corrected before backfill: #116, #226, #349, #131 -> no-test-target; #946 -> umbrella; #738 stays code-change. - R2: labels are prefixed category/<name>; category joins RESERVED_PREFIXES so the scope gate ignores them. - R3: implementation-open refuses a ticket with no category too (no exemption). Backfill runs before the check goes live (no merge, no refresh-plugins until then). - R4: no new fetch_labels method; the tracker returns the ticket (body + labels) and implementation-open reads the category from it.
Author
Owner

Resolution

Done: Every open ticket carries one category/* label (190 of 191; #982 is new and uncategorized); implementation-open refuses a non-code-change ticket on all three implementation maps; 30 more categories recorded in docs/triage/2026-10-09-ticket-categories.json.

Evidence: main 0e281f66: os-sdlc 1524 runs 0 failures, os-backlog 302 runs 0 failures, ticket-takedown 480 runs 0 failures; label counts verified through Backlog::ForgejoBackend.list.

Follow-ups: none

## Resolution **Done:** Every open ticket carries one category/* label (190 of 191; #982 is new and uncategorized); implementation-open refuses a non-code-change ticket on all three implementation maps; 30 more categories recorded in docs/triage/2026-10-09-ticket-categories.json. **Evidence:** main 0e281f66: os-sdlc 1524 runs 0 failures, os-backlog 302 runs 0 failures, ticket-takedown 480 runs 0 failures; label counts verified through Backlog::ForgejoBackend.list. **Follow-ups:** none
jared closed this issue 2026-10-10 13:55:27 +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#973
No description provided.