export type SourceStatus = 'present' | 'partial' | 'absent'
export interface SourceCoverage { status: SourceStatus; observedAt?: string; coverageFrom?: string; error?: string; scopes?: { complete: string[]; incomplete: string[] } }
export interface Evidence { source: 'kubernetes' | 'builds' | 'ledger'; field: string; value: string }
export interface CoverageGap { source: string; reason: string; scope?: string }
export interface ResourceValues { cpuCores: number | null; memoryBytes: number | null }
export interface WorkloadPlacement {
  cluster: string; namespace: string; kind: 'Job' | 'Pod'; name: string; uid: string
  podUid: string | null; podName: string | null; nodeName: string | null; phase: string | null; reason: string | null
  createdAt: string | null; startedAt: string | null; finishedAt: string | null
  containers: Array<{ name: string; state: string | null; reason: string | null; restartCount: number | null; requests: ResourceValues; limits: ResourceValues }>
  requests: ResourceValues; limits: ResourceValues; utilization: ResourceValues
  ownerReference: { kind: string; name: string; uid: string } | null
  annotations: { buildKey: string | null; podBuildKey: string | null; jobBuildKey: string | null; sessionId: string | null; conflict: boolean }
  buildKey: string | null; sessionId: string | null; evidence: Evidence[]; historical: boolean
}
export interface SessionPlacement {
  sessionId: string; buildKey?: string; nodeName?: string; workloadUid?: string
  confidence: 'exact' | 'host-only' | 'unplaced'; evidence: Evidence[]; gaps: CoverageGap[]
  session: { id: string; runtime: string; cwd: string; host: string | null; state: string; title: string | null; activity: string | null; buildKey?: string | null; runId?: string | null; workloadUid?: string | null }
}
export interface BuildPlacement { buildKey: string; nodeName: string | null; workloadUid: string | null; sessionId: string | null; confidence: 'exact' | 'unplaced'; evidence: Evidence[]; gaps: CoverageGap[]; historical: boolean }
export interface ClusterNode {
  name: string; uid: string; ready: boolean | null
  conditions: Array<{ type: string; status: string; reason: string | null; observedAt: string | null }>
  taints: Array<{ key: string; value: string | null; effect: string }>
  capacity: ResourceValues; allocatable: ResourceValues; utilization: ResourceValues; requests: ResourceValues; limits: ResourceValues
  workloadCounts: { running: number; pending: number; failed: number }; restartCount: number | null
  sessions: SessionPlacement[]; builds: BuildPlacement[]; workloads: WorkloadPlacement[]
  sourceTimestamps: Record<string, string | null>; coverageGaps: CoverageGap[]
}
export interface ClusterSources { kubernetes: SourceCoverage; prometheus: SourceCoverage; ledger: SourceCoverage; builds: SourceCoverage }
export interface ClusterSnapshot {
  observedAt: string; cluster: { id: string; version?: string; state: 'reachable' | 'degraded' }; sources: ClusterSources
  summary: { readyNodes: number | null; totalNodes: number | null; runningWorkloads: number | null; pendingWorkloads: number | null; failedWorkloads: number | null; requestedCpuCores: number | null; requestedMemoryBytes: number | null; usedCpuCores: number | null; usedMemoryBytes: number | null }
  nodes: ClusterNode[]; unplacedSessions: SessionPlacement[]; unmatchedWorkloads: WorkloadPlacement[]; unplacedBuilds: BuildPlacement[]
  links?: { grafana?: string; headlamp?: string }
}
export interface ClusterNodeResponse { observedAt: string; sources: ClusterSources; node: ClusterNode }
