"""Tech debt summary read model — P7.""" from __future__ import annotations from datetime import datetime, timedelta, timezone from typing import Any from steering.eval_context import SteeringEvalContext _OPEN_BACKLOG = frozenset({"new", "triaged", "accepted"}) _OPEN_ACTION = frozenset({"open", "ready", "in_progress", "blocked", "review_required"}) def _parse_ts(value: Any) -> datetime | None: if not value: return None if isinstance(value, datetime): return value if value.tzinfo else value.replace(tzinfo=timezone.utc) try: text = str(value).replace("Z", "+00:00") parsed = datetime.fromisoformat(text) return parsed if parsed.tzinfo else parsed.replace(tzinfo=timezone.utc) except ValueError: return None def compute_tech_debt_summary(ctx: SteeringEvalContext) -> dict[str, Any]: vocabulary = ctx.backlog_vocabulary if "tech_debt" not in (vocabulary.get("kinds") or []): return { "enabled": False, "backlog_items": [], "actions": [], "total_open": 0, "stale_count": 0, } stale_days = int(ctx.agent_slot_config.get("stale_debt_days") or 30) cutoff = datetime.now(timezone.utc) - timedelta(days=stale_days) backlog_items: list[dict[str, Any]] = [] for item in ctx.backlog_items: if item.get("item_kind") != "tech_debt": continue if item.get("status") not in _OPEN_BACKLOG: continue created = _parse_ts(item.get("created_at")) stale = created is not None and created < cutoff backlog_items.append( { "id": str(item["id"]), "title": item.get("title") or "Technische Schuld", "status": item.get("status"), "stale": stale, "created_at": item.get("created_at"), } ) actions: list[dict[str, Any]] = [] for action in ctx.actions: if action.get("action_kind") != "tech_debt": continue if action.get("status") not in _OPEN_ACTION: continue created = _parse_ts(action.get("created_at")) stale = created is not None and created < cutoff actions.append( { "id": str(action["id"]), "title": action.get("title") or "Technische Schuld", "status": action.get("status"), "stale": stale, "created_at": action.get("created_at"), } ) stale_count = sum(1 for row in backlog_items if row["stale"]) + sum( 1 for row in actions if row["stale"] ) return { "enabled": True, "backlog_items": backlog_items, "actions": actions, "total_open": len(backlog_items) + len(actions), "stale_count": stale_count, "stale_days": stale_days, }