"""Intake triage proposal — queue_inbox / continuous backlog (no sprint).""" from __future__ import annotations from typing import Any from steering.eval_context import SteeringEvalContext COMMITTABLE = frozenset({"new", "triaged", "accepted"}) _PRIORITY = {"critical": 0, "high": 1, "normal": 2, "low": 3} _QUEUE_KIND_BIAS = {"bug": 0, "issue": 1, "incident": 1, "story": 2, "idea": 3} def propose_intake_triage( ctx: SteeringEvalContext, *, read_models: dict[str, Any] | None = None, ) -> list[dict[str, Any]]: vocabulary = ctx.backlog_vocabulary convertible = frozenset(vocabulary.get("convertible_kinds") or ["story", "bug", "issue"]) queue_mode = "queue_inbox" in ctx.steering_elements candidates = [ item for item in ctx.backlog_items if item.get("status") in COMMITTABLE and item.get("item_kind") != "epic" and (item.get("item_kind") or "story") in convertible ] if not candidates: return [] def sort_key(item: dict[str, Any]) -> tuple: kind = item.get("item_kind") or "story" kind_bias = _QUEUE_KIND_BIAS.get(kind, 5) if queue_mode else 5 return ( _PRIORITY.get(item.get("priority") or "normal", 9), kind_bias, item.get("sort_order") if item.get("sort_order") is not None else 9999, ) proposals: list[dict[str, Any]] = [] for rank, item in enumerate(sorted(candidates, key=sort_key)[:20], start=1): kind = item.get("item_kind") or "story" proposals.append( { "proposal_key": "intake_triage", "scope_type": "backlog_item", "scope_id": str(item["id"]), "rank": rank, "reason_code": "intake_triage_candidate", "summary": "Triage-Kandidat (Heuristik — Ranker austauschbar)", "title": item.get("title") or "Backlog-Item", "item_kind": kind, "priority": item.get("priority") or "normal", "initiative_id": ctx.initiative_id, "ranker_key": "heuristic_v0", "confidence": "heuristic", "factors": [ { "code": "priority", "weight": _PRIORITY.get(item.get("priority") or "normal", 9), "label": "Priorität", } ], "dependency_refs": [], "dependency_blocked": False, "data_source": "steering_kernel", } ) return proposals def intake_triage_attention_items( *, initiative_id: str, proposals: list[dict[str, Any]], ) -> list[dict[str, Any]]: if not proposals: return [] return [ { "kind": "intake_triage_suggested", "severity": "info", "title": "Eingang triagieren", "summary": f"{len(proposals)} Item(s) — Kernel schlägt Triage-Reihenfolge vor", "scope_type": "initiative", "scope_id": initiative_id, "initiative_id": initiative_id, "reason_code": "intake_triage_suggested", "data_source": "intake_triage", } ]