dempsters-court / dempsters_court /case_loader.py
thangvip's picture
initial push: M1 Belief Engine + M2 Witness Engine + M3 vertical slice (Cases 1)
f6771af verified
Raw
History Blame Contribute Delete
2.69 kB
"""Load case YAML into typed dataclasses."""
from __future__ import annotations
from dataclasses import dataclass, field
from pathlib import Path
import yaml
@dataclass(frozen=True)
class Witness:
id: str
name: str
portrait_ref: str
persona: str
secret_knowledge: str
reliability: float
independence_group: str | None
cost_days: int
is_physical_evidence: bool
target_mass: dict[frozenset[str], float]
@dataclass(frozen=True)
class GroundTruth:
culprit: str
accomplice: str | None
@dataclass(frozen=True)
class CaseData:
case_id: str
title: str
setting_blurb: str
victim: str
dock: list[str]
court_days: int
threshold: float
methods_available: list[str]
witnesses: list[Witness]
ground_truth: GroundTruth
intended_path: str
reveal_expectations: dict
def _parse_mass(raw: dict | None, dock: list[str]) -> dict[frozenset[str], float]:
if not raw:
return {}
dock_set = set(dock)
out: dict[frozenset[str], float] = {}
for key, val in raw.items():
# keys are comma-separated suspect names, e.g. "Gardener,Maid"
names = [s.strip() for s in str(key).split(",")]
for n in names:
if n not in dock_set:
raise ValueError(f"unknown suspect in target_mass: {n!r}")
out[frozenset(names)] = float(val)
return out
def load_case(path: str | Path) -> CaseData:
raw = yaml.safe_load(Path(path).read_text())
dock = list(raw["dock"])
witnesses = [
Witness(
id=w["id"],
name=w["name"],
portrait_ref=w.get("portrait_ref", ""),
persona=w["persona"],
secret_knowledge=w["secret_knowledge"],
reliability=float(w.get("reliability", 1.0)),
independence_group=w.get("independence_group"),
cost_days=int(w.get("cost_days", 1)),
is_physical_evidence=bool(w.get("is_physical_evidence", False)),
target_mass=_parse_mass(w.get("target_mass"), dock),
)
for w in raw["witnesses"]
]
gt = raw["ground_truth"]
return CaseData(
case_id=raw["case_id"],
title=raw["title"],
setting_blurb=raw["setting_blurb"],
victim=raw["victim"],
dock=dock,
court_days=int(raw["court_days"]),
threshold=float(raw["threshold"]),
methods_available=list(raw["methods_available"]),
witnesses=witnesses,
ground_truth=GroundTruth(culprit=gt["culprit"], accomplice=gt.get("accomplice")),
intended_path=raw.get("intended_path", ""),
reveal_expectations=raw.get("reveal_expectations", {}),
)