SecureCodeEnv / graders /consistency.py
vishaldhakad's picture
change in reward system to strict it between the 0-1
791664b
Raw
History Blame Contribute Delete
3.03 kB
"""SecureCodeEnv - Consistency Grader v4 — clamped scores"""
from codegraph.graph import CodeGraph
from codegraph.extractor import extract_metadata
from graders.clamp import clamp
GOOD_PRACTICES = {
"uses_type_hints": 0.15,
"uses_docstrings": 0.15,
"uses_try_catch": 0.10,
"no_print_stmts": 0.10,
"no_hardcoded_secrets": 0.10,
}
def grade_consistency(code: str, filename: str, graph: CodeGraph, step: int) -> dict:
new_meta = extract_metadata(code, filename, step)
conv = new_meta.conventions
if not graph.components:
checks = {k: 1.0 if conv.get(k, False) else 0.0 for k in GOOD_PRACTICES}
raw = sum(checks.values()) / max(len(checks), 1)
raw = max(0.45, raw) # floor so first step never crushes reward
return {"score": clamp(raw), "checks": checks,
"feedback": _first_feedback(raw, checks)}
established = graph.conventions
checks = {}
naming = established.get("naming")
if naming and naming != "mixed" and new_meta.functions:
fns = new_meta.functions
if naming == "snake_case":
correct = sum(1 for f in fns if "_" in f["name"] or f["name"].islower())
else:
correct = sum(1 for f in fns if f["name"] and f["name"][0].islower()
and any(c.isupper() for c in f["name"]))
checks["naming_convention"] = correct / len(fns)
if established.get("error_handling") == "try_catch":
checks["error_handling"] = 1.0 if conv.get("uses_try_catch") else 0.3
if established.get("uses_type_hints"):
checks["type_hints"] = 1.0 if conv.get("uses_type_hints") else 0.4
if established.get("uses_docstrings"):
checks["docstrings"] = 1.0 if conv.get("uses_docstrings") else 0.5
existing_no_print = all(c.conventions.get("no_print_stmts", True)
for c in graph.components.values())
if existing_no_print:
checks["no_print_drift"] = 1.0 if conv.get("no_print_stmts", True) else 0.3
reuse_opp = reuse_taken = 0
for name in graph.components:
if name.lower() in code.lower():
reuse_opp += 1
if name in code:
reuse_taken += 1
if reuse_opp > 0:
checks["component_reuse"] = reuse_taken / reuse_opp
raw = sum(checks.values()) / max(len(checks), 1) if checks else 0.7
return {"score": clamp(raw), "checks": checks,
"feedback": _feedback(raw, checks)}
def _first_feedback(score, checks):
missing = [k for k, v in checks.items() if v == 0.0]
if not missing:
return f"Good conventions established ({score:.2f})"
return f"Missing practices: {', '.join(missing)}"
def _feedback(score, checks):
if score >= 0.85: return "Excellent consistency with codebase"
failing = [k for k, v in checks.items() if isinstance(v, float) and v < 0.5]
return f"Convention drift in: {', '.join(failing)}" if failing else f"Minor drift ({score:.2f})"