Config-debug / server /graders /json_grader.py
affu143
one more time
13c6248
Raw
History Blame Contribute Delete
3.34 kB
import json
from typing import Tuple, List
def grade_task1(submitted_config: str) -> Tuple[float, str, List[str]]:
"""
Grade Task 1: Broken JSON Config (3 bugs, progressive grading)
Progressive Validation:
1. Syntax: JSON must parse validly
2. Structure: env must be object (not array), volumes must be object
3. Semantics: All required fields present with correct types
Bugs:
- Bug 1 (Syntax): Missing comma after app_name
- Bug 2 (Structural): env is array instead of object with key-value pairs
- Bug 3 (Structural): volumes is array instead of object mapping
Returns: (reward, error_message, bugs_fixed_list)
Reward is emergent from fixes, not hard-coded.
"""
bugs_fixed = []
error_messages = []
reward = 0.0
# ===== LEVEL 1: SYNTAX VALIDATION =====
try:
config = json.loads(submitted_config)
bugs_fixed.append("json_syntax_valid")
reward += 0.3
except json.JSONDecodeError as e:
error_messages.append(f"JSON parse error: {str(e)}")
# Return early with syntax failure
error_msg = "; ".join(error_messages) if error_messages else "JSON syntax error"
return max(0.01, min(0.90, reward)), error_msg, bugs_fixed
# ===== LEVEL 2: STRUCTURAL VALIDATION =====
# Check env structure
if "env" in config:
if isinstance(config["env"], dict):
bugs_fixed.append("env_is_object")
reward += 0.25
else:
error_messages.append(
f"Field 'env' should be object (dict), got {type(config['env']).__name__}"
)
else:
error_messages.append("Missing required field: 'env'")
# Check volumes structure
if "volumes" in config:
if isinstance(config["volumes"], dict):
bugs_fixed.append("volumes_is_object")
reward += 0.25
else:
error_messages.append(
f"Field 'volumes' should be object (dict), got {type(config['volumes']).__name__}"
)
else:
error_messages.append("Missing required field: 'volumes'")
# ===== LEVEL 3: SEMANTIC VALIDATION =====
# Only check semantics if structure is correct
if "env_is_object" in bugs_fixed and isinstance(config.get("env"), dict):
env = config["env"]
required_env_keys = {"LOG_LEVEL", "DB_HOST", "PORT"}
if required_env_keys.issubset(env.keys()):
bugs_fixed.append("env_all_keys_present")
reward += 0.15
else:
missing = required_env_keys - set(env.keys())
error_messages.append(f"Missing env keys: {missing}")
if "volumes_is_object" in bugs_fixed and isinstance(config.get("volumes"), dict):
volumes = config["volumes"]
required_vol_keys = {"data", "logs"}
if required_vol_keys.issubset(volumes.keys()):
bugs_fixed.append("volumes_all_keys_present")
reward += 0.05
else:
missing = required_vol_keys - set(volumes.keys())
error_messages.append(f"Missing volume keys: {missing}")
# ===== FINAL REWARD CALCULATION =====
reward = max(0.01, min(0.90, reward))
error_msg = "; ".join(error_messages) if error_messages else "All checks passed!"
return reward, error_msg, bugs_fixed