Spaces:
Sleeping
Sleeping
Upload graders.py
Browse files- server/graders.py +145 -0
server/graders.py
CHANGED
|
@@ -1250,3 +1250,148 @@ def grade_dedup_bug(
|
|
| 1250 |
},
|
| 1251 |
partial_scores=partial_scores.copy(),
|
| 1252 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1250 |
},
|
| 1251 |
partial_scores=partial_scores.copy(),
|
| 1252 |
)
|
| 1253 |
+
|
| 1254 |
+
|
| 1255 |
+
def grade_fk_integrity(
|
| 1256 |
+
action: SQLAction,
|
| 1257 |
+
ground_truth: Dict[str, Any],
|
| 1258 |
+
conn: sqlite3.Connection,
|
| 1259 |
+
) -> SQLReward:
|
| 1260 |
+
"""Single-step fk_integrity scorer — validates grader exists."""
|
| 1261 |
+
fix_sql = (action.fix_query or action.sql or "").strip()
|
| 1262 |
+
target_table = ground_truth.get("table", "invoices")
|
| 1263 |
+
parent_table = ground_truth.get("parent_table", "customers")
|
| 1264 |
+
parent_key = ground_truth.get("parent_key", "id")
|
| 1265 |
+
fk_col = ground_truth.get("column", "customer_id")
|
| 1266 |
+
snapshot = _snapshot_table(conn, target_table)
|
| 1267 |
+
|
| 1268 |
+
if not fix_sql or fix_sql.upper().startswith("SELECT"):
|
| 1269 |
+
return SQLReward(
|
| 1270 |
+
score=_clamp(0.0),
|
| 1271 |
+
step_reward=_clamp(0.0),
|
| 1272 |
+
feedback="No fix query provided",
|
| 1273 |
+
dimensions={"legacy_mode": True},
|
| 1274 |
+
partial_scores={},
|
| 1275 |
+
)
|
| 1276 |
+
|
| 1277 |
+
test_conn = _fresh_test_db(conn)
|
| 1278 |
+
try:
|
| 1279 |
+
test_conn.executescript(fix_sql)
|
| 1280 |
+
test_conn.commit()
|
| 1281 |
+
orphan_count = test_conn.execute(
|
| 1282 |
+
f"SELECT COUNT(*) FROM {quote_identifier(target_table)} t "
|
| 1283 |
+
f"LEFT JOIN {quote_identifier(parent_table)} p ON t.{quote_identifier(fk_col)} = p.{quote_identifier(parent_key)} "
|
| 1284 |
+
f"WHERE p.{quote_identifier(parent_key)} IS NULL"
|
| 1285 |
+
).fetchone()[0]
|
| 1286 |
+
issue_resolved = orphan_count == 0
|
| 1287 |
+
preservation = _measure_data_preservation(
|
| 1288 |
+
test_conn, snapshot, target_table
|
| 1289 |
+
)
|
| 1290 |
+
score = 0.0
|
| 1291 |
+
if issue_resolved:
|
| 1292 |
+
score += 0.6
|
| 1293 |
+
if preservation >= 0.95:
|
| 1294 |
+
score += 0.4
|
| 1295 |
+
return SQLReward(
|
| 1296 |
+
score=_clamp(score),
|
| 1297 |
+
step_reward=_clamp(score),
|
| 1298 |
+
feedback=(
|
| 1299 |
+
"FK integrity resolved" if issue_resolved
|
| 1300 |
+
else f"Orphans remaining: {orphan_count}"
|
| 1301 |
+
),
|
| 1302 |
+
dimensions={"legacy_mode": True, "composite": _clamp(score)},
|
| 1303 |
+
partial_scores={"issue_resolved": float(issue_resolved),
|
| 1304 |
+
"preservation": preservation},
|
| 1305 |
+
)
|
| 1306 |
+
except sqlite3.Error as exc:
|
| 1307 |
+
return SQLReward(
|
| 1308 |
+
score=_clamp(0.0),
|
| 1309 |
+
step_reward=_clamp(0.0),
|
| 1310 |
+
feedback=f"SQL error: {exc}",
|
| 1311 |
+
dimensions={"legacy_mode": True},
|
| 1312 |
+
partial_scores={},
|
| 1313 |
+
)
|
| 1314 |
+
finally:
|
| 1315 |
+
test_conn.close()
|
| 1316 |
+
|
| 1317 |
+
|
| 1318 |
+
def grade_schema_drift(
|
| 1319 |
+
action: SQLAction,
|
| 1320 |
+
ground_truth: Dict[str, Any],
|
| 1321 |
+
conn: sqlite3.Connection,
|
| 1322 |
+
) -> SQLReward:
|
| 1323 |
+
"""Single-step schema_drift scorer — validates grader exists."""
|
| 1324 |
+
fix_sql = (action.fix_query or action.sql or "").strip()
|
| 1325 |
+
canonical_table = ground_truth.get("table", "canonical_events")
|
| 1326 |
+
expected_cols = ground_truth.get(
|
| 1327 |
+
"expected_columns",
|
| 1328 |
+
["event_id", "user_id", "event_type", "amount", "event_time"]
|
| 1329 |
+
)
|
| 1330 |
+
expected_rows = ground_truth.get("expected_row_count", 1200)
|
| 1331 |
+
|
| 1332 |
+
if not fix_sql:
|
| 1333 |
+
return SQLReward(
|
| 1334 |
+
score=_clamp(0.0),
|
| 1335 |
+
step_reward=_clamp(0.0),
|
| 1336 |
+
feedback="No fix query provided",
|
| 1337 |
+
dimensions={"legacy_mode": True},
|
| 1338 |
+
partial_scores={},
|
| 1339 |
+
)
|
| 1340 |
+
|
| 1341 |
+
test_conn = _fresh_test_db(conn)
|
| 1342 |
+
try:
|
| 1343 |
+
test_conn.executescript(fix_sql)
|
| 1344 |
+
test_conn.commit()
|
| 1345 |
+
tables = {
|
| 1346 |
+
r[0] for r in test_conn.execute(
|
| 1347 |
+
"SELECT name FROM sqlite_master WHERE type='table'"
|
| 1348 |
+
).fetchall()
|
| 1349 |
+
}
|
| 1350 |
+
if canonical_table not in tables:
|
| 1351 |
+
return SQLReward(
|
| 1352 |
+
score=_clamp(0.0),
|
| 1353 |
+
step_reward=_clamp(0.0),
|
| 1354 |
+
feedback=f"Table {canonical_table} not created",
|
| 1355 |
+
dimensions={"legacy_mode": True},
|
| 1356 |
+
partial_scores={},
|
| 1357 |
+
)
|
| 1358 |
+
cols = {
|
| 1359 |
+
r[1] for r in test_conn.execute(
|
| 1360 |
+
f"PRAGMA table_info({quote_identifier(canonical_table)})"
|
| 1361 |
+
)
|
| 1362 |
+
}
|
| 1363 |
+
row_count = test_conn.execute(
|
| 1364 |
+
f"SELECT COUNT(*) FROM {quote_identifier(canonical_table)}"
|
| 1365 |
+
).fetchone()[0]
|
| 1366 |
+
col_overlap = len(set(expected_cols) & cols) / max(1, len(expected_cols))
|
| 1367 |
+
row_align = 1.0 - min(
|
| 1368 |
+
1.0, abs(row_count - expected_rows) / max(1, expected_rows)
|
| 1369 |
+
)
|
| 1370 |
+
score = col_overlap * 0.5 + row_align * 0.5
|
| 1371 |
+
return SQLReward(
|
| 1372 |
+
score=_clamp(score),
|
| 1373 |
+
step_reward=_clamp(score),
|
| 1374 |
+
feedback=f"Schema drift: col_overlap={col_overlap:.2f} row_align={row_align:.2f}",
|
| 1375 |
+
dimensions={"legacy_mode": True, "composite": _clamp(score)},
|
| 1376 |
+
partial_scores={"col_overlap": col_overlap, "row_align": row_align},
|
| 1377 |
+
)
|
| 1378 |
+
except sqlite3.Error as exc:
|
| 1379 |
+
return SQLReward(
|
| 1380 |
+
score=_clamp(0.0),
|
| 1381 |
+
step_reward=_clamp(0.0),
|
| 1382 |
+
feedback=f"SQL error: {exc}",
|
| 1383 |
+
dimensions={"legacy_mode": True},
|
| 1384 |
+
partial_scores={},
|
| 1385 |
+
)
|
| 1386 |
+
finally:
|
| 1387 |
+
test_conn.close()
|
| 1388 |
+
|
| 1389 |
+
|
| 1390 |
+
__all__ = [
|
| 1391 |
+
"grade_null_audit",
|
| 1392 |
+
"grade_type_repair",
|
| 1393 |
+
"grade_dedup_bug",
|
| 1394 |
+
"grade_fk_integrity",
|
| 1395 |
+
"grade_schema_drift",
|
| 1396 |
+
"compute_episode_score",
|
| 1397 |
+
]
|