Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 135 additions & 36 deletions planfile/importers/code2llm_importer.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
"""Import tickets from code2llm evolution.toon and analysis.toon."""


def import_code2llm(toon_path: str, auto_priority: bool = True,
sprint: str = "backlog", **kwargs) -> list[dict]:
"""Parse evolution.toon NEXT[] → ticket dicts."""
content = open(toon_path, encoding="utf-8").read()

if "NEXT[" in content:
return _parse_evolution(content, auto_priority)
elif "HEALTH[" in content:
return _parse_health(content, auto_priority)
return []
import hashlib
import re
from pathlib import Path


def import_code2llm(
toon_path: str, auto_priority: bool = True, sprint: str = "backlog", **kwargs
) -> list[dict]:
"""Parse current HEALTH or legacy NEXT sections into persistable candidates."""
path = Path(toon_path)
raw = path.read_bytes()
content = raw.decode("utf-8")
if re.search(r"^\s*HEALTH\[\d+\]:\s*$", content, re.MULTILINE):
tickets = _parse_health(content, auto_priority)
digest = hashlib.sha256(raw).hexdigest()
for ticket in tickets:
ticket["source"]["context"].update(
analysis_path=str(path.resolve()), analysis_sha256=digest
)
elif re.search(r"^\s*NEXT\[\d+\]:", content, re.MULTILINE):
tickets = _parse_evolution(content, auto_priority)
else:
return []
for ticket in tickets:
ticket["name"] = ticket["title"]
return tickets


def _parse_evolution(content: str, auto_priority: bool) -> list[dict]:
Expand Down Expand Up @@ -65,10 +80,12 @@ def _handle_in_next(self, line: str):

# End of NEXT section - check if line has content but doesn't start with space
# and is not a property line (WHY:, EFFORT:, IMPACT:)
elif (stripped and
not line.startswith(" ") and
not stripped.startswith("[") and
":" not in stripped):
elif (
stripped
and not line.startswith(" ")
and not stripped.startswith("[")
and ":" not in stripped
):
self.state = "outside"

# Property lines
Expand Down Expand Up @@ -102,28 +119,110 @@ def _evolution_item_to_ticket(item: dict, auto_priority: bool) -> dict:
"description": item.get("why", ""),
"priority": priority,
"labels": ["tech-debt", "refactoring", action.lower()],
"source": {"tool": "code2llm", "context": {
"impact": impact,
"effort": item.get("effort"),
}},
"source": {
"tool": "code2llm",
"context": {
"impact": impact,
"effort": item.get("effort"),
},
},
}


def _parse_health(content: str, auto_priority: bool) -> list[dict]:
"""Parse HEALTH[] section from analysis.toon."""
tickets = []
for line in content.split("\n"):
if "CC" in line and "limit:" in line:
parts = line.strip().split()
func = parts[2] if len(parts) > 2 else "unknown"
cc_str = [p for p in parts if p.startswith("CC=")]
cc = int(cc_str[0].split("=")[1]) if cc_str else 0
tickets.append({
"title": f"Reduce CC: {func} (CC={cc})",
"priority": "high" if cc > 20 else "normal",
"labels": ["complexity", "cc-violation"],
"source": {"tool": "code2llm", "context": {
"function": func, "cc": cc,
}},
})
return tickets
"""Import only HEALTH alerts; other sections contain repeated metrics."""
tickets = {}
in_health = False
declared_count = 0
for line in content.splitlines():
header = re.fullmatch(r"\s*HEALTH\[(\d+)\]:\s*", line)
if header:
in_health = True
declared_count += int(header[1])
continue
if not in_health:
continue
if re.match(r"^[A-Z][A-Z0-9_]*\[\d+\]:", line):
in_health = False
continue
ticket = _health_alert(line.strip(), auto_priority)
if ticket:
key = ticket["source"]["context"]["dedupe_key"]
tickets.setdefault(key, ticket)
if declared_count and not tickets:
raise ValueError("Non-empty code2llm HEALTH section has no supported alerts")
return list(tickets.values())


def _health_ticket(
title: str, description: str, priority: str, labels: list[str], context: dict, key: str
) -> dict:
context["dedupe_key"] = key
return {
"title": title,
"description": description,
"priority": priority,
"labels": ["tech-debt", *labels, f"dedupe:{key}"],
"source": {"tool": "code2llm", "context": context},
}


