import type { AiEvidence, AuthorityTier, ClaimScope, ClaimStatus, ConfidenceLevel, DensityView, EventType, FacilityStatus, FacilityType, GeoPrecision, MapLayer, OperatorKind, ProjectStage, Significance, SourceKind } from "@dci/core"; /** Semantic status groups → one colour token each (shared by badges, map, charts). */ export type StatusTone = "operational" | "construction" | "planned" | "permitting" | "delayed" | "closed" | "rumored" | "unknown"; export const STATUS_TONE: Record = { operational: "operational", partially_operational: "operational", expansion: "operational", under_construction: "construction", announced: "planned", proposed: "planned", permitting: "permitting", approved: "permitting", delayed: "delayed", cancelled: "closed", closed: "closed", rumored: "rumored", unknown: "unknown", }; export const STATUS_LABEL: Record = { rumored: "Rumored", proposed: "Proposed", announced: "Announced", permitting: "Permitting", approved: "Approved", under_construction: "Under construction", partially_operational: "Partially operational", operational: "Operational", expansion: "Expansion", delayed: "Delayed", cancelled: "Cancelled", closed: "Closed", unknown: "Unknown", }; export const STATUS_SHORT: Record = { ...STATUS_LABEL, under_construction: "Construction", partially_operational: "Partial", }; /** Display order used by legends, stacked bars and filter chips. */ export const STATUS_ORDER: FacilityStatus[] = [ "operational", "partially_operational", "expansion", "under_construction", "approved", "permitting", "announced", "proposed", "rumored", "delayed", "cancelled", "closed", "unknown", ]; /** CSS variable name for a tone — resolved at paint time so the map / SVG follow the theme. */ export function statusVar(status: FacilityStatus | StatusTone): string { const tone = (status in STATUS_TONE ? STATUS_TONE[status as FacilityStatus] : status) as StatusTone; return `var(--st-${tone})`; } export const TYPE_LABEL: Record = { colocation: "Colocation", hyperscale: "Hyperscale", cloud_region: "Cloud region", edge: "Edge", carrier_hotel: "Carrier hotel", internet_exchange: "Internet exchange", ai: "AI", hpc: "HPC", sovereign_cloud: "Sovereign cloud", government: "Government", research: "Research", enterprise: "Enterprise", telecom: "Telecom", wholesale: "Wholesale", unknown: "Unknown", }; export const CONFIDENCE_LABEL: Record = { verified: "Verified", high: "High confidence", moderate: "Moderate confidence", estimated: "Estimated", unverified: "Unverified", }; export const CONFIDENCE_SHORT: Record = { verified: "Verified", high: "High", moderate: "Moderate", estimated: "Estimate", unverified: "Unverified", }; /** 0..4 dots filled for the confidence meter. */ export const CONFIDENCE_RANK: Record = { verified: 4, high: 3, moderate: 2, estimated: 1, unverified: 0 }; export const PRECISION_LABEL: Record = { exact: "Exact location", parcel: "Parcel", street: "Street level", city: "City level", metro: "Metro level", approximate: "Approximate", unknown: "Location unknown", }; export const PRECISION_SHORT: Record = { exact: "Exact", parcel: "Parcel", street: "Street", city: "City", metro: "Metro", approximate: "Approx.", unknown: "Unknown", }; /** True when the point should be drawn as a hollow ring (not a precise site). */ export function isImprecise(p: GeoPrecision): boolean { return p === "city" || p === "metro" || p === "approximate" || p === "unknown"; } export const OPERATOR_KIND_LABEL: Record = { colocation: "Colocation", hyperscaler: "Hyperscaler", cloud: "Cloud", carrier: "Carrier", enterprise: "Enterprise", government: "Government", research: "Research", developer: "Developer", investor: "Investor", ixp_operator: "IXP operator", other: "Other", }; export const SOURCE_KIND_LABEL: Record = { operator: "Operator", government: "Government", filing: "Filing", utility: "Utility", dataset: "Dataset", community: "Community", secondary: "Secondary", news: "News", cloud_provider: "Cloud provider", registry: "Registry", }; export const EVENT_LABEL: Record = { facility_discovered: "New facility", facility_updated: "Facility updated", status_changed: "Status change", capacity_changed: "Capacity change", planned_capacity_changed: "Planned capacity", opening_date_changed: "Opening date", operator_changed: "Operator change", owner_changed: "Owner change", project_announced: "Project announced", project_status_changed: "Project status", phase_announced: "Phase announced", planning_filed: "Planning filed", planning_approved: "Planning approved", construction_started: "Construction started", facility_opened: "Facility opened", expansion_announced: "Expansion", acquisition: "Acquisition", closure: "Closure", cloud_region_announced: "Cloud region announced", cloud_region_launched: "Cloud region launched", cloud_region_updated: "Cloud region updated", power_agreement: "Power agreement", investment_announced: "Investment", incident: "Incident", page_changed: "Page changed", news: "News", land_acquired: "Land acquired", grid_connection: "Grid connection", grid_constraint: "Grid constraint", utility_event: "Utility event", operator_expansion: "Operator expansion", customer_agreement: "Customer agreement", partnership: "Partnership", executive_change: "Executive change", project_delayed: "Project delayed", project_cancelled: "Project cancelled", }; /** Event families → tone, so the feed reads by colour without a rainbow. */ export function eventTone(t: EventType): StatusTone | "accent" | "neutral" { switch (t) { case "facility_opened": case "cloud_region_launched": case "facility_discovered": return "operational"; case "construction_started": case "phase_announced": return "construction"; case "project_announced": case "expansion_announced": case "cloud_region_announced": case "investment_announced": case "power_agreement": return "accent"; case "planning_filed": case "planning_approved": return "permitting"; case "closure": case "incident": return "delayed"; case "status_changed": case "project_status_changed": case "capacity_changed": case "planned_capacity_changed": case "opening_date_changed": case "operator_changed": case "owner_changed": case "acquisition": return "planned"; default: return "neutral"; } } export const ENTITY_TYPE_LABEL: Record = { facility: "Data center", campus: "Campus", operator: "Operator", company: "Company", cloud_region: "Cloud region", metro: "Market", city: "City", country: "Country", project: "Project", ixp: "IXP", power_project: "Power project", carrier: "Carrier", news_event: "News", }; /* ------------------------------------------------------------------ claim-first vocabulary (2026-09-12) */ /** Claim / figure scope — what a number describes. Site scopes may populate a record's own figures; the rest never do. */ export const SCOPE_LABEL: Record = { building: "Building", facility: "Facility", campus: "Campus", metro: "Metro", country: "Country", portfolio: "Portfolio", company: "Company-wide", unknown: "Scope unknown", }; export const SCOPE_SHORT: Record = { ...SCOPE_LABEL, company: "Company", unknown: "Unknown" }; export function isSiteScopeLabel(s: ClaimScope | string | null | undefined): boolean { return s === "building" || s === "facility" || s === "campus"; } /** Capacity semantics — the predicate behind a MW figure; also accepts the free-text `capacitySemantics` the API returns. */ export const SEMANTICS_LABEL: Record = { it_capacity_mw: "IT capacity", it_capacity: "IT capacity", it_load: "IT capacity", critical_power_mw: "Critical power", critical_power: "Critical power", current_power_mw: "Total power", total_power: "Total power", total_power_mw: "Total power", planned_power_mw: "Planned", planned: "Planned", grid_connection_mw: "Grid connection", grid_connection: "Grid connection", utility_capacity_mw: "Utility", utility: "Utility", utility_capacity: "Utility", ultimate_campus_mw: "Ultimate build-out", ultimate: "Ultimate build-out", phase_mw: "Phase capacity", project_investment_usd: "Project investment", campus_investment_usd: "Campus investment", company_investment_usd: "Company investment", country_program_usd: "Country programme", multi_year_capex_usd: "Multi-year capex", deal_value_usd: "Deal value", status: "Status", }; export function semanticsLabel(s: string | null | undefined): string | null { if (!s) return null; return SEMANTICS_LABEL[s] ?? s.replace(/_mw$|_usd$/, "").replace(/_/g, " ").replace(/^./, (c) => c.toUpperCase()); } export const AUTHORITY_TIER_LABEL: Record = { A: "Tier A — primary authority for this field", B: "Tier B — first-party or provider source", C: "Tier C — registry / secondary source", D: "Tier D — press coverage", E: "Tier E — dataset / community source", }; export const CLAIM_STATUS_LABEL: Record = { current: "Current", superseded: "Superseded", rejected: "Rejected", review: "In review", unscoped: "Not site-scoped", }; /** Extraction method families for the evidence drawer (from provenance.method / claims.parserName). */ export type ExtractionKind = "structured" | "parser" | "regex" | "reviewed" | "llm" | "unknown"; export function extractionKind(method: string | null | undefined): ExtractionKind { if (!method) return "unknown"; const m = method.toLowerCase(); if (/review|manual|human|curated/.test(m)) return "reviewed"; if (/llm|gpt|claude|model/.test(m)) return "llm"; if (/regex|prose|sentence|text/.test(m)) return "regex"; if (/json-?ld|dataset|api|structured|embedded|spec|table|field/.test(m)) return "structured"; return "parser"; } export const EXTRACTION_LABEL: Record = { structured: "Structured data", parser: "Parser", regex: "Sentence extraction", reviewed: "Human-reviewed", llm: "Model-assisted", unknown: "Method not recorded", }; export const SIGNIFICANCE_LABEL: Record = { major: "Major", medium: "Medium", minor: "Minor" }; export function significanceBand(value: number, band?: Significance | null): Significance { if (band) return band; return value >= 70 ? "major" : value >= 40 ? "medium" : "minor"; } export const AI_EVIDENCE_LABEL: Record = { confirmed: "AI · confirmed", likely: "AI · likely", associated: "AI · associated", unknown: "AI evidence unknown" }; /** Project lifecycle stages in funnel order (side branches last). */ export const PROJECT_STAGE_ORDER: ProjectStage[] = ["rumored", "proposed", "announced", "permitting", "approved", "under_construction", "partially_operational", "operational", "delayed", "cancelled"]; export const STAGE_LABEL: Record = { rumored: "Rumored", proposed: "Proposed", announced: "Announced", permitting: "Permitting", approved: "Approved", under_construction: "Construction", partially_operational: "Partially open", operational: "Opened", delayed: "Delayed", cancelled: "Cancelled", }; export const MAP_LAYER_LABEL: Record = { facilities: "Facilities", capacity: "Capacity", projects: "Projects", ai: "AI / HPC", cloud: "Cloud", ixps: "IXPs", connectivity: "Connectivity", power: "Power", pipeline: "Pipeline", }; export const DENSITY_LABEL: Record = { facilities: "Facility density", known_mw: "Known MW", pipeline_mw: "Pipeline MW", ai: "AI facilities", operators: "Operator diversity", cloud: "Cloud regions", ixps: "Internet exchanges", }; export const SEARCH_GROUP_LABEL: Record = { facility: "Data centers", operator: "Operators", country: "Countries", metro: "Markets", city: "Cities", cloud_region: "Cloud regions", project: "Projects", ixp: "Internet exchanges", };