"""Tarot 응답 스키마 검증 — 누락·빈 필드 reroll 트리거.""" VALID_CONFIDENCE = {"high", "medium", "low"} def validate_interpretation(parsed: dict, spread_type: str) -> tuple[bool, str]: if not isinstance(parsed, dict): return False, "응답이 dict가 아님" for k in ("summary", "cards", "interactions", "advice", "confidence"): if k not in parsed: return False, f"필수 필드 누락: {k}" if parsed.get("confidence") not in VALID_CONFIDENCE: return False, f"confidence 값 비정상: {parsed.get('confidence')}" cards = parsed.get("cards") if not isinstance(cards, list) or not cards: return False, "cards가 빈 배열" for i, c in enumerate(cards): if not isinstance(c, dict): return False, f"cards[{i}] dict 아님" for k in ("position", "card", "reversed", "interpretation", "advice", "evidence"): if k not in c: return False, f"cards[{i}].{k} 누락" ev = c["evidence"] if not isinstance(ev, dict): return False, f"cards[{i}].evidence dict 아님" for k in ("card_meaning_used", "position_logic", "category_lens"): if k not in ev: return False, f"cards[{i}].evidence.{k} 누락" if not isinstance(ev[k], str) or not ev[k].strip(): return False, f"cards[{i}].evidence.{k} 빈 문자열" interactions = parsed.get("interactions") if not isinstance(interactions, list): return False, "interactions가 list 아님" if spread_type == "three_card" and len(interactions) == 0: return False, "three_card는 interactions 1개 이상 필요" return True, ""