from __future__ import annotations from dataclasses import dataclass, field from pathlib import Path from typing import Literal ComponentKind = Literal[ "process_v2_intent_router", "process_v2_retrieval_policy_resolver", "process_v2_router_plus_retrieval_policy", "process_v2_router_plus_retrieval_policy_rag", "process_v2_full_chain", ] @dataclass(slots=True, frozen=True) class RouterExpectation: domain: str | None = None intent: str | None = None sub_intent: str | None = None @dataclass(slots=True, frozen=True) class RetrievalPlanExpectation: profile: str | None = None layers: tuple[str, ...] = () limit: int | None = None filters: dict[str, object] = field(default_factory=dict) @dataclass(slots=True, frozen=True) class CaseExpectations: router: RouterExpectation = RouterExpectation() retrieval_plan: RetrievalPlanExpectation = field(default_factory=RetrievalPlanExpectation) route_assertions: dict[str, object] = field(default_factory=dict) retrieval_plan_assertions: dict[str, object] = field(default_factory=dict) rag_assertions: dict[str, object] = field(default_factory=dict) pipeline_assertions: dict[str, object] = field(default_factory=dict) llm_assertions: dict[str, object] = field(default_factory=dict) @dataclass(slots=True, frozen=True) class V4Case: case_id: str component: ComponentKind source_file: Path query: str = "" rag_session_id: str | None = None route: dict[str, object] = field(default_factory=dict) expectations: CaseExpectations = field(default_factory=CaseExpectations) notes: str = "" tags: tuple[str, ...] = () @property def display_input(self) -> str: return self.query or self.route.get("user_query") or self.case_id @dataclass(slots=True, frozen=True) class ExecutionPayload: actual: dict details: dict @dataclass(slots=True) class V4CaseResult: case: V4Case actual: dict details: dict passed: bool mismatches: list[str] = field(default_factory=list)