cc-os/plugins/os-backlog/lib/backlog/triage_check.rb

47 lines
2.1 KiB
Ruby

module Backlog
# Pure decision for the triage-trigger SessionStart hook (card
# 1818330518584820864): given the label arrays already sitting on a
# board's Backlog-column cards, does the hook need to instruct dispatch
# of the card-triage agent? Network/board-fetch stays in the hook
# script (hooks/triage_check.rb) — this class only classifies +
# composes the note text, so the decision is unit-testable without
# Planka.
#
# "Unlabeled" mirrors card-triage's own definition (agents/card-triage.md):
# a card is raw if it is missing a priority label (P0-P3) OR an
# autonomy label (hitl/semi/afk-ready) — not just totally bare.
class TriageCheck
PRIORITY_LABELS = %w[P0 P1 P2 P3].freeze
AUTONOMY_LABELS = %w[hitl semi afk-ready].freeze
# @param labels [Array<String>] the label names on one card
# @return [Boolean]
def self.needs_triage?(labels)
(labels & PRIORITY_LABELS).empty? || (labels & AUTONOMY_LABELS).empty?
end
# @param backlog_cards_labels [Array<Array<String>>] label arrays,
# one per card currently in the board's Backlog list
# @return [Array<Array<String>>] the subset needing triage
def self.unlabeled(backlog_cards_labels)
backlog_cards_labels.select { |labels| needs_triage?(labels) }
end
# @param board_name [String]
# @param backlog_cards_labels [Array<Array<String>>]
# @return [String, nil] the SessionStart additionalContext note, or
# nil when there is nothing to triage
def self.note_for(board_name, backlog_cards_labels)
count = unlabeled(backlog_cards_labels).size
return nil if count.zero?
card_word = count == 1 ? "card" : "cards"
"[os-backlog] #{count} unlabeled Backlog #{card_word} on board #{board_name} -> " \
"dispatch the card-triage agent now (model: haiku, run in background) to label " \
"them. Labeling is this project's job for its own board (a parent umbrella may " \
"also label its child boards) — never label cards on a board that belongs to a " \
"different project."
end
end
end