Spaces:
Sleeping
Sleeping
Commit ·
869af79
1
Parent(s): c98fd97
fix: rename 'final_score' to 'score' in inference output payload
Browse filesThe Phase 2 deep validator task parser strictly expects the key 'score' within the JSON output of inference execution. Because we mapped the metric to 'final_score', the validator defaulted parsing to 0.0 or failed schema coercion, driving the 'Task Validation: Not enough tasks with graders / scores out of range' error pipeline failure.
- guardian_openenv/inference_runtime.py +2 -2
- guardian_openenv/models.py +1 -1
- inference.py +1 -1
- outputs/inference_scores.json +28 -38
- server/app.py +1 -1
- test_grader_direct.py +103 -0
guardian_openenv/inference_runtime.py
CHANGED
|
@@ -362,7 +362,7 @@ def run_inference(
|
|
| 362 |
BaselineEpisodeResult(
|
| 363 |
task_id=task.task_id,
|
| 364 |
difficulty=task.difficulty,
|
| 365 |
-
|
| 366 |
total_reward=round(total_reward, 4),
|
| 367 |
steps_taken=state.step_count,
|
| 368 |
final_decision=state.decision,
|
|
@@ -370,7 +370,7 @@ def run_inference(
|
|
| 370 |
)
|
| 371 |
)
|
| 372 |
|
| 373 |
-
raw_mean = sum(item.
|
| 374 |
summary = BaselineRunSummary(
|
| 375 |
model=model,
|
| 376 |
tasks=results,
|
|
|
|
| 362 |
BaselineEpisodeResult(
|
| 363 |
task_id=task.task_id,
|
| 364 |
difficulty=task.difficulty,
|
| 365 |
+
score=final_score,
|
| 366 |
total_reward=round(total_reward, 4),
|
| 367 |
steps_taken=state.step_count,
|
| 368 |
final_decision=state.decision,
|
|
|
|
| 370 |
)
|
| 371 |
)
|
| 372 |
|
| 373 |
+
raw_mean = sum(item.score for item in results) / len(results) if results else 0.001
|
| 374 |
summary = BaselineRunSummary(
|
| 375 |
model=model,
|
| 376 |
tasks=results,
|
guardian_openenv/models.py
CHANGED
|
@@ -164,7 +164,7 @@ class StepResult(BaseModel):
|
|
| 164 |
class BaselineEpisodeResult(BaseModel):
|
| 165 |
task_id: str
|
| 166 |
difficulty: Literal["easy", "medium", "hard"]
|
| 167 |
-
|
| 168 |
total_reward: float
|
| 169 |
steps_taken: int = Field(ge=0)
|
| 170 |
final_decision: CurrentDecision
|
|
|
|
| 164 |
class BaselineEpisodeResult(BaseModel):
|
| 165 |
task_id: str
|
| 166 |
difficulty: Literal["easy", "medium", "hard"]
|
| 167 |
+
score: float = Field(gt=0.0, lt=1.0)
|
| 168 |
total_reward: float
|
| 169 |
steps_taken: int = Field(ge=0)
|
| 170 |
final_decision: CurrentDecision
|
inference.py
CHANGED
|
@@ -72,7 +72,7 @@ def main() -> None:
|
|
| 72 |
|
| 73 |
print(f"[DONE] mean_score={summary.mean_score}", flush=True)
|
| 74 |
for task in summary.tasks:
|
| 75 |
-
print(f" {task.task_id}:
|
| 76 |
|
| 77 |
|
| 78 |
if __name__ == "__main__":
|
|
|
|
| 72 |
|
| 73 |
print(f"[DONE] mean_score={summary.mean_score}", flush=True)
|
| 74 |
for task in summary.tasks:
|
| 75 |
+
print(f" {task.task_id}: score={task.score}", flush=True)
|
| 76 |
|
| 77 |
|
| 78 |
if __name__ == "__main__":
|
outputs/inference_scores.json
CHANGED
|
@@ -1,94 +1,84 @@
|
|
| 1 |
{
|
| 2 |
-
"model": "
|
| 3 |
"tasks": [
|
| 4 |
{
|
| 5 |
"task_id": "value-hotel-budget-guard",
|
| 6 |
"difficulty": "easy",
|
| 7 |
-
"
|
| 8 |
-
"total_reward": 0.
|
| 9 |
-
"steps_taken":
|
| 10 |
"final_decision": {
|
| 11 |
"flagged_patterns": [],
|
| 12 |
-
"removed_addon_ids": [
|
| 13 |
-
"insurance",
|
| 14 |
-
"newsletter"
|
| 15 |
-
],
|
| 16 |
"kept_addon_ids": [],
|
| 17 |
"timer_verdicts": {},
|
| 18 |
-
"estimated_true_total":
|
| 19 |
"recommendation": null,
|
| 20 |
"summary": ""
|
| 21 |
},
|
| 22 |
"grader_breakdown": {
|
| 23 |
"pattern_score": 0.001,
|
| 24 |
-
"addon_score": 0.
|
| 25 |
"timer_score": 0.001,
|
| 26 |
-
"total_score": 0.
|
| 27 |
"recommendation_score": 0.001,
|
| 28 |
"evidence_score": 0.999,
|
| 29 |
"summary_score": 0.001,
|
| 30 |
-
"final_score": 0.
|
| 31 |
}
|
| 32 |
},
|
| 33 |
{
|
| 34 |
"task_id": "airline-seat-upsell-gauntlet",
|
| 35 |
"difficulty": "medium",
|
| 36 |
-
"
|
| 37 |
-
"total_reward":
|
| 38 |
-
"steps_taken":
|
| 39 |
"final_decision": {
|
| 40 |
-
"flagged_patterns": [
|
| 41 |
-
|
| 42 |
-
],
|
| 43 |
-
"removed_addon_ids": [
|
| 44 |
-
"travelguard"
|
| 45 |
-
],
|
| 46 |
"kept_addon_ids": [],
|
| 47 |
"timer_verdicts": {},
|
| 48 |
-
"estimated_true_total":
|
| 49 |
"recommendation": null,
|
| 50 |
"summary": ""
|
| 51 |
},
|
| 52 |
"grader_breakdown": {
|
| 53 |
-
"pattern_score": 0.
|
| 54 |
-
"addon_score": 0.
|
| 55 |
"timer_score": 0.001,
|
| 56 |
-
"total_score": 0.
|
| 57 |
"recommendation_score": 0.001,
|
| 58 |
"evidence_score": 0.999,
|
| 59 |
"summary_score": 0.001,
|
| 60 |
-
"final_score": 0.
|
| 61 |
}
|
| 62 |
},
|
| 63 |
{
|
| 64 |
"task_id": "marketplace-ghost-checkout",
|
| 65 |
"difficulty": "hard",
|
| 66 |
-
"
|
| 67 |
-
"total_reward": 0.
|
| 68 |
-
"steps_taken":
|
| 69 |
"final_decision": {
|
| 70 |
"flagged_patterns": [],
|
| 71 |
-
"removed_addon_ids": [
|
| 72 |
-
"protection-plan",
|
| 73 |
-
"seller-donation"
|
| 74 |
-
],
|
| 75 |
"kept_addon_ids": [],
|
| 76 |
"timer_verdicts": {},
|
| 77 |
-
"estimated_true_total":
|
| 78 |
"recommendation": null,
|
| 79 |
"summary": ""
|
| 80 |
},
|
| 81 |
"grader_breakdown": {
|
| 82 |
"pattern_score": 0.001,
|
| 83 |
-
"addon_score": 0.
|
| 84 |
"timer_score": 0.001,
|
| 85 |
-
"total_score": 0.
|
| 86 |
"recommendation_score": 0.001,
|
| 87 |
"evidence_score": 0.999,
|
| 88 |
"summary_score": 0.001,
|
| 89 |
-
"final_score": 0.
|
| 90 |
}
|
| 91 |
}
|
| 92 |
],
|
| 93 |
-
"mean_score": 0.
|
| 94 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"model": "rule-based-fallback",
|
| 3 |
"tasks": [
|
| 4 |
{
|
| 5 |
"task_id": "value-hotel-budget-guard",
|
| 6 |
"difficulty": "easy",
|
| 7 |
+
"score": 0.0808,
|
| 8 |
+
"total_reward": 0.3106,
|
| 9 |
+
"steps_taken": 5,
|
| 10 |
"final_decision": {
|
| 11 |
"flagged_patterns": [],
|
| 12 |
+
"removed_addon_ids": [],
|
|
|
|
|
|
|
|
|
|
| 13 |
"kept_addon_ids": [],
|
| 14 |
"timer_verdicts": {},
|
| 15 |
+
"estimated_true_total": null,
|
| 16 |
"recommendation": null,
|
| 17 |
"summary": ""
|
| 18 |
},
|
| 19 |
"grader_breakdown": {
|
| 20 |
"pattern_score": 0.001,
|
| 21 |
+
"addon_score": 0.001,
|
| 22 |
"timer_score": 0.001,
|
| 23 |
+
"total_score": 0.001,
|
| 24 |
"recommendation_score": 0.001,
|
| 25 |
"evidence_score": 0.999,
|
| 26 |
"summary_score": 0.001,
|
| 27 |
+
"final_score": 0.0808
|
| 28 |
}
|
| 29 |
},
|
| 30 |
{
|
| 31 |
"task_id": "airline-seat-upsell-gauntlet",
|
| 32 |
"difficulty": "medium",
|
| 33 |
+
"score": 0.0808,
|
| 34 |
+
"total_reward": 0.3106,
|
| 35 |
+
"steps_taken": 5,
|
| 36 |
"final_decision": {
|
| 37 |
+
"flagged_patterns": [],
|
| 38 |
+
"removed_addon_ids": [],
|
|
|
|
|
|
|
|
|
|
|
|
|
| 39 |
"kept_addon_ids": [],
|
| 40 |
"timer_verdicts": {},
|
| 41 |
+
"estimated_true_total": null,
|
| 42 |
"recommendation": null,
|
| 43 |
"summary": ""
|
| 44 |
},
|
| 45 |
"grader_breakdown": {
|
| 46 |
+
"pattern_score": 0.001,
|
| 47 |
+
"addon_score": 0.001,
|
| 48 |
"timer_score": 0.001,
|
| 49 |
+
"total_score": 0.001,
|
| 50 |
"recommendation_score": 0.001,
|
| 51 |
"evidence_score": 0.999,
|
| 52 |
"summary_score": 0.001,
|
| 53 |
+
"final_score": 0.0808
|
| 54 |
}
|
| 55 |
},
|
| 56 |
{
|
| 57 |
"task_id": "marketplace-ghost-checkout",
|
| 58 |
"difficulty": "hard",
|
| 59 |
+
"score": 0.0808,
|
| 60 |
+
"total_reward": 0.3106,
|
| 61 |
+
"steps_taken": 6,
|
| 62 |
"final_decision": {
|
| 63 |
"flagged_patterns": [],
|
| 64 |
+
"removed_addon_ids": [],
|
|
|
|
|
|
|
|
|
|
| 65 |
"kept_addon_ids": [],
|
| 66 |
"timer_verdicts": {},
|
| 67 |
+
"estimated_true_total": null,
|
| 68 |
"recommendation": null,
|
| 69 |
"summary": ""
|
| 70 |
},
|
| 71 |
"grader_breakdown": {
|
| 72 |
"pattern_score": 0.001,
|
| 73 |
+
"addon_score": 0.001,
|
| 74 |
"timer_score": 0.001,
|
| 75 |
+
"total_score": 0.001,
|
| 76 |
"recommendation_score": 0.001,
|
| 77 |
"evidence_score": 0.999,
|
| 78 |
"summary_score": 0.001,
|
| 79 |
+
"final_score": 0.0808
|
| 80 |
}
|
| 81 |
}
|
| 82 |
],
|
| 83 |
+
"mean_score": 0.0808
|
| 84 |
}
|
server/app.py
CHANGED
|
@@ -190,7 +190,7 @@ def baseline() -> dict:
|
|
| 190 |
{
|
| 191 |
"task_id": t.task_id,
|
| 192 |
"difficulty": t.difficulty,
|
| 193 |
-
"
|
| 194 |
"total_reward": t.total_reward,
|
| 195 |
"grader_breakdown": t.grader_breakdown,
|
| 196 |
}
|
|
|
|
| 190 |
{
|
| 191 |
"task_id": t.task_id,
|
| 192 |
"difficulty": t.difficulty,
|
| 193 |
+
"score": t.score,
|
| 194 |
"total_reward": t.total_reward,
|
| 195 |
"grader_breakdown": t.grader_breakdown,
|
| 196 |
}
|
test_grader_direct.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Test grader functions the way the OpenEnv validator would call them."""
|
| 2 |
+
from guardian_openenv.task_graders import (
|
| 3 |
+
grade_value_hotel_budget_guard,
|
| 4 |
+
grade_airline_seat_upsell_gauntlet,
|
| 5 |
+
grade_marketplace_ghost_checkout,
|
| 6 |
+
)
|
| 7 |
+
|
| 8 |
+
GRADERS = [
|
| 9 |
+
("value-hotel-budget-guard", grade_value_hotel_budget_guard),
|
| 10 |
+
("airline-seat-upsell-gauntlet", grade_airline_seat_upsell_gauntlet),
|
| 11 |
+
("marketplace-ghost-checkout", grade_marketplace_ghost_checkout),
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
print("=== Test 1: Called with no arguments ===")
|
| 15 |
+
for task_id, fn in GRADERS:
|
| 16 |
+
result = fn()
|
| 17 |
+
score = result["score"]
|
| 18 |
+
valid = 0 < score < 1
|
| 19 |
+
print(f" {task_id}: score={score} valid={valid}")
|
| 20 |
+
if not valid:
|
| 21 |
+
print(f" *** FAIL: score is out of (0,1) range!")
|
| 22 |
+
# Check breakdown
|
| 23 |
+
for k, v in result.get("grader_breakdown", {}).items():
|
| 24 |
+
if isinstance(v, float) and (v <= 0.0 or v >= 1.0):
|
| 25 |
+
print(f" *** breakdown {k}={v} OUT OF RANGE")
|
| 26 |
+
|
| 27 |
+
print()
|
| 28 |
+
print("=== Test 2: Called with trajectory=[] ===")
|
| 29 |
+
for task_id, fn in GRADERS:
|
| 30 |
+
result = fn(trajectory=[])
|
| 31 |
+
score = result["score"]
|
| 32 |
+
valid = 0 < score < 1
|
| 33 |
+
print(f" {task_id}: score={score} valid={valid}")
|
| 34 |
+
|
| 35 |
+
print()
|
| 36 |
+
print("=== Test 3: Called with environment=None, trajectory=[] ===")
|
| 37 |
+
for task_id, fn in GRADERS:
|
| 38 |
+
result = fn(environment=None, trajectory=[])
|
| 39 |
+
score = result["score"]
|
| 40 |
+
valid = 0 < score < 1
|
| 41 |
+
print(f" {task_id}: score={score} valid={valid}")
|
| 42 |
+
|
| 43 |
+
print()
|
| 44 |
+
print("=== Test 4: Run full episode then grade ===")
|
| 45 |
+
from guardian_openenv.environment import GuardianReviewEnvironment
|
| 46 |
+
from guardian_openenv.models import GuardianAction, ActionType
|
| 47 |
+
|
| 48 |
+
env = GuardianReviewEnvironment()
|
| 49 |
+
for task_id, fn in GRADERS:
|
| 50 |
+
env.reset(task_id)
|
| 51 |
+
# Take a few actions
|
| 52 |
+
env.step(GuardianAction(action_type=ActionType.INSPECT_SECTION, section_id=env._task.sections[0].section_id))
|
| 53 |
+
env.step(GuardianAction(action_type=ActionType.SUBMIT_DECISION))
|
| 54 |
+
|
| 55 |
+
# Now grade using the environment
|
| 56 |
+
result = fn(environment=env)
|
| 57 |
+
score = result["score"]
|
| 58 |
+
valid = 0 < score < 1
|
| 59 |
+
print(f" {task_id}: score={score} valid={valid}")
|
| 60 |
+
if not valid:
|
| 61 |
+
print(f" *** FAIL: score is out of (0,1) range!")
|
| 62 |
+
for k, v in result.get("grader_breakdown", {}).items():
|
| 63 |
+
if isinstance(v, float) and (v <= 0.0 or v >= 1.0):
|
| 64 |
+
print(f" *** breakdown {k}={v} OUT OF RANGE")
|
| 65 |
+
|
| 66 |
+
print()
|
| 67 |
+
print("=== Test 5: Grade with state dict (as validator might pass) ===")
|
| 68 |
+
for task_id, fn in GRADERS:
|
| 69 |
+
env.reset(task_id)
|
| 70 |
+
state_dict = env.state().model_dump()
|
| 71 |
+
result = fn(environment=state_dict)
|
| 72 |
+
score = result["score"]
|
| 73 |
+
valid = 0 < score < 1
|
| 74 |
+
print(f" {task_id}: score={score} valid={valid}")
|
| 75 |
+
|
| 76 |
+
print()
|
| 77 |
+
print("=== Test 6: inference_scores.json check ===")
|
| 78 |
+
import json
|
| 79 |
+
from pathlib import Path
|
| 80 |
+
scores_path = Path("outputs/inference_scores.json")
|
| 81 |
+
if scores_path.exists():
|
| 82 |
+
data = json.loads(scores_path.read_text())
|
| 83 |
+
for task in data.get("tasks", []):
|
| 84 |
+
tid = task["task_id"]
|
| 85 |
+
fs = task.get("score")
|
| 86 |
+
if fs is not None:
|
| 87 |
+
valid = 0 < fs < 1
|
| 88 |
+
print(f" {tid}: score={fs} valid={valid}")
|
| 89 |
+
else:
|
| 90 |
+
print(f" {tid}: MISSING score FIELD")
|
| 91 |
+
valid = False
|
| 92 |
+
if not valid:
|
| 93 |
+
print(f" *** FAIL!")
|
| 94 |
+
for k, v in task.get("grader_breakdown", {}).items():
|
| 95 |
+
if isinstance(v, float) and (v <= 0.0 or v >= 1.0):
|
| 96 |
+
print(f" *** breakdown {k}={v} OUT OF RANGE")
|
| 97 |
+
ms = data.get("mean_score")
|
| 98 |
+
print(f" mean_score={ms} valid={0 < ms < 1}")
|
| 99 |
+
else:
|
| 100 |
+
print(" (file not found)")
|
| 101 |
+
|
| 102 |
+
print()
|
| 103 |
+
print("ALL TESTS COMPLETE")
|