"""Feedback labels: one label artifact per human-review decision, for metrics.""" import json import os from datetime import datetime, timezone def _as_dict(value) -> dict: return value if isinstance(value, dict) else {} def decision_to_label(queue_item: dict, decision: dict, job: dict) -> dict: """Build one feedback label from a queue item, its decision, and the job. All field access is defensive: missing fields degrade to None (or [] for models_used) rather than raising. """ queue_item = _as_dict(queue_item) decision = _as_dict(decision) job = _as_dict(job) payload = _as_dict(queue_item.get("payload")) summary = _as_dict(_as_dict(job.get("report")).get("summary")) return { "review_item_id": queue_item.get("review_item_id"), "job_id": job.get("job_id"), "pipeline_mode": job.get("pipeline_mode"), "source_stage": payload.get("source_stage"), "category": payload.get("category"), "severity": payload.get("severity"), "confidence": payload.get("confidence"), "decision": decision.get("decision"), "reason_code": decision.get("reason_code"), "location": payload.get("location"), "disciplines": payload.get("disciplines"), "sheets": payload.get("sheets"), "drawing_type": payload.get("drawing_type"), "models_used": summary.get("models_used") or [], "created_at": datetime.now(timezone.utc).isoformat(), } def write_label(out_dir: str, label: dict) -> None: """Append one label as a JSON line; never raises on I/O failure.""" try: review_dir = os.path.join(out_dir, "review") os.makedirs(review_dir, exist_ok=True) path = os.path.join(review_dir, "feedback_labels.jsonl") with open(path, "a", encoding="utf-8") as f: f.write(json.dumps(label) + "\n") except OSError as e: print(f"[Review] feedback label write failed: {e}")