import uuid from datetime import datetime from typing import Any, Literal from pydantic import BaseModel, ConfigDict, Field MappingFit = Literal["direct", "partial", "conflict", "gap", "unknown"] EvidenceState = Literal["observed", "declared", "inferred", "proposed", "gap"] class FabricGraphSource(BaseModel): model_config = ConfigDict(extra="forbid") repo: str | None = None commit: str | None = None path: str | None = None class FabricGraphNodePayload(BaseModel): model_config = ConfigDict(extra="forbid") id: str kind: str name: str repo: str domain: str lifecycle: str canon_category: str | None = None canon_anchor: str | None = None mapping_fit: MappingFit | None = None evidence_state: EvidenceState | None = None attributes: dict[str, Any] = Field(default_factory=dict) class FabricGraphEdgePayload(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) from_graph_id: str = Field(alias="from") to_graph_id: str = Field(alias="to") edge_type: str = Field(alias="type") canonical_type: str | None = None canon_anchor: str | None = None mapping_fit: MappingFit | None = None display_only: bool | None = None evidence_state: EvidenceState | None = None attributes: dict[str, Any] = Field(default_factory=dict) class FabricGraphExportPayload(BaseModel): model_config = ConfigDict(extra="forbid", populate_by_name=True) api_version: Literal["railiance.fabric/v1alpha1"] = Field(alias="apiVersion") kind: Literal["FabricGraphExport"] generated_at: datetime | None = None source: FabricGraphSource | None = None nodes: list[FabricGraphNodePayload] edges: list[FabricGraphEdgePayload] class FabricGraphPullRequest(BaseModel): source_repo_slug: str = "railiance-fabric" source_url: str = "http://127.0.0.1:8765/exports/state-hub" requested_by: str = "operator" class FabricGraphImportRead(BaseModel): model_config = ConfigDict(from_attributes=True) id: uuid.UUID source_repo_slug: str source_url: str | None = None source_commit: str | None = None source_path: str | None = None api_version: str | None = None export_kind: str | None = None exported_at: datetime | None = None content_hash: str node_count: int edge_count: int validation_status: str error_details: dict | None = None is_latest: bool last_seen_at: datetime | None = None created_at: datetime updated_at: datetime class FabricGraphIngestResult(BaseModel): import_run: FabricGraphImportRead created: bool idempotent: bool node_count: int edge_count: int class FabricGraphNodeRead(BaseModel): model_config = ConfigDict(from_attributes=True) id: uuid.UUID import_id: uuid.UUID source_repo_slug: str graph_id: str kind: str name: str repo_slug: str domain_slug: str lifecycle: str canonical_type: str | None = None canon_category: str | None = None canon_anchor: str | None = None mapping_fit: str | None = None evidence_state: str | None = None display_only: bool attributes: dict raw_json: dict class FabricGraphEdgeRead(BaseModel): model_config = ConfigDict(from_attributes=True) id: uuid.UUID import_id: uuid.UUID source_repo_slug: str edge_key: str from_graph_id: str to_graph_id: str edge_type: str canonical_type: str | None = None canon_anchor: str | None = None mapping_fit: str | None = None evidence_state: str | None = None display_only: bool attributes: dict raw_json: dict class FabricGraphSummary(BaseModel): source_repo_slug: str latest_import: FabricGraphImportRead | None = None node_count: int edge_count: int nodes_by_domain: dict[str, int] nodes_by_repo: dict[str, int] nodes_by_canon_category: dict[str, int] edges_by_canonical_type: dict[str, int] nodes_by_evidence_state: dict[str, int] edges_by_evidence_state: dict[str, int] nodes_by_mapping_fit: dict[str, int] edges_by_mapping_fit: dict[str, int] example_nodes: list[FabricGraphNodeRead] example_edges: list[FabricGraphEdgeRead]