diff --git a/project/ticket-120/README.md b/project/ticket-120/README.md new file mode 100644 index 00000000..e43f79c8 --- /dev/null +++ b/project/ticket-120/README.md @@ -0,0 +1,25 @@ +# Ticket 120: Separate todo2code ticket hydration policy + +- **ID**: ticket-120 +- **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 bounded todo2code verification command construction from ticket +hydration while preserving contract gating, diagnostic validation, source path +binding, labels and input defaults. + +## Acceptance criteria + +- [ ] AC-01: Hydration behavior remains unchanged and complexity decreases. + +Validation: 7 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-120/intent.json b/project/ticket-120/intent.json new file mode 100644 index 00000000..65eb97cc --- /dev/null +++ b/project/ticket-120/intent.json @@ -0,0 +1,29 @@ +{ + "schema": "new-project.intent/v3", + "ticket": "ticket-120", + "summary": "Separate todo2code ticket hydration policy", + "workstream": "application", + "classification": { + "kind": "SERVICE", + "priority": "P2", + "origin": "requested" + }, + "allowedPaths": ["src/koru/queue/ticket_templates.py", "tests/test_todo2code_autonomous_gate.py", "project/ticket-120/**"], + "forbiddenPaths": ["project/ticket-*/user-*.md"], + "stacks": ["python", "docker"], + "dependsOn": [], + "conflictsWith": [], + "integrationTicket": null, + "delivery": { + "acceptedBaseSha": "1d9f14e3678dd30d5e6178b7571ad99ee891b1d5", + "targetBranch": "main", + "outcome": "Publish a behavior-preserving extraction of todo2code ticket hydration command construction.", + "nonGoals": ["No changes to execution authority, ticket schema, dependencies or public interfaces."], + "complexity": "S", + "estimatedMinutes": 30, + "budgets": {"maxImplementationFiles": 2, "maxAffectedComponents": 1, "maxPublicInterfaceChanges": 0, "maxRuntimeDependencies": 0}, + "architecture": {"status": "accepted", "decision": "Move diagnostic verification command assembly into a focused helper while retaining hydration and fail-closed contract behavior.", "components": [{"name": "todo2code-hydration", "paths": ["src/koru/queue/ticket_templates.py", "tests/test_todo2code_autonomous_gate.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_autonomous_gate.py", "./project/governance-check.sh", "docker compose config --quiet"], "evidence": "Focused regression, Koru run and independent CI."}] + } +} diff --git a/src/koru/queue/ticket_templates.py b/src/koru/queue/ticket_templates.py index 002dfc5f..5ef3ae84 100644 --- a/src/koru/queue/ticket_templates.py +++ b/src/koru/queue/ticket_templates.py @@ -250,6 +250,21 @@ def hydrate_subactor_repair_ticket(ticket: dict[str, Any]) -> dict[str, Any]: return out +def _todo2code_verify_command(project: Path, diagnostic_ids: list[str]) -> str | None: + """Build the Koru verification command for validated todo2code diagnostics.""" + if not diagnostic_ids: + return None + t2c = t2c_executable(project) + if not t2c: + return None + koru_source_root = str(Path(__file__).resolve().parents[2]) + command = ["env", f"PYTHONPATH={koru_source_root}", sys.executable, "-m", + "koru.queue.todo2code_gate", "--project", ".", "--t2c", t2c] + for diagnostic_id in diagnostic_ids: + command.extend(["--diagnostic", diagnostic_id]) + return shlex.join(command) + + def hydrate_todo2code_ticket(ticket: dict[str, Any], project: Path) -> dict[str, Any]: """Hydrate todo2code defaults without manufacturing execution authority.""" labels = [str(label) for label in (ticket.get("labels") or [])] @@ -295,27 +310,10 @@ def hydrate_todo2code_ticket(ticket: dict[str, Any], project: Path) -> dict[str, str(value) for value in (context.get("diagnostic_ids") or []) if re.fullmatch(r"DIAG-[a-f0-9]+", str(value)) ] - if not str(inputs.get("verify_command") or "").strip() and diagnostic_ids: - t2c = t2c_executable(project) - if t2c: - # Verification runs in a temporary worktree of the target project. - # A relative developer PYTHONPATH (commonly ``src``) would then - # resolve against that project and make the Koru gate disappear. - koru_source_root = str(Path(__file__).resolve().parents[2]) - command = [ - "env", - f"PYTHONPATH={koru_source_root}", - sys.executable, - "-m", - "koru.queue.todo2code_gate", - "--project", - ".", - "--t2c", - t2c, - ] - for diagnostic_id in diagnostic_ids: - command.extend(["--diagnostic", diagnostic_id]) - inputs["verify_command"] = shlex.join(command) + if not str(inputs.get("verify_command") or "").strip(): + verify_command = _todo2code_verify_command(project, diagnostic_ids) + if verify_command: + inputs["verify_command"] = verify_command if "type:development-defect" not in lowered: labels.append("type:development-defect")