import uuid from datetime import datetime from typing import Literal from pydantic import BaseModel, ConfigDict, Field LegacyInterfaceKind = Literal[ "rest_api", "mcp_tool", "procedure_call", "event_subject", "cli", "dashboard_route", "schema_field", ] LegacyInterfaceStatus = Literal["legacy", "retirement_candidate", "retired"] class LegacyInterfaceRegister(BaseModel): interface_key: str interface_kind: LegacyInterfaceKind = "rest_api" replacement_ref: str owner_component: str = "state-hub" replacement_verified: bool = False manual_hold: bool = False hold_reason: str | None = None notes: str | None = None class LegacyInterfacePatch(BaseModel): replacement_ref: str | None = None owner_component: str | None = None status: LegacyInterfaceStatus | None = None replacement_verified: bool | None = None manual_hold: bool | None = None hold_reason: str | None = None notes: str | None = None class LegacyUsageRecord(BaseModel): interface_key: str interface_kind: LegacyInterfaceKind = "rest_api" replacement_ref: str owner_component: str = "state-hub" replacement_verified: bool = False tenant_key: str | None = None user_key: str | None = None component_key: str | None = None observed_at: datetime | None = None call_count: int = Field(default=1, ge=1) class LegacyInterfaceRead(BaseModel): model_config = ConfigDict(from_attributes=True) id: uuid.UUID interface_key: str interface_kind: str legacy_since: datetime replacement_ref: str owner_component: str status: str replacement_verified: bool manual_hold: bool hold_reason: str | None = None notes: str | None = None retired_at: datetime | None = None created_at: datetime updated_at: datetime class LegacyUsageCounters(BaseModel): calls: int = 0 tenant_count: int = 0 user_count: int = 0 component_count: int = 0 tenants: dict[str, int] = Field(default_factory=dict) users: dict[str, int] = Field(default_factory=dict) components: dict[str, int] = Field(default_factory=dict) class LegacyInterfaceSummary(BaseModel): interface: LegacyInterfaceRead all_time: LegacyUsageCounters window: LegacyUsageCounters last_seen_at: datetime | None = None retirement_candidate: bool retirement_reason: str class LegacyUsageSummary(BaseModel): generated_at: datetime window_start: datetime window_end: datetime interfaces: list[LegacyInterfaceSummary] class LegacyWeeklyReview(BaseModel): generated_at: datetime window_start: datetime window_end: datetime cadence: str = "weekly" activity_core_handoff: dict[str, str] interfaces: list[LegacyInterfaceSummary] retirement_candidates: list[LegacyInterfaceSummary]