Some checks failed
Deploy Development / deploy (push) Successful in 47s
Test Suite / pytest-backend (push) Failing after 4m15s
Test Suite / k6 /api/health Baseline (push) Has been skipped
Test Suite / playwright-smoke (push) Has been skipped
Test Suite / lint-backend (push) Successful in 2s
Test Suite / compose-smoke (push) Has been skipped
K-Ext-4/P8 deklarative Agent-Slots; P7 tech_debt Read Model und Vokabular; Review-Attention in den Kernel verlagert. Co-authored-by: Cursor <cursoragent@cursor.com>
89 lines
2.9 KiB
Python
89 lines
2.9 KiB
Python
"""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,
|
|
}
|