def _health_alert(line: str, auto_priority: bool) -> dict | None:
god = re.search(r"\bGOD\s+(\S+)\s*=\s*(\d+)L\b", line)
if god:
path = god[1]
if Path(path).is_absolute() or "\\" in path or ":" in path or ".." in Path(path).parts:
raise ValueError(f"Unsafe code2llm module path: {path}")
cc = re.search(r"max CC=(\d+)", line)
context = {"signal": "god", "module": path, "lines": int(god[2])}
if cc:
context["cc"] = int(cc[1])
ticket = _health_ticket(
f"Split god module: {path}",
f"Review {path} ({god[2]} lines) and split cohesive responsibilities. "
"Preserve public behavior, run relevant tests and compare a fresh analysis. "
"A native ticket and editing admission are required before execution.",
"high" if auto_priority else "normal",
["refactoring", "god-module"],
context,
f"code2llm:god:{path}",
)
ticket["files"] = [path]
return ticket
dup = re.search(r"\bDUP\s+(\d+) duplicate class groups\b", line)
if dup and int(dup[1]):
return _health_ticket(
f"Review duplicated classes ({dup[1]} groups)",
"Inspect concrete duplicate groups before choosing a shared abstraction. "
"The aggregate alert does not identify editable files.",
"high" if auto_priority else "normal",
["duplication", "triage"],
{"signal": "dup", "groups": int(dup[1])},
"code2llm:dup:class-groups",
)
cycle = re.search(r"\bCYCLE\s+Circular dependency detected:\s*(.+)", line)
if cycle:
chain = cycle[1].split(". This indicates", 1)[0].rstrip(".")
key = hashlib.sha256(chain.encode()).hexdigest()[:20]
return _health_ticket(
f"Inspect circular dependency: {chain[:120]}",
f"Reported call chain: {chain}. Check whether recursion is intentional "
"and whether the code is vendored before proposing a change. "
"Resolve source files and a bounded native scope during triage.",
"high" if auto_priority else "normal",
["circular-dependency", "triage"],
{"signal": "cycle", "chain": chain},
f"code2llm:cycle:{key}",
)
legacy = re.search(r"\bCC\s+(\S+)\s+(?:CC=|=\s*)(\d+)\s*\(limit:\s*\d+\)", line)
if legacy:
function, cc = legacy[1], int(legacy[2])
return _health_ticket(
f"Reduce CC: {function} (CC={cc})",
"Reduce complexity while preserving behavior and run relevant tests.",
"high" if auto_priority and cc > 20 else "normal",
["complexity", "cc-violation"],
{"function": function, "cc": cc},
f"code2llm:cc:{function}",
)
return None
35 changes: 35 additions & 0 deletions project/ticket-206/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Ticket 206: Import current code2llm health reports as actionable quality tickets

- **ID**: ticket-206
- **Owner**: agent:codex
- **Status**: IN_PROGRESS
- **Workflow state**: PUBLICATION
- **Created**: 2026-10-08

## Goal and scope

SESSION_EXECUTION_AUTHORIZATION: The user requests continuation of the
Willman/Koru code quality pipeline based on project/analysis.toon.yaml.
Workspace PLF-013 / PLF-121 tracks this bounded parser repair. Current HEALTH
reports contain GOD, DUP and CYCLE alerts; the installed importer silently
returns no tickets because it only recognizes an older CC line format.
Parse current health alerts, preserve legacy CC/evolution support, restrict
parsing to HEALTH, and return ticket names accepted by Planfile persistence.
Retain report provenance, concrete module paths and stable dedupe labels.
Duplicate and cycle signals require triage; no executor or lease is inferred.

## Acceptance criteria

- [x] AC-01: Current GOD/DUP/CYCLE health alerts produce file-scoped or triage candidates instead of an empty result.
- [x] AC-02: Legacy CC and evolution imports retain their existing fields and behavior.
- [x] AC-03: Imported records persist with Planfile's normal bulk API; unrelated report sections cannot create tickets.
- [x] AC-04: Focused importer and persistence tests plus governance pass.

SESSION_EXECUTION_AUTHORIZATION (2026-10-08 continuation): The user says
"kontynuuj, scalaj, naprawiaj" after reviewing the tested local repair and
explicit publication question. This authorizes push, PR, independent protected
validation and gated merge of this bounded importer repair. Record actual merge
and activation externally; session prose never substitutes for trusted approval.

No dispatcher activation, Koru quality editing, protected policy changes or
version bump is part of this slice.
76 changes: 76 additions & 0 deletions project/ticket-206/intent.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"schema": "new-project.intent/v3",
"ticket": "ticket-206",
"summary": "Import current code2llm health reports as actionable quality tickets",
"workstream": "application",
"classification": {
"kind": "BUG",
"priority": "P1",
"origin": "requested"
},
"allowedPaths": [
"project/ticket-206/**",
"TODO.md",
"project/TICKETS.md",
"planfile/importers/code2llm_importer.py",
"tests/test_code2llm_importer.py"
],
"forbiddenPaths": [
"project/ticket-*/user-*.md"
],
"stacks": [],
"dependsOn": [],
"conflictsWith": [],
"integrationTicket": null,
"delivery": {
"acceptedBaseSha": "a5bc9be973a2eca012590c65d271ac8286622e35",
"targetBranch": "main",
"outcome": "Validated current code2llm HEALTH import published through protected independent approval and merge, then observed in the installed primary checkout.",
"nonGoals": [
"No dispatcher activation, Koru quality editing, protected admission changes or version bump"
],
"complexity": "S",
"estimatedMinutes": 45,
"budgets": {
"maxImplementationFiles": 2,
"maxAffectedComponents": 2,
"maxPublicInterfaceChanges": 0,
"maxRuntimeDependencies": 0
},
"architecture": {
"status": "accepted",
"decision": "Parse only HEALTH alerts into named advisory records; preserve legacy evolution and CC fields.",
"components": [
{
"name": "code2llm-import",
"paths": [
"planfile/importers/code2llm_importer.py",
"tests/test_code2llm_importer.py"
]
}
],
"responsibilityChanges": false,
"interfaceChanges": [],
"dataChanges": [],
"ui": {
"impact": "none",
"states": [],
"evidence": []
},
"rollback": "Revert the ticket implementation commit."
},
"runtimeDependencies": [],
"validation": [
{
"criterion": "AC-04",
"commands": [
"pytest -q tests/test_code2llm_importer.py tests/test_store_tickets_id_fallback.py",
"ruff check --no-cache planfile/importers/code2llm_importer.py tests/test_code2llm_importer.py",
"ruff format --check --no-cache planfile/importers/code2llm_importer.py tests/test_code2llm_importer.py",
"bash project/governance-check.sh"
],
"evidence": "17 focused tests pass with managed governance 0 errors/0 warnings; lint and formatting pass. Actual workspace report produces and persists20 candidates:7 GOD,1 DUP,12 CYCLE. External receipt: .subactor/recovery/code2llm-health-206-20261008/current-report-import.json. Final standalone gate recorded there before commit."
}
]
}
}
Loading
Loading