# Generated from src/schemas.ts. Do not edit manually.
from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Literal

NAMESPACE = "ai.aletheion.asm"
MAJOR = 1
MINOR = 1

JsonObject = dict[str, Any]

@dataclass(frozen=True, slots=True)
class Header:
    namespace: Literal["ai.aletheion.asm"] = NAMESPACE
    major: Literal[1] = MAJOR
    minor: int = MINOR

    def __post_init__(self) -> None:
        if self.namespace != NAMESPACE or self.major != MAJOR or self.minor < 0:
            raise ValueError("unsupported ASM contract header")

@dataclass(frozen=True, slots=True)
class MemoryContract:
    header: Header
    memory_id: str
    revision: int
    owner_id: str
    project_id: str
    kind: Literal["observation", "fact", "instruction"]
    content: str
    evidence_ids: tuple[str, ...]
    created_at: datetime
    session_id: str | None = None
    tombstoned_at: datetime | None = None
    metadata: JsonObject = field(default_factory=dict)

@dataclass(frozen=True, slots=True)
class EvidenceContract:
    header: Header
    evidence_id: str
    owner_id: str
    project_id: str
    source_type: Literal["user", "tool", "document", "system"]
    digest: str
    captured_at: datetime
    content_type: str
    source_uri: str | None = None
    metadata: JsonObject = field(default_factory=dict)

@dataclass(frozen=True, slots=True)
class RetrievalCandidate:
    memory_id: str
    score: float
    selected: bool
    reason_codes: tuple[str, ...]

@dataclass(frozen=True, slots=True)
class RetrievalContract:
    header: Header
    request_id: str
    owner_id: str
    project_id: str
    query: str
    limit: int
    algorithm: str
    candidates: tuple[RetrievalCandidate, ...]
    started_at: datetime
    latency_ms: int
    session_id: str | None = None

@dataclass(frozen=True, slots=True)
class IntentContract:
    header: Header
    intent_id: str
    operation: Literal["diagnose", "read", "write", "execute", "communicate", "deploy", "purchase", "delete"]
    resources: tuple[str, ...]
    external_effect: bool
    requested_at: datetime
    arguments: JsonObject
    idempotency_key: str | None = None

@dataclass(frozen=True, slots=True)
class PolicyContract:
    header: Header
    decision_id: str
    intent_id: str
    outcome: Literal["allow", "deny", "require_approval"]
    reason_codes: tuple[str, ...]
    required_approvals: tuple[str, ...]
    decided_at: datetime
    policy_version: str

@dataclass(frozen=True, slots=True)
class FeedbackContract:
    header: Header
    feedback_id: str
    target_type: Literal["memory", "retrieval", "action"]
    target_id: str
    rating: Literal["positive", "negative", "correction"]
    created_at: datetime
    comment: str | None = None

@dataclass(frozen=True, slots=True)
class StateSnapshotContract:
    header: Header
    snapshot_id: str
    session_id: str
    sequence: int
    state: JsonObject
    digest: str
    created_at: datetime

@dataclass(frozen=True, slots=True)
class InferenceManifestContract:
    header: Header
    manifest_id: str
    model_id: str
    model_version: str
    backend: Literal["deterministic", "vector", "causal_head", "dual_asm", "asm_cm"]
    contract_majors: dict[str, int]
    parameters: JsonObject
    created_at: datetime
    artifact_digest: str | None = None

REQUIRED_FIELDS: dict[str, frozenset[str]] = {
    "memory": frozenset({"header", "memoryId", "revision", "ownerId", "projectId", "kind", "content", "evidenceIds", "createdAt"}),
    "evidence": frozenset({"header", "evidenceId", "ownerId", "projectId", "sourceType", "digest", "capturedAt", "contentType"}),
    "retrieval": frozenset({"header", "requestId", "ownerId", "projectId", "query", "limit", "algorithm", "candidates", "startedAt", "latencyMs"}),
    "intent": frozenset({"header", "intentId", "operation", "resources", "externalEffect", "requestedAt", "arguments"}),
    "policy": frozenset({"header", "decisionId", "intentId", "outcome", "reasonCodes", "requiredApprovals", "decidedAt", "policyVersion"}),
    "feedback": frozenset({"header", "feedbackId", "targetType", "targetId", "rating", "createdAt"}),
    "stateSnapshot": frozenset({"header", "snapshotId", "sessionId", "sequence", "state", "digest", "createdAt"}),
    "inferenceManifest": frozenset({"header", "manifestId", "modelId", "modelVersion", "backend", "contractMajors", "parameters", "createdAt"}),
}

OPTIONAL_FIELDS: dict[str, frozenset[str]] = {
    "memory": frozenset({"sessionId", "tombstonedAt", "metadata"}),
    "evidence": frozenset({"sourceUri", "metadata"}),
    "retrieval": frozenset({"sessionId"}),
    "intent": frozenset({"idempotencyKey"}),
    "policy": frozenset(),
    "feedback": frozenset({"comment"}),
    "stateSnapshot": frozenset(),
    "inferenceManifest": frozenset({"artifactDigest"}),
}

def validate_wire_contract(name: str, payload: object) -> None:
    if name not in REQUIRED_FIELDS:
        raise ValueError(f"unknown ASM contract: {name}")
    if not isinstance(payload, dict):
        raise ValueError("ASM contract payload must be an object")
    keys = set(payload)
    missing = REQUIRED_FIELDS[name] - keys
    unknown = keys - REQUIRED_FIELDS[name] - OPTIONAL_FIELDS[name]
    if missing:
        raise ValueError(f"missing fields: {sorted(missing)}")
    if unknown:
        raise ValueError(f"unknown fields: {sorted(unknown)}")
    header = payload.get("header")
    if not isinstance(header, dict):
        raise ValueError("header must be an object")
    if set(header) != {"namespace", "major", "minor"}:
        raise ValueError("invalid header fields")
    if header.get("namespace") != NAMESPACE or header.get("major") != MAJOR:
        raise ValueError("unsupported ASM contract header")
    minor = header.get("minor")
    if not isinstance(minor, int) or isinstance(minor, bool) or minor < 0:
        raise ValueError("header minor must be a non-negative integer")
