Files
whetstone_DSL/tools/mcp/remediation_router.py

119 lines
3.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""Deterministic remediation routing from gate diagnostics to action plan."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from typing import Dict, List
def load_json(path: str) -> Dict[str, object]:
p = Path(path)
if not p.exists():
return {}
return json.loads(p.read_text())
def classify(gates: Dict[str, object]) -> Dict[str, object]:
g = gates.get("gates", {}) if isinstance(gates, dict) else {}
reasons = list(g.get("failure_reasons", [])) if isinstance(g, dict) else []
compile_reason = str((g.get("compile") or {}).get("reason", ""))
tests_reason = str((g.get("tests") or {}).get("reason", ""))
actions: List[Dict[str, object]] = []
nonrecoverable = "tool_missing" in compile_reason or "tool_missing" in tests_reason
if nonrecoverable:
actions.append(
{
"action": "stop_blocked",
"tool": "none",
"reason": "missing_toolchain",
"confidence": 1.0,
"priority": 100,
}
)
return {
"blocked": True,
"blocked_reason": "missing_toolchain",
"actions": actions,
}
if any(r.startswith("placeholder_or_todo") for r in reasons):
actions.append(
{
"action": "strengthen_spec",
"tool": "whetstone_generate_code",
"hint": "Eliminate placeholders/TODO markers and provide concrete field/method types and bodies.",
"confidence": 0.95,
"priority": 90,
}
)
if any(r.startswith("compile_failed") for r in reasons):
actions.append(
{
"action": "diagnose_pipeline",
"tool": "whetstone_run_pipeline",
"hint": "Run same-language pipeline pass to collect parse/validation diagnostics and refine signatures/types.",
"confidence": 0.9,
"priority": 80,
}
)
actions.append(
{
"action": "strengthen_spec",
"tool": "whetstone_generate_code",
"hint": "Emit compile-clean code for target language with explicit imports/includes and fully typed declarations.",
"confidence": 0.85,
"priority": 70,
}
)
if any(r.startswith("tests_failed") for r in reasons):
actions.append(
{
"action": "strengthen_spec",
"tool": "whetstone_generate_code",
"hint": "Implement queue behaviors: enqueue/dequeue/peek/size/empty with deterministic semantics.",
"confidence": 0.9,
"priority": 75,
}
)
actions.sort(key=lambda a: (-int(a["priority"]), a["action"]))
return {
"blocked": False,
"blocked_reason": "",
"actions": actions,
}
def main() -> None:
ap = argparse.ArgumentParser()
ap.add_argument("--gates-json", required=True)
ap.add_argument("--out", default="")
args = ap.parse_args()
gates = load_json(args.gates_json)
plan = classify(gates)
payload = {
"router_version": "1",
"input_failure_reasons": (gates.get("gates", {}) or {}).get("failure_reasons", []),
"blocked": plan["blocked"],
"blocked_reason": plan["blocked_reason"],
"actions": plan["actions"],
}
text = json.dumps(payload, indent=2, sort_keys=True)
if args.out:
out = Path(args.out)
out.parent.mkdir(parents=True, exist_ok=True)
out.write_text(text + "\n")
print(text)
if __name__ == "__main__":
main()