from __future__ import annotations from typing import Any, Literal, TypedDict Completeness = Literal["complete", "partial", "missing"] Resolution = Literal["resolved", "partial", "missing", "unsafe"] class EvidenceSpec(TypedDict): availability: Literal[ "direct-read", "returned-to-agent", "available-upstream", "produced-by-run", "visualization-derived", "unavailable", ] adoption: Literal[ "explicitly-adopted", "explicitly-rejected", "not-recorded", "not-applicable", ] confidence: Literal["exact", "safe-association", "deterministic", "unconfirmed"] class SourceBinding(TypedDict): id: str sourceId: str role: Literal["input", "basis", "constraint", "process", "output", "status"] selector: dict[str, Any] transform: dict[str, Any] evidence: EvidenceSpec resolution: Resolution class SourceRecord(TypedDict, total=False): id: str kind: Literal[ "database", "runtime-event", "artifact", "log-anchor", "calculation", "historical-fallback", "missing", ] label: str locator: dict[str, Any] status: str durationMs: int | None completeness: Completeness resultState: Literal["present", "empty", "missing", "unavailable"] truncated: bool omittedCharacters: int selectedValues: list[dict[str, Any]] rawRecord: Any def unresolved_binding( binding_id: str, *, reason: str, role: str = "basis", source_id: str | None = None, resolution: Resolution = "missing", code: str | None = None, ) -> SourceBinding: selector = {"kind": "unresolved", "reason": reason} if code: selector["code"] = code return { "id": binding_id, "sourceId": source_id or f"missing:{binding_id}", "role": role, # type: ignore[typeddict-item] "selector": selector, "transform": {"kind": "direct"}, "evidence": { "availability": "unavailable", "adoption": "not-recorded", "confidence": "unconfirmed", }, "resolution": resolution, }