From 908ce3f703f3f4034d88ccbecef9c1e6f05043a7 Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Tue, 8 Sep 2026 22:14:27 +0200 Subject: [PATCH] refactor(scan): separate todo2code suggestion mapping --- project/ticket-118/README.md | 25 +++++++++++ project/ticket-118/intent.json | 29 +++++++++++++ src/koru/scan.py | 78 ++++++++++++++++++---------------- 3 files changed, 96 insertions(+), 36 deletions(-) create mode 100644 project/ticket-118/README.md create mode 100644 project/ticket-118/intent.json diff --git a/project/ticket-118/README.md b/project/ticket-118/README.md new file mode 100644 index 00000000..f20747f5 --- /dev/null +++ b/project/ticket-118/README.md @@ -0,0 +1,25 @@ +# Ticket 118: Separate todo2code scan suggestion mapping + +- **ID**: ticket-118 +- **Owner**: unresolved:human +- **Status**: IN_PROGRESS +- **Workflow state**: EDIT +- **Created**: 2026-09-08 + +SESSION_EXECUTION_AUTHORIZATION: User requested continued refactoring, GitHub publication, deployment and testing. + +AC-01: Extract conversion of one useful todo2code plan into a suggestion while +preserving usefulness checks, path bounds, truncation, priority normalization, +dedupe evidence and labels. + +## Acceptance criteria + +- [ ] AC-01: Scan output remains identical and the orchestration is simpler. + +Validation: 15 focused tests, Koru-driven regressions, Ruff, managed +governance, Docker Compose and compileall passed. + +## Tracking boundary + +This directory contains the minimal reviewed intent. Optional participant prose +and raw command logs are not required delivery output. diff --git a/project/ticket-118/intent.json b/project/ticket-118/intent.json new file mode 100644 index 00000000..6ea899ad --- /dev/null +++ b/project/ticket-118/intent.json @@ -0,0 +1,29 @@ +{ + "schema": "new-project.intent/v3", + "ticket": "ticket-118", + "summary": "Separate todo2code scan suggestion mapping", + "workstream": "application", + "classification": { + "kind": "SERVICE", + "priority": "P2", + "origin": "requested" + }, + "allowedPaths": ["src/koru/scan.py", "tests/test_todo2code_discovery.py", "project/ticket-118/**"], + "forbiddenPaths": ["project/ticket-*/user-*.md"], + "stacks": ["python", "docker"], + "dependsOn": [], + "conflictsWith": [], + "integrationTicket": null, + "delivery": { + "acceptedBaseSha": "5aadcaaf87bd43c52ee33c414c7b9c10e6eeaa13", + "targetBranch": "main", + "outcome": "Publish a behavior-preserving extraction of todo2code scan suggestion mapping.", + "nonGoals": ["No changes to scan authority, suggestion schema, dependencies or public interfaces."], + "complexity": "S", + "estimatedMinutes": 30, + "budgets": {"maxImplementationFiles": 2, "maxAffectedComponents": 1, "maxPublicInterfaceChanges": 0, "maxRuntimeDependencies": 0}, + "architecture": {"status": "accepted", "decision": "Move per-plan eligibility and suggestion construction into a focused helper while retaining artifact loading and iteration.", "components": [{"name": "todo2code-scan", "paths": ["src/koru/scan.py", "tests/test_todo2code_discovery.py"]}], "responsibilityChanges": false, "interfaceChanges": [], "dataChanges": [], "ui": {"impact": "none", "states": [], "evidence": []}, "rollback": "Revert protected merge."}, + "runtimeDependencies": [], + "validation": [{"criterion": "AC-01", "commands": ["python -m pytest -q tests/test_todo2code_discovery.py", "./project/governance-check.sh", "docker compose config --quiet"], "evidence": "Focused regression, Koru run, fresh analysis and independent CI."}] + } +} diff --git a/src/koru/scan.py b/src/koru/scan.py index 49e13966..8595c77f 100644 --- a/src/koru/scan.py +++ b/src/koru/scan.py @@ -39,7 +39,7 @@ import shutil import subprocess from collections import Counter -from collections.abc import Callable, Sequence +from collections.abc import Callable, Mapping, Sequence from importlib.util import find_spec from pathlib import Path from typing import Any @@ -1714,6 +1714,41 @@ def _scan_metrun_report(project: Path) -> list[Suggestion]: ] +def _todo2code_plan_suggestion( + plan: dict[str, Any], *, project: Path, plans_rel: str, + is_useful_plan: Callable[..., bool], plan_useful_paths: Callable[..., list[str]], + priority_map: Mapping[str, str], source: str, + dedupe_key: Callable[[dict[str, Any]], str], +) -> Suggestion | None: + """Convert one useful grounded plan into a scan suggestion.""" + if not is_useful_plan(plan, project=project): + return None + paths = plan_useful_paths(plan, project=project) + if not paths: + return None + title_raw = str(plan.get("title") or "todo2code code-change plan").strip() + title = title_raw if len(title_raw) <= 140 else title_raw[:139].rstrip() + "…" + description = str(plan.get("description") or title_raw).strip() + priority = priority_map.get(str(plan.get("priority") or "").upper(), "normal") + if priority not in {"high", "normal", "low"}: + priority = "normal" + evidence = plan.get("evidence") if isinstance(plan.get("evidence"), dict) else {} + return Suggestion( + signal="todo2code_plan", title=f"[todo2code] {title}", + description=( + f"{description}\n\nSource: `{plans_rel}` " + f"(plan id {plan.get('id') or 'n/a'}). Implement only declared target paths." + ), + priority=priority, labels=("todo2code", "code-change", "scan", "useful-code-change"), + files=tuple(paths[:12]), + source_context={"signal": "todo2code_code_change_plan", "dedupe_key": dedupe_key(plan), + "plan_id": str(plan.get("id") or "").strip() or None, + "plan_hash": str(plan.get("planHash") or "").strip() or None, + "source_tool": source, + "diagnostic_ids": [str(v) for v in (evidence.get("diagnosticIds") or []) if str(v).strip()]}, + ) + + def _scan_todo2code_plans(project: Path) -> list[Suggestion]: """Useful grounded code-change plans from ``t2c`` artifacts.""" try: @@ -1746,42 +1781,13 @@ def _scan_todo2code_plans(project: Path) -> list[Suggestion]: suggestions: list[Suggestion] = [] for plan in plans: - if not is_useful_plan(plan, project=project): - continue - paths = plan_useful_paths(plan, project=project) - if not paths: - continue - title_raw = str(plan.get("title") or "todo2code code-change plan").strip() - title = title_raw if len(title_raw) <= 140 else title_raw[:139].rstrip() + "…" - description = str(plan.get("description") or title_raw).strip() - priority = _PRIORITY_MAP.get(str(plan.get("priority") or "").upper(), "normal") - if priority not in {"high", "normal", "low"}: - priority = "normal" - evidence = plan.get("evidence") if isinstance(plan.get("evidence"), dict) else {} - suggestions.append( - Suggestion( - signal="todo2code_plan", - title=f"[todo2code] {title}", - description=( - f"{description}\n\n" - f"Source: `{plans_rel}` (plan id {plan.get('id') or 'n/a'}). " - "Implement only declared target paths." - ), - priority=priority, - labels=("todo2code", "code-change", "scan", "useful-code-change"), - files=tuple(paths[:12]), - source_context={ - "signal": "todo2code_code_change_plan", - "dedupe_key": _plan_dedupe_key(plan), - "plan_id": str(plan.get("id") or "").strip() or None, - "plan_hash": str(plan.get("planHash") or "").strip() or None, - "source_tool": TODO2CODE_SOURCE, - "diagnostic_ids": [ - str(v) for v in (evidence.get("diagnosticIds") or []) if str(v).strip() - ], - }, - ), + suggestion = _todo2code_plan_suggestion( + plan, project=project, plans_rel=plans_rel, is_useful_plan=is_useful_plan, + plan_useful_paths=plan_useful_paths, priority_map=_PRIORITY_MAP, + source=TODO2CODE_SOURCE, dedupe_key=_plan_dedupe_key, ) + if suggestion is not None: + suggestions.append(suggestion) return suggestions