#!/usr/bin/env node /** * Company Atlas — mock API for development and QA (NOT used in production). * Dependency-free Node HTTP server on :8371 serving contract-shaped sample data for every endpoint in docs/API.md: * ~40 companies across countries/industries, events of every type with careful wording, metrics, rankings, industries, * countries, signals, trends, map buckets, sensors/snapshots/changes/diff, in-memory watchlists/alerts, SSE live stream * (one event every ~4 s) and admin payloads. Data is generated from a fixed seed so SSR and client agree. * * Run: node apps/web/qa/mock-api.mjs [port] */ import { createServer } from 'node:http'; const PORT = Number(process.argv[2] ?? process.env.PORT ?? 8371); const NOW = Date.now(); const DAY = 86_400_000; // ------------------------------------------------------------------------------------------------ deterministic random let seed = 20260912; function rnd() { seed |= 0; seed = (seed + 0x6d2b79f5) | 0; let t = Math.imul(seed ^ (seed >>> 15), 1 | seed); t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; } const ri = (a, b) => a + Math.floor(rnd() * (b - a + 1)); const pick = (arr) => arr[Math.floor(rnd() * arr.length)]; const chance = (p) => rnd() < p; const B32 = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; let idc = 1000; function id(prefix) { idc += 7; let n = idc * 9973 + 12345; let s = ''; for (let i = 0; i < 16; i++) { s = B32[(n + i * 7) % 32] + s; n = Math.floor(n / 3) + i * 131; } return `${prefix}_${s}`; } const iso = (t) => new Date(t).toISOString(); const day = (t) => new Date(t).toISOString().slice(0, 10); const slugify = (s) => s .toLowerCase() .replace(/&/g, ' and ') .replace(/[^a-z0-9]+/g, '-') .replace(/^-|-$/g, ''); const r1 = (x) => Math.round(x * 10) / 10; const clamp = (x, a, b) => Math.max(a, Math.min(b, x)); // ------------------------------------------------------------------------------------------------ reference data const INDUSTRIES = [ ['fintech', 'Fintech', 'financial-services'], ['financial-services', 'Financial services', null], ['banking', 'Banking', 'financial-services'], ['software', 'Software', 'technology'], ['technology', 'Technology', null], ['artificial-intelligence', 'Artificial intelligence', 'technology'], ['semiconductors', 'Semiconductors', 'technology'], ['cloud-infrastructure', 'Cloud infrastructure', 'technology'], ['e-commerce', 'E-commerce', 'retail'], ['retail', 'Retail', null], ['automotive', 'Automotive', 'manufacturing'], ['manufacturing', 'Manufacturing', null], ['aerospace', 'Aerospace', 'manufacturing'], ['energy', 'Energy', null], ['renewable-energy', 'Renewable energy', 'energy'], ['healthcare', 'Healthcare', null], ['biotech', 'Biotech', 'healthcare'], ['pharmaceuticals', 'Pharmaceuticals', 'healthcare'], ['telecom', 'Telecom', null], ['media', 'Media', null], ['logistics', 'Logistics', null], ['insurance', 'Insurance', 'financial-services'], ['real-estate', 'Real estate', null], ['consumer', 'Consumer goods', null], ['cybersecurity', 'Cybersecurity', 'technology'], ]; const IND = Object.fromEntries(INDUSTRIES.map(([slug, name, parent]) => [slug, { slug, name, parent_slug: parent }])); const COUNTRY_META = { US: ['United States', 'North America', 39.8, -98.6], CA: ['Canada', 'North America', 56.1, -106.3], GB: ['United Kingdom', 'Europe', 55.4, -3.4], DE: ['Germany', 'Europe', 51.2, 10.4], FR: ['France', 'Europe', 46.2, 2.2], NL: ['Netherlands', 'Europe', 52.1, 5.3], SE: ['Sweden', 'Europe', 60.1, 18.6], CH: ['Switzerland', 'Europe', 46.8, 8.2], IE: ['Ireland', 'Europe', 53.4, -8.2], ES: ['Spain', 'Europe', 40.5, -3.7], JP: ['Japan', 'Asia', 36.2, 138.3], KR: ['South Korea', 'Asia', 35.9, 127.8], IN: ['India', 'Asia', 20.6, 79.0], SG: ['Singapore', 'Asia', 1.35, 103.8], AU: ['Australia', 'Oceania', -25.3, 133.8], BR: ['Brazil', 'South America', -14.2, -51.9], MX: ['Mexico', 'North America', 23.6, -102.6], AE: ['United Arab Emirates', 'Middle East', 23.4, 53.8], IL: ['Israel', 'Middle East', 31.0, 34.9], ZA: ['South Africa', 'Africa', -30.6, 22.9], NG: ['Nigeria', 'Africa', 9.1, 8.7], TW: ['Taiwan', 'Asia', 23.7, 121.0], CN: ['China', 'Asia', 35.9, 104.2], FI: ['Finland', 'Europe', 61.9, 25.7], }; // [name, domain, country, city, lat, lon, industries, public, ticker, exchange, founded, employees_band, importance, description] const SEED = [ ['Stripe', 'stripe.com', 'US', 'South San Francisco', 37.65, -122.4, ['fintech', 'software'], false, null, null, 2010, '5,001–10,000', 92, 'Payments infrastructure for the internet.'], ['Adyen', 'adyen.com', 'NL', 'Amsterdam', 52.37, 4.9, ['fintech'], true, 'ADYEN', 'Euronext', 2006, '1,001–5,000', 84, 'Global payments platform for enterprises.'], ['Block', 'block.xyz', 'US', 'Oakland', 37.8, -122.27, ['fintech'], true, 'XYZ', 'NYSE', 2009, '10,001+', 83, 'Economic empowerment tools: Square, Cash App, TIDAL.'], ['Shopify', 'shopify.com', 'CA', 'Ottawa', 45.42, -75.7, ['e-commerce', 'software'], true, 'SHOP', 'TSX', 2006, '5,001–10,000', 90, 'Commerce platform for merchants of every size.'], ['Lightspeed', 'lightspeedhq.com', 'CA', 'Montréal', 45.5, -73.57, ['software', 'retail'], true, 'LSPD', 'TSX', 2005, '1,001–5,000', 62, 'Point-of-sale and commerce platform.'], ['Wealthsimple', 'wealthsimple.com', 'CA', 'Toronto', 43.65, -79.38, ['fintech'], false, null, null, 2014, '1,001–5,000', 58, 'Investing, spending and saving app.'], ['Cohere', 'cohere.com', 'CA', 'Toronto', 43.65, -79.38, ['artificial-intelligence'], false, null, null, 2019, '201–500', 74, 'Enterprise AI models and retrieval.'], ['Anthropic', 'anthropic.com', 'US', 'San Francisco', 37.77, -122.42, ['artificial-intelligence'], false, null, null, 2021, '1,001–5,000', 91, 'AI safety and research company building Claude.'], ['NVIDIA', 'nvidia.com', 'US', 'Santa Clara', 37.35, -121.95, ['semiconductors', 'artificial-intelligence'], true, 'NVDA', 'NASDAQ', 1993, '10,001+', 98, 'Accelerated computing and AI platforms.'], ['Apple', 'apple.com', 'US', 'Cupertino', 37.32, -122.03, ['technology', 'consumer'], true, 'AAPL', 'NASDAQ', 1976, '10,001+', 99, 'Consumer hardware, software and services.'], ['Snowflake', 'snowflake.com', 'US', 'Bozeman', 45.68, -111.04, ['cloud-infrastructure', 'software'], true, 'SNOW', 'NYSE', 2012, '5,001–10,000', 80, 'AI Data Cloud.'], ['Datadog', 'datadoghq.com', 'US', 'New York', 40.71, -74.0, ['software', 'cloud-infrastructure'], true, 'DDOG', 'NASDAQ', 2010, '5,001–10,000', 79, 'Observability and security platform.'], ['Cloudflare', 'cloudflare.com', 'US', 'San Francisco', 37.77, -122.42, ['cloud-infrastructure', 'cybersecurity'], true, 'NET', 'NYSE', 2009, '1,001–5,000', 85, 'Connectivity cloud.'], ['Revolut', 'revolut.com', 'GB', 'London', 51.5, -0.12, ['fintech', 'banking'], false, null, null, 2015, '5,001–10,000', 78, 'Global financial super-app.'], ['Monzo', 'monzo.com', 'GB', 'London', 51.5, -0.12, ['banking', 'fintech'], false, null, null, 2015, '1,001–5,000', 60, 'Digital bank.'], ['Arm', 'arm.com', 'GB', 'Cambridge', 52.2, 0.12, ['semiconductors'], true, 'ARM', 'NASDAQ', 1990, '5,001–10,000', 82, 'CPU architecture and IP.'], ['SAP', 'sap.com', 'DE', 'Walldorf', 49.3, 8.64, ['software'], true, 'SAP', 'XETRA', 1972, '10,001+', 88, 'Enterprise application software.'], ['Siemens', 'siemens.com', 'DE', 'Munich', 48.14, 11.58, ['manufacturing', 'technology'], true, 'SIE', 'XETRA', 1847, '10,001+', 90, 'Industrial technology.'], ['Zalando', 'zalando.com', 'DE', 'Berlin', 52.52, 13.4, ['e-commerce', 'retail'], true, 'ZAL', 'XETRA', 2008, '10,001+', 70, 'Online fashion platform.'], ['Mistral AI', 'mistral.ai', 'FR', 'Paris', 48.86, 2.35, ['artificial-intelligence'], false, null, null, 2023, '201–500', 76, 'Open and portable generative AI.'], ['Dassault Systèmes', '3ds.com', 'FR', 'Vélizy-Villacoublay', 48.78, 2.19, ['software', 'manufacturing'], true, 'DSY', 'Euronext', 1981, '10,001+', 77, '3D design and PLM software.'], ['Spotify', 'spotify.com', 'SE', 'Stockholm', 59.33, 18.07, ['media', 'technology'], true, 'SPOT', 'NYSE', 2006, '5,001–10,000', 83, 'Audio streaming.'], ['Klarna', 'klarna.com', 'SE', 'Stockholm', 59.33, 18.07, ['fintech'], false, null, null, 2005, '1,001–5,000', 72, 'Payments and shopping.'], ['Roche', 'roche.com', 'CH', 'Basel', 47.56, 7.59, ['pharmaceuticals', 'healthcare'], true, 'ROG', 'SIX', 1896, '10,001+', 89, 'Pharmaceuticals and diagnostics.'], ['Intercom', 'intercom.com', 'IE', 'Dublin', 53.35, -6.26, ['software'], false, null, null, 2011, '1,001–5,000', 61, 'AI-first customer service.'], ['Cabify', 'cabify.com', 'ES', 'Madrid', 40.42, -3.7, ['logistics', 'technology'], false, null, null, 2011, '1,001–5,000', 48, 'Mobility platform.'], ['Toyota', 'toyota-global.com', 'JP', 'Toyota City', 35.08, 137.16, ['automotive', 'manufacturing'], true, '7203', 'TSE', 1937, '10,001+', 95, 'Automobiles and mobility.'], ['Sony', 'sony.com', 'JP', 'Tokyo', 35.68, 139.69, ['consumer', 'media', 'technology'], true, '6758', 'TSE', 1946, '10,001+', 91, 'Electronics, entertainment and financial services.'], ['Samsung Electronics', 'samsung.com', 'KR', 'Suwon', 37.26, 127.03, ['semiconductors', 'consumer'], true, '005930', 'KRX', 1969, '10,001+', 96, 'Consumer electronics and semiconductors.'], ['Infosys', 'infosys.com', 'IN', 'Bengaluru', 12.97, 77.59, ['software', 'technology'], true, 'INFY', 'NSE', 1981, '10,001+', 80, 'Digital services and consulting.'], ['Zerodha', 'zerodha.com', 'IN', 'Bengaluru', 12.97, 77.59, ['fintech'], false, null, null, 2010, '1,001–5,000', 55, 'Discount brokerage.'], ['Grab', 'grab.com', 'SG', 'Singapore', 1.29, 103.85, ['logistics', 'fintech'], true, 'GRAB', 'NASDAQ', 2012, '5,001–10,000', 71, 'Superapp for deliveries, mobility and finance.'], ['Atlassian', 'atlassian.com', 'AU', 'Sydney', -33.87, 151.21, ['software'], true, 'TEAM', 'NASDAQ', 2002, '10,001+', 84, 'Team collaboration software.'], ['Canva', 'canva.com', 'AU', 'Sydney', -33.87, 151.21, ['software', 'media'], false, null, null, 2013, '1,001–5,000', 73, 'Visual communication platform.'], ['Nubank', 'nubank.com.br', 'BR', 'São Paulo', -23.55, -46.63, ['banking', 'fintech'], true, 'NU', 'NYSE', 2013, '5,001–10,000', 81, 'Digital banking platform.'], ['Bitso', 'bitso.com', 'MX', 'Mexico City', 19.43, -99.13, ['fintech'], false, null, null, 2014, '501–1,000', 45, 'Crypto financial services.'], ['Careem', 'careem.com', 'AE', 'Dubai', 25.2, 55.27, ['logistics', 'technology'], false, null, null, 2012, '1,001–5,000', 52, 'Everything app for the Middle East.'], ['Wiz', 'wiz.io', 'IL', 'Tel Aviv', 32.08, 34.78, ['cybersecurity', 'cloud-infrastructure'], false, null, null, 2020, '1,001–5,000', 69, 'Cloud security platform.'], ['Discovery', 'discovery.co.za', 'ZA', 'Sandton', -26.1, 28.05, ['insurance', 'financial-services'], true, 'DSY', 'JSE', 1992, '10,001+', 57, 'Shared-value insurance.'], ['Flutterwave', 'flutterwave.com', 'NG', 'Lagos', 6.52, 3.38, ['fintech'], false, null, null, 2016, '501–1,000', 50, 'Payments technology for Africa.'], ['TSMC', 'tsmc.com', 'TW', 'Hsinchu', 24.8, 120.97, ['semiconductors', 'manufacturing'], true, '2330', 'TWSE', 1987, '10,001+', 97, 'Dedicated semiconductor foundry.'], ['Ørsted', 'orsted.com', 'DE', 'Hamburg', 53.55, 9.99, ['renewable-energy', 'energy'], true, 'ORSTED', 'Nasdaq Copenhagen', 1972, '5,001–10,000', 66, 'Offshore wind developer.'], ['Nokia', 'nokia.com', 'FI', 'Espoo', 60.2, 24.66, ['telecom', 'technology'], true, 'NOKIA', 'Nasdaq Helsinki', 1865, '10,001+', 78, 'Network infrastructure and technology.'], ['Moderna', 'modernatx.com', 'US', 'Cambridge', 42.37, -71.11, ['biotech', 'pharmaceuticals'], true, 'MRNA', 'NASDAQ', 2010, '5,001–10,000', 75, 'mRNA medicines.'], ['Rocket Lab', 'rocketlabusa.com', 'US', 'Long Beach', 33.77, -118.19, ['aerospace'], true, 'RKLB', 'NASDAQ', 2006, '1,001–5,000', 64, 'Launch and space systems.'], ['Compass', 'compass.com', 'US', 'New York', 40.71, -74.0, ['real-estate', 'technology'], true, 'COMP', 'NYSE', 2012, '1,001–5,000', 47, 'Real estate technology and brokerage.'], ]; const SURFACES = ['homepage', 'about', 'careers', 'newsroom', 'blog', 'products', 'pricing', 'leadership', 'locations', 'investor_relations', 'documentation', 'changelog', 'legal', 'security', 'developer', 'partners', 'customers', 'sitemap', 'feed']; const SURFACE_PATH = { homepage: '/', about: '/about', careers: '/careers', newsroom: '/newsroom', blog: '/blog', products: '/products', pricing: '/pricing', leadership: '/about/leadership', locations: '/about/locations', investor_relations: '/investors', documentation: '/docs', changelog: '/changelog', legal: '/legal/terms', security: '/security', developer: '/developers', partners: '/partners', customers: '/customers', sitemap: '/sitemap.xml', feed: '/blog/rss.xml' }; const CONNECTOR_FOR = { careers: 'generic_careers', newsroom: 'generic_news', blog: 'rss_connector', pricing: 'generic_pricing', leadership: 'generic_leadership', locations: 'generic_locations', products: 'generic_products', documentation: 'generic_docs', changelog: 'generic_changelog', legal: 'generic_legal', sitemap: 'sitemap_connector', feed: 'rss_connector', investor_relations: 'generic_ir' }; const CONNECTORS = [ ['generic_html', 'Generic HTML page', '1.4.0', 'core'], ['generic_careers', 'Generic careers page', '2.1.0', 'jobs'], ['greenhouse_connector', 'Greenhouse board', '1.2.0', 'jobs'], ['lever_connector', 'Lever board', '1.1.0', 'jobs'], ['generic_news', 'Generic newsroom', '1.3.0', 'news'], ['rss_connector', 'RSS / Atom feed', '1.0.2', 'news'], ['generic_pricing', 'Generic pricing page', '2.0.0', 'pricing'], ['generic_leadership', 'Generic leadership page', '1.1.0', 'people'], ['generic_locations', 'Generic locations page', '1.0.0', 'locations'], ['generic_products', 'Generic product catalogue', '1.2.0', 'products'], ['generic_docs', 'Documentation', '1.0.1', 'developer'], ['generic_changelog', 'Changelog', '1.0.0', 'developer'], ['generic_legal', 'Legal / terms', '1.0.0', 'legal'], ['generic_ir', 'Investor relations', '1.0.0', 'ir'], ['sitemap_connector', 'Sitemap discovery', '1.5.0', 'discovery'], ]; const TIERS = ['A', 'B', 'C', 'D', 'E']; const TIER_INTERVAL = { A: 900, B: 3600, C: 21600, D: 86400, E: 432000 }; const FAILURE_CLASSES = ['TIMEOUT', 'HTTP_4XX', 'HTTP_5XX', 'BOT_CHALLENGE', 'PARSING', 'REDIRECT', 'PAGE_REMOVED', 'RATE_LIMIT', 'DNS']; const DEPARTMENTS = ['Engineering', 'Product', 'Sales', 'Marketing', 'Customer Success', 'Finance', 'Legal', 'Operations', 'Data', 'Design', 'Security', 'People']; const JOB_TITLES = ['Software Engineer', 'Senior Software Engineer', 'Staff Engineer', 'Machine Learning Engineer', 'Applied AI Engineer', 'Data Scientist', 'Product Manager', 'Account Executive', 'Solutions Engineer', 'Security Engineer', 'Site Reliability Engineer', 'Technical Writer', 'Designer', 'Recruiter', 'Finance Analyst', 'Legal Counsel', 'Research Scientist, LLMs', 'Developer Advocate', 'Platform Engineer', 'Support Specialist']; const PRODUCT_NAMES = ['Terminal', 'Connect', 'Radar', 'Atlas', 'Issuing', 'Billing', 'Sigma', 'Vault', 'Insights', 'Studio', 'Workflows', 'Assistant', 'Guard', 'Ledger', 'Pulse', 'Edge', 'Core API', 'Marketplace', 'Analytics', 'Identity']; const PEOPLE = ['Ava Martin', 'Noah Chen', 'Léa Dubois', 'Mateo Rossi', 'Priya Nair', 'Kenji Watanabe', 'Sofia Alvarez', 'Liam O’Connor', 'Amara Okafor', 'Hugo Lindqvist', 'Yuna Park', 'Daniel Cohen', 'Fatima Al-Sayed', 'Elena Petrova', 'Tomás Silva', 'Grace Kim', 'Arjun Mehta', 'Mia Fischer', 'Oliver Brown', 'Chloé Bernard']; const TITLES = ['Chief Executive Officer', 'Chief Financial Officer', 'Chief Technology Officer', 'Chief Operating Officer', 'Chief Product Officer', 'Chief Revenue Officer', 'General Counsel', 'Chief People Officer', 'VP Engineering', 'VP Sales', 'Head of AI', 'Chief Information Security Officer']; const CITIES = [['New York', 'US', 40.71, -74.0], ['London', 'GB', 51.5, -0.12], ['Berlin', 'DE', 52.52, 13.4], ['Paris', 'FR', 48.86, 2.35], ['Toronto', 'CA', 43.65, -79.38], ['Singapore', 'SG', 1.29, 103.85], ['Sydney', 'AU', -33.87, 151.21], ['Tokyo', 'JP', 35.68, 139.69], ['Dublin', 'IE', 53.35, -6.26], ['Bengaluru', 'IN', 12.97, 77.59], ['São Paulo', 'BR', -23.55, -46.63], ['Austin', 'US', 30.27, -97.74], ['Amsterdam', 'NL', 52.37, 4.9], ['Dubai', 'AE', 25.2, 55.27], ['Seoul', 'KR', 37.57, 126.98], ['Mexico City', 'MX', 19.43, -99.13], ['Warsaw', 'PL', 52.23, 21.01], ['Lisbon', 'PT', 38.72, -9.14]]; const TREND_TERMS = ['agentic AI', 'AI engineer', 'usage-based pricing', 'data residency', 'FedRAMP', 'EU AI Act', 'sovereign cloud', 'stablecoin', 'on-device inference', 'enterprise tier', 'SOC 2', 'MCP server', 'embedded finance', 'carbon accounting', 'returns policy', 'API deprecation', 'self-serve', 'hybrid work', 'Bengaluru hub', 'German expansion']; // ------------------------------------------------------------------------------------------------ event templates // [event_type, event_subtype, importanceRange, surfaces, titleFn, summaryFn, old/new fn] const EVENT_TEMPLATES = [ ['PRODUCT', 'PRODUCT_LAUNCH', [0.55, 0.92], ['products', 'homepage', 'newsroom', 'blog'], (c, p) => `${c.display_name} lists a new product: ${p.name}`, (c, p) => `A product page for ${p.name} was detected on the monitored catalog. It did not appear in the previous snapshot.`, (c, p) => [null, p.name]], ['PRODUCT', 'PRODUCT_REMOVAL', [0.5, 0.8], ['products'], (c, p) => `${p.name} no longer listed on ${c.display_name}'s product catalog`, (c, p) => `The product entry was present in the previous version of the page and is no longer visible. This does not by itself confirm discontinuation.`, (c, p) => [p.name, null]], ['PRODUCT', 'PRODUCT_RENAME', [0.35, 0.6], ['products'], (c, p) => `${c.display_name} appears to have renamed ${p.name}`, (c, p) => `The product card kept its position and description but its name changed between snapshots.`, (c, p) => [p.name, `${p.name} Pro`]], ['PRICING', 'PRICE_INCREASE', [0.6, 0.95], ['pricing'], (c, p) => `${c.display_name} ${p.plan} plan price increased`, (c, p) => `The listed monthly price of the ${p.plan} plan changed on the public pricing page.`, (c, p) => [`$${p.oldPrice}/mo`, `$${p.newPrice}/mo`]], ['PRICING', 'PRICE_DECREASE', [0.5, 0.85], ['pricing'], (c, p) => `${c.display_name} ${p.plan} plan price decreased`, (c, p) => `The listed monthly price of the ${p.plan} plan is lower than in the previous snapshot.`, (c, p) => [`$${p.newPrice}/mo`, `$${p.oldPrice}/mo`]], ['PRICING', 'NEW_PRICING_TIER', [0.55, 0.85], ['pricing'], (c, p) => `${c.display_name} adds a new pricing tier: ${p.plan}`, (c) => `A pricing column that did not exist in the previous snapshot is now listed.`, (c, p) => [null, p.plan]], ['HIRING', 'JOB_COUNT_INCREASE', [0.3, 0.75], ['careers'], (c, p) => `${c.display_name} open listings up ${p.pct} % over 7 days`, (c, p) => `${p.n} listings were added on the monitored careers surface, ${p.ai} of them mentioning AI or machine learning.`, (c, p) => [`${p.from} open listings`, `${p.to} open listings`]], ['HIRING', 'JOB_COUNT_DECREASE', [0.4, 0.85], ['careers'], (c, p) => `${p.n} ${c.display_name} listings are no longer visible`, (c, p) => `${p.n} monitored job listings are no longer visible on the careers page (${p.pct} % of the previous count). This reflects public listings only and is not evidence of layoffs.`, (c, p) => [`${p.from} open listings`, `${p.to} open listings`]], ['LEADERSHIP', 'NEW_EXECUTIVE', [0.6, 0.9], ['leadership', 'newsroom'], (c, p) => `${p.name} listed as ${p.title} at ${c.display_name}`, (c, p) => `A new profile appeared on the monitored leadership page.`, (c, p) => [null, `${p.name} — ${p.title}`]], ['LEADERSHIP', 'EXECUTIVE_REMOVED', [0.6, 0.9], ['leadership'], (c, p) => `${p.name} no longer listed on ${c.display_name}'s leadership page`, (c, p) => `The profile for ${p.name} (${p.title}) is no longer visible on the monitored leadership page. The reason is not stated on the page.`, (c, p) => [`${p.name} — ${p.title}`, null]], ['LOCATION', 'NEW_OFFICE', [0.5, 0.8], ['locations', 'careers'], (c, p) => `${c.display_name} lists a new office in ${p.city}`, (c, p) => `A ${p.city}, ${p.country} location was added to the monitored locations page.`, (c, p) => [null, `${p.city}, ${p.country}`]], ['LOCATION', 'COUNTRY_EXPANSION', [0.65, 0.92], ['locations', 'careers', 'newsroom'], (c, p) => `${c.display_name} appears to expand into ${p.country}`, (c, p) => `First monitored presence in ${p.country}: a location entry and ${p.jobs} job listings referencing ${p.city}.`, (c, p) => [null, p.country]], ['LOCATION', 'OFFICE_REMOVED', [0.45, 0.75], ['locations'], (c, p) => `${c.display_name}'s ${p.city} office no longer listed`, (c, p) => `The ${p.city} entry was present in the previous snapshot of the locations page and is no longer visible.`, (c, p) => [`${p.city}, ${p.country}`, null]], ['DEVELOPER', 'API_LAUNCH', [0.55, 0.85], ['developer', 'documentation', 'changelog'], (c, p) => `${c.display_name} publishes a new API: ${p.name} API`, (c, p) => `A new reference section for the ${p.name} API appeared in the developer documentation.`, (c, p) => [null, `${p.name} API v1`]], ['DEVELOPER', 'DOCUMENTATION_CHANGE', [0.25, 0.55], ['documentation', 'changelog'], (c, p) => `${c.display_name} documentation updated: ${p.section}`, (c, p) => `${p.blocks} blocks changed in the ${p.section} section of the monitored documentation.`, () => [null, null]], ['LEGAL', 'TERMS_CHANGE', [0.45, 0.8], ['legal'], (c, p) => `${c.display_name} terms of service updated (section ${p.section})`, (c, p) => `Section ${p.section} of the terms was materially updated; ${p.pct} % of the text changed. The previous version is preserved.`, (c, p) => [`Terms v${p.v}`, `Terms v${p.v + 1}`]], ['COMMUNICATION', 'NEWS_RELEASE', [0.3, 0.7], ['newsroom', 'blog', 'feed'], (c, p) => `${c.display_name}: ${p.headline}`, (c, p) => `A first-party newsroom item was published.`, () => [null, null]], ['PARTNERSHIP', 'NEW_PARTNERSHIP', [0.5, 0.8], ['newsroom', 'partners'], (c, p) => `${c.display_name} announces a partnership with ${p.partner}`, (c, p) => `A partnership was described in a first-party release and ${p.partner} now appears on the partners page.`, (c, p) => [null, p.partner]], ['M&A', 'ACQUISITION', [0.75, 0.98], ['newsroom', 'investor_relations'], (c, p) => `${c.display_name} announces the acquisition of ${p.target}`, (c, p) => `Stated in a first-party release on the newsroom; corroborated by an investor relations notice ${p.delay} minutes later.`, (c, p) => [null, p.target]], ['FINANCING', 'FUNDING_ROUND', [0.7, 0.95], ['newsroom', 'blog'], (c, p) => `${c.display_name} states a ${p.amount} funding round`, (c, p) => `Amount as stated by the company in its own release; not independently verified.`, (c, p) => [null, p.amount]], ['SECURITY', 'SECURITY_NOTICE', [0.6, 0.9], ['security', 'blog'], (c, p) => `${c.display_name} publishes a security notice`, (c, p) => `A new advisory appeared on the monitored security page (${p.kind}).`, () => [null, null]], ['STRATEGY', 'BRAND_REPOSITIONING', [0.45, 0.75], ['homepage', 'about'], (c, p) => `${c.display_name} homepage headline changed`, (c, p) => `The hero headline changed from an SMB-oriented message to enterprise language. Signal, not a confirmed strategy change.`, (c, p) => [p.oldHeadline, p.newHeadline]], ['TECHNOLOGY', 'TECHNOLOGY_SIGNAL', [0.3, 0.6], ['developer', 'blog', 'careers'], (c, p) => `${c.display_name} references ${p.tech} across ${p.n} surfaces`, (c, p) => `${p.tech} appeared in new documentation and ${p.jobs} job listings within the same week.`, () => [null, null]], ['INVESTOR_RELATIONS', 'IR_UPDATE', [0.4, 0.7], ['investor_relations'], (c, p) => `${c.display_name} posts ${p.item} on investor relations`, () => `Published on the company's investor relations page; not a substitute for regulated filings.`, () => [null, null]], ['SUSTAINABILITY', 'SUSTAINABILITY_UPDATE', [0.3, 0.6], ['about', 'newsroom'], (c, p) => `${c.display_name} publishes its ${p.year} sustainability report`, () => `A new report link appeared on the monitored page.`, () => [null, null]], ['MARKETING', 'CAMPAIGN_CHANGE', [0.2, 0.45], ['homepage'], (c) => `${c.display_name} homepage hero campaign changed`, () => `Hero imagery and call-to-action blocks were replaced; classified as marketing noise above the significance floor.`, () => [null, null]], ['OPERATIONS', 'STATUS_INCIDENT', [0.4, 0.7], ['status', 'security'], (c, p) => `${c.display_name} status page reports ${p.kind}`, () => `Observed on the public status page.`, () => [null, null]], ]; const HEADLINES = ['expands enterprise offering to the EU', 'reports record quarter for developer sign-ups', 'opens applications for its startup program', 'introduces new sustainability commitments', 'launches regional data residency', 'names new advisory board members', 'publishes annual developer survey', 'partners with universities on AI research']; const PARTNERS = ['Microsoft', 'AWS', 'Google Cloud', 'Accenture', 'Deloitte', 'Salesforce', 'Visa', 'Mastercard', 'Snowflake', 'NVIDIA']; const TECHS = ['Rust', 'Kubernetes', 'MCP', 'vector search', 'WebAssembly', 'PostgreSQL', 'Kafka', 'Terraform', 'Claude', 'LLM evaluation']; // ------------------------------------------------------------------------------------------------ enrichment profiles // Sample `CompanyCard.profile` payloads (mock only — figures are approximate public values used to exercise the UI, not // a dataset). Mix: complete (nvidia, apple, toyota, sony, roche, sap, spotify, adyen, arm, tsmc, siemens, samsung), // partial (stripe, cohere, anthropic, mistral-ai, shopify, nubank, revolut, klarna), null-filled (cabify, careem, // flutterwave, zerodha, discovery), absent key (compass, bitso, wiz), and an auto-derived minimal profile for the rest. const MOCK_ASSET_BASE = `http://127.0.0.1:${PORT}/api/v1/_mock`; const WD = (q) => `https://www.wikidata.org/wiki/${q}`; const WP = (t) => `https://en.wikipedia.org/wiki/${t}`; const money = (value, currency, year) => ({ value, currency, year }); const RETRIEVED = iso(NOW - 3 * DAY); const NO_PROFILE_KEY = new Set(['compass', 'bitso', 'wiz']); const NULL_PROFILE = new Set(['cabify', 'careem', 'flutterwave', 'zerodha', 'discovery']); const PROFILES = { nvidia: { description: 'Nvidia Corporation is an American technology company headquartered in Santa Clara, California. It designs graphics processing units, system-on-a-chip units and application programming interfaces for data science, high-performance computing and mobile and automotive markets.', description_source: 'wikipedia', description_url: WP('Nvidia'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 1993, legal_form: 'Public company (Delaware corporation)', employees: 36000, employees_year: 2025, revenue: money(130497000000, 'USD', 2025), net_income: money(72880000000, 'USD', 2025), total_assets: money(111601000000, 'USD', 2025), hq: { city: 'Santa Clara', region: 'California', country: 'US', address: '2788 San Tomas Expressway', lat: 37.3706, lon: -121.9636 }, ticker: 'NVDA', exchange: 'NASDAQ', isin: 'US67066G1040', lei: '549300S4KLFTLO7GSQ80', sec_cik: '0001045810', public_company: true, wikipedia_url: WP('Nvidia'), wikidata_url: WD('Q182477'), official_website: 'https://www.nvidia.com', phone: '+1 408-486-2000', products: ['GeForce', 'Quadro', 'CUDA', 'DGX', 'Jetson', 'Tegra', 'NVIDIA DRIVE', 'Omniverse', 'Nvidia RTX'], industry_labels: ['semiconductor industry', 'artificial intelligence', 'computer hardware'], socials: { linkedin: 'https://www.linkedin.com/company/nvidia', x: 'https://x.com/nvidia', youtube: 'https://www.youtube.com/@NVIDIA', facebook: 'https://www.facebook.com/NVIDIA', instagram: 'https://www.instagram.com/nvidia', github: 'https://github.com/NVIDIA' }, extra_facts: [{ key: 'index_membership', label: 'Index membership', value: 'S&P 500 · Nasdaq-100 · Dow Jones Industrial Average', source: 'wikidata' }], financial_source: 'sec_edgar', }, apple: { description: 'Apple Inc. is an American multinational technology company headquartered in Cupertino, California. It designs, develops and sells consumer electronics, software and online services, including the iPhone, Mac, iPad, Apple Watch and the App Store.', description_source: 'wikipedia', description_url: WP('Apple_Inc.'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 1976, legal_form: 'Public company (California corporation)', employees: 164000, employees_year: 2024, revenue: money(391035000000, 'USD', 2024), net_income: money(93736000000, 'USD', 2024), total_assets: money(364980000000, 'USD', 2024), hq: { city: 'Cupertino', region: 'California', country: 'US', address: 'One Apple Park Way', lat: 37.3349, lon: -122.009 }, ticker: 'AAPL', exchange: 'NASDAQ', isin: 'US0378331005', lei: 'HWUPKR0MPOU8FGXBT394', sec_cik: '0000320193', public_company: true, wikipedia_url: WP('Apple_Inc.'), wikidata_url: WD('Q312'), official_website: 'https://www.apple.com', phone: '+1 408-996-1010', products: ['iPhone', 'iPad', 'Mac', 'Apple Watch', 'AirPods', 'Apple TV', 'Apple Vision Pro', 'iOS', 'macOS', 'App Store', 'Apple Music', 'iCloud'], industry_labels: ['consumer electronics', 'software industry', 'online services'], socials: { linkedin: 'https://www.linkedin.com/company/apple', x: 'https://x.com/Apple', youtube: 'https://www.youtube.com/@Apple', instagram: 'https://www.instagram.com/apple', facebook: 'https://www.facebook.com/apple' }, extra_facts: [{ key: 'index_membership', label: 'Index membership', value: 'S&P 500 · Nasdaq-100 · Dow Jones Industrial Average', source: 'wikidata' }, { key: 'auditor', label: 'Auditor', value: 'Ernst & Young', source: 'sec_edgar' }], financial_source: 'sec_edgar', }, toyota: { description: 'Toyota Motor Corporation is a Japanese multinational automotive manufacturer headquartered in Toyota City, Aichi. It is one of the largest automobile manufacturers in the world by production volume.', description_source: 'wikipedia', description_url: WP('Toyota'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 1937, legal_form: 'Kabushiki gaisha (public)', employees: 380793, employees_year: 2024, revenue: money(48036704000000, 'JPY', 2025), net_income: money(4765086000000, 'JPY', 2025), total_assets: money(93601350000000, 'JPY', 2025), hq: { city: 'Toyota City', region: 'Aichi', country: 'JP', address: '1 Toyota-cho', lat: 35.0826, lon: 137.1562 }, ticker: '7203', exchange: 'TSE', isin: 'JP3633400001', lei: '5493006W3QUS5LMH6R84', sec_cik: '0001094517', public_company: true, wikipedia_url: WP('Toyota'), wikidata_url: WD('Q53268'), official_website: 'https://global.toyota', phone: null, products: ['Toyota Corolla', 'Toyota Camry', 'Toyota RAV4', 'Toyota Prius', 'Toyota Hilux', 'Toyota Land Cruiser', 'Lexus'], industry_labels: ['automotive industry'], socials: { linkedin: 'https://www.linkedin.com/company/toyota', x: 'https://x.com/Toyota', youtube: 'https://www.youtube.com/@toyotaglobal' }, }, sony: { description: 'Sony Group Corporation is a Japanese multinational conglomerate headquartered in Minato, Tokyo, active in electronics, gaming, entertainment (pictures and music), imaging sensors and financial services.', description_source: 'homepage', description_url: 'https://www.sony.com/en/SonyInfo/CorporateInfo/', description_license: null, logo: true, icon: false, founded_year: 1946, legal_form: 'Kabushiki gaisha (public)', employees: 113000, employees_year: 2024, revenue: money(12957000000000, 'JPY', 2025), net_income: money(1141600000000, 'JPY', 2025), total_assets: money(35300000000000, 'JPY', 2025), hq: { city: 'Minato', region: 'Tokyo', country: 'JP', address: '1-7-1 Konan', lat: 35.6299, lon: 139.7402 }, ticker: '6758', exchange: 'TSE', isin: 'JP3435000009', lei: '353800A2DP3ZMC4LR436', sec_cik: '0000313838', public_company: true, wikipedia_url: WP('Sony'), wikidata_url: WD('Q41187'), official_website: 'https://www.sony.com', phone: null, products: ['PlayStation 5', 'Sony Alpha', 'Bravia', 'WH-1000XM5', 'Xperia', 'Sony Pictures', 'Sony Music'], industry_labels: ['conglomerate', 'consumer electronics', 'entertainment industry'], socials: { linkedin: 'https://www.linkedin.com/company/sony', x: 'https://x.com/Sony', youtube: 'https://www.youtube.com/@Sony', instagram: 'https://www.instagram.com/sony', facebook: 'https://www.facebook.com/Sony', tiktok: 'https://www.tiktok.com/@sony' }, }, roche: { description: 'F. Hoffmann-La Roche AG is a Swiss multinational healthcare company operating worldwide under two divisions: Pharmaceuticals and Diagnostics. It is headquartered in Basel.', description_source: 'wikipedia', description_url: WP('Hoffmann-La_Roche'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 1896, legal_form: 'Aktiengesellschaft (public)', employees: 103613, employees_year: 2024, revenue: money(60500000000, 'CHF', 2024), net_income: money(9186000000, 'CHF', 2024), total_assets: money(93700000000, 'CHF', 2024), hq: { city: 'Basel', region: 'Basel-Stadt', country: 'CH', address: 'Grenzacherstrasse 124', lat: 47.5615, lon: 7.6086 }, ticker: 'ROG', exchange: 'SIX', isin: 'CH0012032048', lei: '549300U41AUUVOAZRV96', sec_cik: null, public_company: true, wikipedia_url: WP('Hoffmann-La_Roche'), wikidata_url: WD('Q212646'), official_website: 'https://www.roche.com', phone: '+41 61 688 11 11', products: ['Ocrevus', 'Hemlibra', 'Tecentriq', 'Vabysmo', 'Perjeta', 'cobas', 'Accu-Chek'], industry_labels: ['pharmaceutical industry', 'in vitro diagnostics'], socials: { linkedin: 'https://www.linkedin.com/company/roche', x: 'https://x.com/Roche', youtube: 'https://www.youtube.com/@roche' }, }, sap: { description: 'SAP SE is a German multinational software company based in Walldorf, Baden-Württemberg, that develops enterprise software to manage business operations and customer relations.', description_source: 'wikipedia', description_url: WP('SAP'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 1972, legal_form: 'Societas Europaea (SE)', employees: 109121, employees_year: 2024, revenue: money(34176000000, 'EUR', 2024), net_income: money(3096000000, 'EUR', 2024), total_assets: money(69700000000, 'EUR', 2024), hq: { city: 'Walldorf', region: 'Baden-Württemberg', country: 'DE', address: 'Dietmar-Hopp-Allee 16', lat: 49.2933, lon: 8.6414 }, ticker: 'SAP', exchange: 'XETRA', isin: 'DE0007164600', lei: '529900D6BF99LW9R2E68', sec_cik: '0001000184', public_company: true, wikipedia_url: WP('SAP'), wikidata_url: WD('Q166262'), official_website: 'https://www.sap.com', phone: '+49 6227 7-47474', products: ['SAP S/4HANA', 'SAP HANA', 'SAP Business Technology Platform', 'SAP SuccessFactors', 'SAP Ariba', 'SAP Concur', 'Joule'], industry_labels: ['software industry', 'enterprise software'], socials: { linkedin: 'https://www.linkedin.com/company/sap', x: 'https://x.com/SAP', youtube: 'https://www.youtube.com/@SAP', github: 'https://github.com/SAP' }, }, spotify: { description: 'Spotify Technology S.A. is a Swedish audio streaming and media services provider founded in 2006 and headquartered in Stockholm, with its legal seat in Luxembourg.', description_source: 'wikipedia', description_url: WP('Spotify'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 2006, legal_form: 'Société anonyme (Luxembourg)', employees: 7359, employees_year: 2024, revenue: money(15673000000, 'EUR', 2024), net_income: money(1138000000, 'EUR', 2024), total_assets: money(11100000000, 'EUR', 2024), hq: { city: 'Stockholm', region: null, country: 'SE', address: 'Regeringsgatan 19', lat: 59.3326, lon: 18.0649 }, ticker: 'SPOT', exchange: 'NYSE', isin: 'LU1778762911', lei: '549300I8UDPDOMRCNP86', sec_cik: '0001639920', public_company: true, wikipedia_url: WP('Spotify'), wikidata_url: WD('Q689141'), official_website: 'https://www.spotify.com', phone: null, products: ['Spotify', 'Spotify Premium', 'Spotify for Artists', 'Spotify for Podcasters', 'Anchor'], industry_labels: ['music streaming', 'podcasting'], socials: { linkedin: 'https://www.linkedin.com/company/spotify', x: 'https://x.com/Spotify', youtube: 'https://www.youtube.com/@Spotify', instagram: 'https://www.instagram.com/spotify', github: 'https://github.com/spotify' }, }, adyen: { description: 'Adyen N.V. is a Dutch payment company headquartered in Amsterdam that provides a single platform for accepting payments across online, mobile and in-store channels.', description_source: 'wikipedia', description_url: WP('Adyen'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 2006, legal_form: 'Naamloze vennootschap (public)', employees: 4322, employees_year: 2024, revenue: money(1996000000, 'EUR', 2024), net_income: money(925000000, 'EUR', 2024), total_assets: null, hq: { city: 'Amsterdam', region: 'North Holland', country: 'NL', address: 'Simon Carmiggeltstraat 6-50', lat: 52.3765, lon: 4.9016 }, ticker: 'ADYEN', exchange: 'Euronext Amsterdam', isin: 'NL0012969182', lei: '724500PSWKAY73WSLD26', sec_cik: null, public_company: true, wikipedia_url: WP('Adyen'), wikidata_url: WD('Q19833716'), official_website: 'https://www.adyen.com', phone: null, products: ['Adyen Platform', 'Adyen for Platforms', 'Adyen Issuing', 'Adyen Terminal'], industry_labels: ['payment service provider', 'financial technology'], socials: { linkedin: 'https://www.linkedin.com/company/adyen', x: 'https://x.com/Adyen', youtube: 'https://www.youtube.com/@adyen', github: 'https://github.com/Adyen' }, }, arm: { description: 'Arm Holdings plc is a British semiconductor and software design company based in Cambridge that licenses processor architectures and IP cores; majority-owned by SoftBank Group.', description_source: 'wikipedia', description_url: WP('Arm_Holdings'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 1990, legal_form: 'Public limited company', employees: 8300, employees_year: 2025, revenue: money(4007000000, 'USD', 2025), net_income: money(792000000, 'USD', 2025), total_assets: money(8700000000, 'USD', 2025), hq: { city: 'Cambridge', region: 'Cambridgeshire', country: 'GB', address: '110 Fulbourn Road', lat: 52.1839, lon: 0.1791 }, ticker: 'ARM', exchange: 'NASDAQ', isin: 'US0420682058', lei: '213800ND9OV4ZZKK7O47', sec_cik: '0001973239', public_company: true, wikipedia_url: WP('Arm_Holdings'), wikidata_url: WD('Q1063165'), official_website: 'https://www.arm.com', phone: null, products: ['Cortex-A', 'Cortex-M', 'Neoverse', 'Mali', 'Armv9', 'Arm Compute Subsystems'], industry_labels: ['semiconductor industry', 'intellectual property licensing'], socials: { linkedin: 'https://www.linkedin.com/company/arm', x: 'https://x.com/Arm', youtube: 'https://www.youtube.com/@Arm', github: 'https://github.com/ARM-software' }, financial_source: 'sec_edgar', }, tsmc: { description: 'Taiwan Semiconductor Manufacturing Company Limited is a Taiwanese multinational semiconductor contract manufacturing and design company headquartered in Hsinchu Science Park; it is the world’s largest dedicated independent semiconductor foundry.', description_source: 'wikipedia', description_url: WP('TSMC'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 1987, legal_form: 'Public company', employees: 83825, employees_year: 2024, revenue: money(2894307000000, 'TWD', 2024), net_income: money(1173268000000, 'TWD', 2024), total_assets: money(6691000000000, 'TWD', 2024), hq: { city: 'Hsinchu', region: null, country: 'TW', address: '8 Li-Hsin Road 6, Hsinchu Science Park', lat: 24.7739, lon: 121.0107 }, ticker: '2330', exchange: 'TWSE', isin: 'TW0002330008', lei: '549300YSKHMGWXOR9E51', sec_cik: '0001046179', public_company: true, wikipedia_url: WP('TSMC'), wikidata_url: WD('Q713418'), official_website: 'https://www.tsmc.com', phone: null, products: ['3 nm process', '5 nm process', 'CoWoS', 'InFO'], industry_labels: ['semiconductor industry', 'semiconductor fabrication'], socials: { linkedin: 'https://www.linkedin.com/company/tsmc', youtube: 'https://www.youtube.com/@tsmc' }, }, siemens: { description: 'Siemens AG is a German multinational technology conglomerate headquartered in Munich, focused on industrial automation, smart infrastructure, rail transport and, through Siemens Healthineers, medical technology.', description_source: 'wikipedia', description_url: WP('Siemens'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 1847, legal_form: 'Aktiengesellschaft (public)', employees: 327000, employees_year: 2024, revenue: money(75930000000, 'EUR', 2024), net_income: money(9000000000, 'EUR', 2024), total_assets: money(146000000000, 'EUR', 2024), hq: { city: 'Munich', region: 'Bavaria', country: 'DE', address: 'Werner-von-Siemens-Straße 1', lat: 48.1396, lon: 11.5744 }, ticker: 'SIE', exchange: 'XETRA', isin: 'DE0007236101', lei: 'W38RGI023J3WT1HWRP32', sec_cik: null, public_company: true, wikipedia_url: WP('Siemens'), wikidata_url: WD('Q81230'), official_website: 'https://www.siemens.com', phone: '+49 89 636-00', products: ['SIMATIC', 'Siemens Xcelerator', 'TIA Portal', 'Desigo', 'Velaro', 'Mobility Vectron'], industry_labels: ['industrial automation', 'electrical engineering', 'rail transport'], socials: { linkedin: 'https://www.linkedin.com/company/siemens', x: 'https://x.com/Siemens', youtube: 'https://www.youtube.com/@Siemens', instagram: 'https://www.instagram.com/siemens' }, }, 'samsung-electronics': { description: 'Samsung Electronics Co., Ltd. is a South Korean multinational electronics company headquartered in Suwon, and the flagship affiliate of the Samsung Group, producing memory chips, displays, smartphones and home appliances.', description_source: 'wikipedia', description_url: WP('Samsung_Electronics'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 1969, legal_form: 'Chusik hoesa (public)', employees: 267860, employees_year: 2023, revenue: money(300870900000000, 'KRW', 2024), net_income: money(34451000000000, 'KRW', 2024), total_assets: money(514531900000000, 'KRW', 2024), hq: { city: 'Suwon', region: 'Gyeonggi', country: 'KR', address: '129 Samsung-ro, Yeongtong-gu', lat: 37.2599, lon: 127.0303 }, ticker: '005930', exchange: 'KRX', isin: 'KR7005930003', lei: '988400E5HRVX81AYLM04', sec_cik: null, public_company: true, wikipedia_url: WP('Samsung_Electronics'), wikidata_url: WD('Q20718'), official_website: 'https://www.samsung.com', phone: null, products: ['Galaxy S', 'Galaxy Z', 'Galaxy Tab', 'Neo QLED', 'Bespoke', 'Exynos', 'HBM3E'], industry_labels: ['consumer electronics', 'semiconductor industry', 'display technology'], socials: { linkedin: 'https://www.linkedin.com/company/samsung-electronics', x: 'https://x.com/Samsung', youtube: 'https://www.youtube.com/@Samsung', instagram: 'https://www.instagram.com/samsung', facebook: 'https://www.facebook.com/SamsungGlobal', tiktok: 'https://www.tiktok.com/@samsung' }, }, // ---- partial profiles stripe: { description: 'Stripe, Inc. is an Irish-American multinational financial services and software-as-a-service company dual-headquartered in South San Francisco, California, and Dublin, Ireland. It offers payment-processing software and APIs for e-commerce websites and mobile applications.', description_source: 'wikipedia', description_url: WP('Stripe,_Inc.'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 2010, legal_form: 'Private company', employees: 8550, employees_year: 2024, hq: { city: 'South San Francisco', region: 'California', country: 'US', address: '354 Oyster Point Blvd', lat: 37.6547, lon: -122.3894 }, public_company: false, wikipedia_url: WP('Stripe,_Inc.'), wikidata_url: WD('Q10318979'), official_website: 'https://stripe.com', products: ['Stripe Payments', 'Stripe Connect', 'Stripe Billing', 'Stripe Terminal', 'Stripe Radar', 'Stripe Atlas', 'Stripe Issuing', 'Stripe Treasury'], industry_labels: ['payment service provider', 'financial technology'], socials: { linkedin: 'https://www.linkedin.com/company/stripe', x: 'https://x.com/stripe', youtube: 'https://www.youtube.com/@StripeDevelopers', github: 'https://github.com/stripe', crunchbase: 'https://www.crunchbase.com/organization/stripe' }, }, shopify: { description: 'Shopify Inc. is a Canadian multinational e-commerce company headquartered in Ottawa, Ontario, that provides a proprietary platform for online stores and retail point-of-sale systems.', description_source: 'wikipedia', description_url: WP('Shopify'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 2006, legal_form: 'Public company (Canada Business Corporations Act)', employees: 8100, employees_year: 2024, revenue: money(8880000000, 'USD', 2024), net_income: money(2020000000, 'USD', 2024), hq: { city: 'Ottawa', region: 'Ontario', country: 'CA', address: '151 O’Connor Street', lat: 45.4215, lon: -75.6972 }, ticker: 'SHOP', exchange: 'TSX · NASDAQ', isin: 'CA82509L1076', lei: '549300HPKKP5AVXRM893', sec_cik: '0001594805', public_company: true, wikipedia_url: WP('Shopify'), wikidata_url: WD('Q3963870'), official_website: 'https://www.shopify.com', products: ['Shopify', 'Shopify Plus', 'Shopify POS', 'Shopify Payments', 'Shop Pay', 'Shop app', 'Shopify Magic'], industry_labels: ['e-commerce', 'software as a service'], socials: { linkedin: 'https://www.linkedin.com/company/shopify', x: 'https://x.com/Shopify', youtube: 'https://www.youtube.com/@Shopify', github: 'https://github.com/Shopify' }, financial_source: 'sec_edgar', }, cohere: { description: 'Cohere is a Toronto-based AI company that builds large language models and retrieval systems for enterprises, offered through an API and deployed in private clouds. Its public pages emphasise data privacy and multilingual models.', description_source: 'llm', description_url: null, description_license: null, logo: false, icon: true, founded_year: 2019, legal_form: 'Private company', employees: null, employees_year: null, hq: { city: 'Toronto', region: 'Ontario', country: 'CA', address: null, lat: 43.6532, lon: -79.3832 }, public_company: false, wikipedia_url: WP('Cohere'), wikidata_url: WD('Q108024780'), official_website: 'https://cohere.com', products: ['Command', 'Embed', 'Rerank', 'Aya', 'North'], industry_labels: ['artificial intelligence'], socials: { linkedin: 'https://www.linkedin.com/company/cohere-ai', x: 'https://x.com/cohere', github: 'https://github.com/cohere-ai', youtube: 'https://www.youtube.com/@cohere-ai' }, }, anthropic: { description: 'American artificial intelligence company founded in 2021, developer of the Claude family of large language models.', description_source: 'wikidata', description_url: WD('Q109832790'), description_license: 'CC0', logo: false, icon: true, founded_year: 2021, legal_form: 'Public-benefit corporation', employees: null, employees_year: null, hq: { city: 'San Francisco', region: 'California', country: 'US', address: null, lat: 37.7749, lon: -122.4194 }, public_company: false, wikipedia_url: WP('Anthropic'), wikidata_url: WD('Q109832790'), official_website: 'https://www.anthropic.com', products: ['Claude'], industry_labels: ['artificial intelligence'], socials: { linkedin: 'https://www.linkedin.com/company/anthropicresearch', x: 'https://x.com/AnthropicAI', youtube: 'https://www.youtube.com/@anthropic-ai', github: 'https://github.com/anthropics' }, }, 'mistral-ai': { description: 'Mistral AI is a French artificial intelligence company headquartered in Paris that develops open-weight and commercial large language models.', description_source: 'wikipedia', description_url: WP('Mistral_AI'), description_license: 'CC BY-SA 4.0', logo: true, icon: false, founded_year: 2023, legal_form: 'Société par actions simplifiée', employees: null, employees_year: null, hq: { city: 'Paris', region: 'Île-de-France', country: 'FR', address: null, lat: 48.8566, lon: 2.3522 }, public_company: false, wikipedia_url: WP('Mistral_AI'), wikidata_url: WD('Q119711183'), official_website: 'https://mistral.ai', products: ['Mistral Large', 'Mistral Small', 'Codestral', 'Le Chat', 'Pixtral'], industry_labels: ['artificial intelligence'], socials: { linkedin: 'https://www.linkedin.com/company/mistralai', x: 'https://x.com/MistralAI', github: 'https://github.com/mistralai' }, }, nubank: { description: 'Nu Holdings Ltd. is a Brazilian neobank headquartered in São Paulo, operating in Brazil, Mexico and Colombia; it is one of the largest digital banking platforms in the world by customer count.', description_source: 'wikipedia', description_url: WP('Nubank'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 2013, legal_form: 'Cayman Islands holding company', employees: null, employees_year: null, revenue: money(11500000000, 'USD', 2024), net_income: money(1970000000, 'USD', 2024), hq: { city: 'São Paulo', region: 'São Paulo', country: 'BR', address: null, lat: -23.5505, lon: -46.6333 }, ticker: 'NU', exchange: 'NYSE', isin: 'KYG6683N1034', sec_cik: '0001691493', public_company: true, wikipedia_url: WP('Nubank'), wikidata_url: WD('Q28129905'), official_website: 'https://nubank.com.br', products: ['Nu conta', 'Nu cartão', 'NuInvest', 'Nu Pagamentos'], industry_labels: ['neobank', 'financial technology'], socials: { linkedin: 'https://www.linkedin.com/company/nubank', x: 'https://x.com/nubank', instagram: 'https://www.instagram.com/nubank', youtube: 'https://www.youtube.com/@nubank' }, financial_source: 'sec_edgar', }, revolut: { description: 'Revolut Group Holdings Ltd is a British fintech company headquartered in London offering banking services, including multi-currency accounts, cards, trading and crypto, to retail and business customers.', description_source: 'wikipedia', description_url: WP('Revolut'), description_license: 'CC BY-SA 4.0', logo: true, icon: true, founded_year: 2015, legal_form: 'Private limited company', employees: 10000, employees_year: 2024, hq: { city: 'London', region: 'England', country: 'GB', address: null, lat: 51.5074, lon: -0.1278 }, public_company: false, wikipedia_url: WP('Revolut'), wikidata_url: WD('Q21179207'), official_website: 'https://www.revolut.com', products: ['Revolut', 'Revolut Business', 'Revolut X', 'Revolut <18'], industry_labels: ['neobank', 'financial technology'], socials: { linkedin: 'https://www.linkedin.com/company/revolut', x: 'https://x.com/RevolutApp', instagram: 'https://www.instagram.com/revolutapp', youtube: 'https://www.youtube.com/@Revolut' }, }, klarna: { description: 'Klarna Group plc is a Swedish fintech company that provides online financial services such as payments for online storefronts, direct payments and post-purchase payments.', description_source: 'wikipedia', description_url: WP('Klarna'), description_license: 'CC BY-SA 4.0', logo: true, icon: false, founded_year: 2005, legal_form: 'Public limited company', employees: 3422, employees_year: 2024, revenue: money(2810000000, 'USD', 2024), hq: { city: 'Stockholm', region: null, country: 'SE', address: 'Sveavägen 46', lat: 59.3376, lon: 18.0603 }, ticker: 'KLAR', exchange: 'NYSE', public_company: true, wikipedia_url: WP('Klarna'), wikidata_url: WD('Q1747210'), official_website: 'https://www.klarna.com', products: ['Klarna', 'Pay in 4', 'Klarna Card'], industry_labels: ['financial technology', 'buy now, pay later'], socials: { linkedin: 'https://www.linkedin.com/company/klarna', x: 'https://x.com/Klarna', instagram: 'https://www.instagram.com/klarna' }, }, }; /** Build a full-shape profile from a sample; `null` fills everything the sample omits (the UI must hide those). */ function makeProfile(c, sample) { const base = { description: null, description_source: null, description_url: null, description_license: null, logo_url: null, icon_url: null, founded_year: null, legal_form: null, employees: null, employees_year: null, revenue: null, net_income: null, total_assets: null, hq: { city: null, region: null, country: null, address: null, lat: null, lon: null }, ticker: null, exchange: null, isin: null, lei: null, sec_cik: null, public_company: false, wikipedia_url: null, wikidata_url: null, official_website: null, phone: null, products: [], industries: [], industry_labels: [], socials: {}, enriched_at: null, sources: [], }; if (!sample) return base; const { logo, icon, extra_facts, financial_source, ...rest } = sample; const p = { ...base, ...rest, hq: { ...base.hq, ...(rest.hq ?? {}) } }; if (logo) p.logo_url = `${MOCK_ASSET_BASE}/logo/${c.slug}.svg`; if (icon) p.icon_url = `${MOCK_ASSET_BASE}/icon/${c.slug}.svg`; p.enriched_at = RETRIEVED; const src = (field, source, url) => p.sources.push({ field, source, url: url ?? null, retrieved_at: RETRIEVED }); if (p.description) src('description', p.description_source ?? 'wikidata', p.description_url); if (p.logo_url || p.icon_url) src('logo_url', 'wikidata', p.wikidata_url); if (p.founded_year) src('founded_year', 'wikidata', p.wikidata_url); if (p.legal_form) src('legal_form', 'wikidata', p.wikidata_url); if (p.hq.city || p.hq.country) src('hq', 'wikidata', p.wikidata_url); if (typeof p.employees === 'number') src('employees', financial_source === 'sec_edgar' ? 'sec_edgar' : 'wikidata', financial_source === 'sec_edgar' && p.sec_cik ? `https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=${p.sec_cik}` : p.wikidata_url); for (const k of ['revenue', 'net_income', 'total_assets']) if (p[k]) src(k, financial_source === 'sec_edgar' ? 'sec_edgar' : 'wikidata', financial_source === 'sec_edgar' && p.sec_cik ? `https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=${p.sec_cik}` : p.wikidata_url); if (p.ticker) src('ticker', 'wikidata', p.wikidata_url); if (p.isin) src('isin', 'wikidata', p.wikidata_url); if (p.lei) src('lei', 'gleif', `https://search.gleif.org/#/record/${p.lei}`); if (p.sec_cik) src('sec_cik', 'sec_edgar', `https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK=${p.sec_cik}`); if (p.products.length) src('products', 'wikidata', p.wikidata_url); if (p.industry_labels.length) src('industry_labels', 'wikidata', p.wikidata_url); if (p.phone) src('phone', 'homepage', p.official_website); if (Object.keys(p.socials).length) src('socials', 'homepage', p.official_website); if (p.wikipedia_url) src('wikipedia_url', 'wikidata', p.wikidata_url); return p; } /** Minimal auto profile for companies without a hand-written sample: registry description, HQ, listing; no logo, no numbers. */ function autoProfile(c) { return makeProfile(c, { description: c.description, description_source: 'homepage', description_url: c.website, founded_year: c.founded_year, hq: { city: c.hq_city, country: c.country, lat: c._lat, lon: c._lon }, ticker: c.ticker, exchange: c.exchange, public_company: c.public_company, official_website: c.website, logo: false, icon: chance(0.6) }); } /** Flattened, pre-formatted facts (`CompanyDetail.facts`) — the structured profile + registry extras. */ function factsOf(c) { const p = c.profile; if (!p) return []; const out = []; const bySrc = Object.fromEntries(p.sources.map((s) => [s.field, s])); const add = (key, label, value, field = key) => { const s = bySrc[field]; if (value === null || value === undefined || value === '') return; out.push({ key, label, value: String(value), source: s?.source ?? 'wikidata', url: s?.url ?? p.wikidata_url, retrieved_at: s?.retrieved_at ?? RETRIEVED }); }; add('founded_year', 'Founded', p.founded_year); add('hq', 'Headquarters', [p.hq.city, p.hq.region, p.hq.country].filter(Boolean).join(', ') || null); add('employees', 'Employees', typeof p.employees === 'number' ? `${p.employees}${p.employees_year ? ` (${p.employees_year})` : ''}` : null); for (const [k, label] of [['revenue', 'Revenue'], ['net_income', 'Net income'], ['total_assets', 'Total assets']]) if (p[k]) add(k, label, `${p[k].value} ${p[k].currency} (${p[k].year})`); add('legal_form', 'Legal form', p.legal_form); add('isin', 'ISIN', p.isin); add('lei', 'LEI', p.lei); add('sec_cik', 'SEC CIK', p.sec_cik); for (const f of PROFILES[c.slug]?.extra_facts ?? []) out.push({ key: f.key, label: f.label, value: f.value, source: f.source, url: f.source === 'wikidata' ? p.wikidata_url : null, retrieved_at: RETRIEVED }); return out; } // relationships in the v1.1 shape: [kind, counterpart (atlas slug or plain name), valid_from, valid_to, confidence, source, property] const WDP = (prop) => ({ source: 'wikidata', property: prop }); const RELATIONS = { nvidia: [['PARENT_OF', 'Mellanox Technologies', '2020-04-27', null, 0.97, WDP('P355')], ['PARENT_OF', 'Cumulus Networks', '2020-05-04', null, 0.9, WDP('P355')], ['PARENT_OF', 'NVIDIA GmbH', null, null, 0.85, WDP('P355')], ['ACQUIRED', 'Run:ai', '2024-12-30', null, 0.9, WDP('P1830')], ['ACQUIRED', 'OctoAI', '2024-09-30', null, 0.8, WDP('P1830')], ['PARTNER', 'tsmc', null, null, 0.75, { source: 'registry' }], ['COMPETITOR', 'arm', null, null, 0.6, { source: 'registry' }]], apple: [['PARENT_OF', 'Beats Electronics', '2014-08-01', null, 0.98, WDP('P355')], ['PARENT_OF', 'Shazam', '2018-09-24', null, 0.95, WDP('P355')], ['PARENT_OF', 'Claris International', '1998-01-01', null, 0.9, WDP('P355')], ['PARENT_OF', 'Apple Sales International', null, null, 0.85, WDP('P355')], ['PARENT_OF', 'Braeburn Capital', '2005-01-01', null, 0.85, WDP('P355')], ['ACQUIRED', 'NeXT', '1997-02-07', null, 0.99, WDP('P1830')], ['PARTNER', 'tsmc', null, null, 0.7, { source: 'registry' }], ['COMPETITOR', 'samsung-electronics', null, null, 0.7, { source: 'registry' }]], sony: [['PARENT_OF', 'Sony Interactive Entertainment', '2016-04-01', null, 0.98, WDP('P355')], ['PARENT_OF', 'Sony Pictures Entertainment', '1991-08-07', null, 0.98, WDP('P355')], ['PARENT_OF', 'Sony Music Entertainment', '1991-01-01', null, 0.98, WDP('P355')], ['PARENT_OF', 'Sony Semiconductor Solutions', '2016-04-01', null, 0.95, WDP('P355')], ['PARENT_OF', 'Sony Music Publishing', '2012-06-29', null, 0.9, WDP('P355')], ['PARENT_OF', 'Crunchyroll', '2021-08-09', null, 0.95, WDP('P355')], ['PARENT_OF', 'Bungie', '2022-07-15', null, 0.95, WDP('P355')], ['PARENT_OF', 'Insomniac Games', '2019-08-19', null, 0.95, WDP('P355')], ['PARENT_OF', 'Aniplex', '1995-09-01', null, 0.9, WDP('P355')], ['PARENT_OF', 'Sony Honda Mobility', '2022-09-28', null, 0.8, WDP('P355')], ['PARENT_OF', 'Sony Financial Group', '2004-04-01', '2025-10-01', 0.85, WDP('P355')], ['OWNER_OF', 'Olympus Corporation', '2012-09-28', '2019-08-30', 0.8, WDP('P1830')], ['COMPETITOR', 'samsung-electronics', null, null, 0.6, { source: 'registry' }]], toyota: [['PARENT_OF', 'Daihatsu', '2016-08-01', null, 0.98, WDP('P355')], ['PARENT_OF', 'Hino Motors', '2001-01-01', null, 0.95, WDP('P355')], ['PARENT_OF', 'Toyota Financial Services', '2000-07-01', null, 0.9, WDP('P355')], ['PARENT_OF', 'Woven by Toyota', '2021-01-01', null, 0.85, WDP('P355')], ['PARENT_OF', 'Toyota Motor Europe', null, null, 0.85, WDP('P355')], ['OWNER_OF', 'Subaru Corporation', '2019-12-27', null, 0.8, WDP('P1830')], ['OWNER_OF', 'Mazda Motor Corporation', '2017-08-04', null, 0.7, WDP('P1830')]], roche: [['PARENT_OF', 'Genentech', '2009-03-26', null, 0.99, WDP('P355')], ['PARENT_OF', 'Chugai Pharmaceutical', '2002-10-01', null, 0.95, WDP('P355')], ['PARENT_OF', 'Foundation Medicine', '2018-07-31', null, 0.95, WDP('P355')], ['PARENT_OF', 'Spark Therapeutics', '2019-12-17', null, 0.95, WDP('P355')], ['PARENT_OF', 'Flatiron Health', '2018-04-06', null, 0.9, WDP('P355')], ['PARENT_OF', 'Ventana Medical Systems', '2008-02-01', null, 0.9, WDP('P355')]], sap: [['PARENT_OF', 'Qualtrics', '2019-01-23', '2023-06-28', 0.95, WDP('P355')], ['PARENT_OF', 'SAP Concur', '2014-12-04', null, 0.95, WDP('P355')], ['PARENT_OF', 'SAP Ariba', '2012-10-01', null, 0.95, WDP('P355')], ['PARENT_OF', 'SAP SuccessFactors', '2012-02-01', null, 0.95, WDP('P355')], ['PARENT_OF', 'SAP Fieldglass', '2014-05-01', null, 0.9, WDP('P355')], ['PARENT_OF', 'Signavio', '2021-03-05', null, 0.9, WDP('P355')], ['PARENT_OF', 'LeanIX', '2023-11-08', null, 0.85, WDP('P355')], ['PARENT_OF', 'WalkMe', '2024-09-12', null, 0.85, WDP('P355')], ['PARTNER', 'siemens', null, null, 0.5, { source: 'registry' }]], spotify: [['PARENT_OF', 'Anchor', '2019-02-06', null, 0.9, WDP('P355')], ['PARENT_OF', 'Megaphone', '2020-12-15', null, 0.9, WDP('P355')], ['PARENT_OF', 'Podsights', '2022-02-16', null, 0.8, WDP('P355')], ['PARENT_OF', 'Findaway', '2022-06-01', null, 0.8, WDP('P355')]], adyen: [['PARENT_OF', 'Adyen Bank N.V.', null, null, 0.8, WDP('P355')], ['COMPETITOR', 'stripe', null, null, 0.7, { source: 'registry' }]], arm: [['SUBSIDIARY_OF', 'SoftBank Group', '2016-09-05', null, 0.98, WDP('P749')], ['OWNED_BY', 'SoftBank Group', '2016-09-05', null, 0.95, WDP('P127')], ['PARENT_OF', 'Arm China', '2018-04-01', null, 0.7, WDP('P355')], ['COMPETITOR', 'nvidia', null, null, 0.5, { source: 'registry' }]], tsmc: [['PARENT_OF', 'TSMC Arizona', '2020-05-15', null, 0.95, WDP('P355')], ['PARENT_OF', 'WaferTech', '1996-06-01', null, 0.9, WDP('P355')], ['OWNER_OF', 'ESMC (European Semiconductor Manufacturing Company)', '2023-08-08', null, 0.85, WDP('P1830')], ['OWNER_OF', 'Vanguard International Semiconductor', '1994-12-01', null, 0.8, WDP('P1830')], ['PARTNER', 'nvidia', null, null, 0.7, { source: 'registry' }], ['PARTNER', 'apple', null, null, 0.7, { source: 'registry' }]], siemens: [['PARENT_OF', 'Siemens Healthineers', '2018-03-16', null, 0.95, WDP('P355')], ['PARENT_OF', 'Siemens Mobility', '2018-08-01', null, 0.95, WDP('P355')], ['PARENT_OF', 'Siemens Financial Services', null, null, 0.85, WDP('P355')], ['PARENT_OF', 'Siemens Energy', '2020-04-01', '2020-09-28', 0.9, WDP('P355')], ['OWNER_OF', 'Siemens Energy', '2020-09-28', null, 0.8, WDP('P1830')], ['ACQUIRED', 'Altair Engineering', '2025-03-26', null, 0.9, WDP('P1830')], ['ACQUIRED', 'Brightly Software', '2022-06-27', null, 0.85, WDP('P1830')]], 'samsung-electronics': [['PARENT_OF', 'Harman International', '2017-03-10', null, 0.98, WDP('P355')], ['PARENT_OF', 'Samsung Display', '2012-04-01', null, 0.95, WDP('P355')], ['PARENT_OF', 'Samsung Electronics America', null, null, 0.9, WDP('P355')], ['PARENT_OF', 'Samsung Medison', '2011-04-01', null, 0.85, WDP('P355')], ['OWNED_BY', 'Samsung Life Insurance', null, null, 0.7, WDP('P127')], ['COMPETITOR', 'apple', null, null, 0.7, { source: 'registry' }]], stripe: [['PARENT_OF', 'Stripe Payments Europe, Ltd.', null, null, 0.85, WDP('P355')], ['PARENT_OF', 'Stripe Payments UK, Ltd.', null, null, 0.8, WDP('P355')], ['ACQUIRED', 'Paystack', '2020-10-15', null, 0.95, WDP('P1830')], ['ACQUIRED', 'Lemon Squeezy', '2024-07-26', null, 0.85, WDP('P1830')], ['ACQUIRED', 'Bridge', '2025-02-04', null, 0.85, WDP('P1830')], ['COMPETITOR', 'adyen', null, null, 0.7, { source: 'registry' }], ['COMPETITOR', 'block', null, null, 0.6, { source: 'registry' }]], shopify: [['ACQUIRED', 'Deliverr', '2022-07-08', '2023-05-04', 0.9, WDP('P1830')], ['ACQUIRED', 'Vantage Discovery', '2025-03-10', null, 0.7, WDP('P1830')], ['PARTNER', 'stripe', null, null, 0.6, { source: 'registry' }]], cohere: [['OWNED_BY', 'Nvidia (minority investor)', '2023-06-08', null, 0.5, { source: 'registry' }]], anthropic: [['OWNED_BY', 'Amazon (minority investor)', '2023-09-25', null, 0.6, { source: 'registry' }], ['OWNED_BY', 'Alphabet (minority investor)', '2023-02-03', null, 0.6, { source: 'registry' }]], nubank: [['PARENT_OF', 'Nu México', '2019-05-01', null, 0.9, WDP('P355')], ['PARENT_OF', 'Nu Colombia', '2020-09-01', null, 0.9, WDP('P355')], ['ACQUIRED', 'Easynvest', '2020-09-01', null, 0.85, WDP('P1830')]], }; function relationsFor(c) { const rows = RELATIONS[c.slug]; if (rows) return rows.map(([kind, who, from, to, confidence, provenance]) => { const other = companiesBySlug.get(who); return { kind, company: other ? { slug: other.slug, display_name: other.display_name, logo_url: other.profile?.logo_url ?? other.profile?.icon_url ?? null } : null, to_name: other ? null : who, valid_from: from, valid_to: to, confidence, provenance }; }); const peer = companies.find((o) => o !== c && o.industries[0] === c.industries[0]); return [{ kind: 'COMPETITOR', company: peer ? { slug: peer.slug, display_name: peer.display_name, logo_url: peer.profile?.logo_url ?? peer.profile?.icon_url ?? null } : null, to_name: peer ? null : 'Unnamed peer', valid_from: null, valid_to: null, confidence: 0.6, provenance: { source: 'registry' } }, { kind: 'PARTNER', company: null, to_name: pick(PARTNERS), valid_from: iso(NOW - 200 * DAY), valid_to: null, confidence: 0.8, provenance: { source: 'registry' } }]; } // Wikidata-sourced executives (`source: 'wikidata'`), some overlapping the page-observed rows to exercise the merge. // [name, title, status, valid_from] const WD_PEOPLE = { nvidia: [['Jensen Huang', 'Chief Executive Officer, President and co-founder', 'listed', '1993-04-05'], ['Colette Kress', 'Chief Financial Officer', 'listed', '2013-09-01'], ['Chris Malachowsky', 'Co-founder', 'listed', '1993-04-05']], apple: [['Tim Cook', 'Chief Executive Officer', 'listed', '2011-08-24'], ['Arthur D. Levinson', 'Chairman of the board', 'listed', '2011-11-15'], ['Kevan Parekh', 'Chief Financial Officer', 'listed', '2025-01-01'], ['Luca Maestri', 'Chief Financial Officer', 'no_longer_listed', '2014-05-29'], ['Steve Jobs', 'Co-founder', 'no_longer_listed', '1976-04-01']], sony: [['Hiroki Totoki', 'President and Chief Executive Officer', 'listed', '2025-04-01'], ['Kenichiro Yoshida', 'Chairman', 'listed', '2025-04-01'], ['Lin Tao', 'Chief Financial Officer', 'listed', '2025-04-01'], ['Kazuo Hirai', 'Chief Executive Officer', 'no_longer_listed', '2012-04-01']], toyota: [['Koji Sato', 'President and Chief Executive Officer', 'listed', '2023-04-01'], ['Akio Toyoda', 'Chairman of the board', 'listed', '2023-04-01']], roche: [['Thomas Schinecker', 'Chief Executive Officer', 'listed', '2023-03-15'], ['Severin Schwan', 'Chairman of the board', 'listed', '2023-03-15']], sap: [['Christian Klein', 'Chief Executive Officer', 'listed', '2019-10-11'], ['Dominik Asam', 'Chief Financial Officer', 'listed', '2023-03-07'], ['Hasso Plattner', 'Co-founder and Chairman of the supervisory board', 'no_longer_listed', '2003-05-01']], spotify: [['Daniel Ek', 'Chief Executive Officer and co-founder', 'listed', '2006-04-23'], ['Martin Lorentzon', 'Co-founder and Chairman', 'listed', '2006-04-23']], adyen: [['Pieter van der Does', 'Co-founder and co-CEO', 'listed', '2006-01-01'], ['Ingo Uytdehaage', 'Co-CEO', 'listed', '2023-05-01']], arm: [['Rene Haas', 'Chief Executive Officer', 'listed', '2022-02-08'], ['Masayoshi Son', 'Chairman of the board', 'listed', '2016-09-05']], tsmc: [['C. C. Wei', 'Chairman and Chief Executive Officer', 'listed', '2024-06-04'], ['Morris Chang', 'Founder', 'no_longer_listed', '1987-02-21']], siemens: [['Roland Busch', 'President and Chief Executive Officer', 'listed', '2021-02-03'], ['Ralf P. Thomas', 'Chief Financial Officer', 'listed', '2013-09-18']], 'samsung-electronics': [['Jun Young-hyun', 'Vice Chairman and co-CEO', 'listed', '2024-11-27'], ['Roh Tae-moon', 'Acting head, Device eXperience division', 'listed', '2025-03-01']], stripe: [['Patrick Collison', 'Chief Executive Officer and co-founder', 'listed', '2010-01-01'], ['John Collison', 'President and co-founder', 'listed', '2010-01-01']], shopify: [['Tobias Lütke', 'Chief Executive Officer and founder', 'listed', '2008-01-01'], ['Harley Finkelstein', 'President', 'listed', '2020-09-01']], cohere: [['Aidan Gomez', 'Chief Executive Officer and co-founder', 'listed', '2019-01-01'], ['Nick Frosst', 'Co-founder', 'listed', '2019-01-01'], ['Ivan Zhang', 'Co-founder', 'listed', '2019-01-01']], anthropic: [['Dario Amodei', 'Chief Executive Officer and co-founder', 'listed', '2021-01-01'], ['Daniela Amodei', 'President and co-founder', 'listed', '2021-01-01']], 'mistral-ai': [['Arthur Mensch', 'Chief Executive Officer and co-founder', 'listed', '2023-04-28'], ['Guillaume Lample', 'Chief Scientist and co-founder', 'listed', '2023-04-28'], ['Timothée Lacroix', 'Chief Technology Officer and co-founder', 'listed', '2023-04-28']], nubank: [['David Vélez', 'Chief Executive Officer and founder', 'listed', '2013-05-06'], ['Cristina Junqueira', 'Co-founder', 'listed', '2013-05-06']], }; function wikidataPeople(c) { const rows = WD_PEOPLE[c.slug] ?? []; const url = c.profile?.wikidata_url ?? `https://www.wikidata.org/wiki/Special:Search?search=${encodeURIComponent(c.display_name)}`; return rows.map(([name, title, status, from]) => ({ id: id('per'), name, title, role_category: /chair/i.test(title) ? 'board' : 'c_suite', is_executive: true, first_seen_at: iso(new Date(from).getTime()), last_seen_at: RETRIEVED, removed_at: status === 'listed' ? null : iso(NOW - ri(200, 2000) * DAY), status, source_url: url, source: 'wikidata' })); } /** Self-hosted sample logos (plate + monogram) so QA never depends on the network; `icon` is the round variant. */ function logoSvg(slug, round) { const name = companiesBySlug.get(slug)?.display_name ?? slug; const words = name.split(/\s+/).filter(Boolean); const mono = (words.length > 1 ? words[0][0] + words[1][0] : name.slice(0, 1)).toUpperCase(); let h = 0; for (const ch of slug) h = (h * 31 + ch.charCodeAt(0)) >>> 0; const hue = h % 360; return `${mono}`; } // ------------------------------------------------------------------------------------------------ build dataset const companies = []; const companiesBySlug = new Map(); const sensors = new Map(); const snapshots = new Map(); const changes = new Map(); const events = []; const eventsById = new Map(); const perCompany = new Map(); function series(days, base, vol, drift = 0) { const out = []; let v = base; for (let i = days - 1; i >= 0; i--) { v = clamp(v + (rnd() - 0.5) * vol + drift, 0, 100); out.push({ day: day(NOW - i * DAY), value: r1(v), confidence: r1(0.6 + rnd() * 0.35) }); } return out; } const blockKinds = ['heading', 'paragraph', 'list', 'card', 'table', 'nav']; function makeBlocks(surface, n) { const blocks = []; for (let i = 0; i < n; i++) { const kind = pick(blockKinds); blocks.push({ key: `${surface}:${kind}:${i}`, kind, path: `main > section:nth-of-type(${1 + Math.floor(i / 3)}) > ${kind === 'heading' ? 'h2' : kind === 'list' ? 'ul' : 'div'}:nth-child(${1 + (i % 3)})`, text: sampleText(surface, i) }); } return blocks; } function sampleText(surface, i) { const map = { pricing: ['Starter — $29 per month. Up to 3 seats, community support.', 'Growth — $99 per month. Unlimited seats, SSO, priority support.', 'Enterprise — Contact sales. Custom SLAs, dedicated support, audit logs.', 'All plans include 14-day trial. Prices in USD, billed annually.'], careers: ['Senior Software Engineer — Toronto, Canada · Engineering', 'Machine Learning Engineer — Remote (EU) · AI Platform', 'Account Executive — London, UK · Sales', 'We are hiring across 12 offices. See all 148 open roles.'], leadership: ['Ava Martin — Chief Executive Officer', 'Noah Chen — Chief Technology Officer', 'Léa Dubois — Chief Financial Officer', 'Our leadership team brings decades of experience across payments and infrastructure.'], locations: ['Headquarters — 354 Oyster Point Blvd, South San Francisco', 'Dublin — Grand Canal Dock', 'Singapore — Raffles Place', 'Bengaluru — Indiranagar'], legal: ['7. Limitation of liability. To the maximum extent permitted by law…', '8. Governing law. These terms are governed by the laws of Ireland.', '12. Changes to these terms. We may update these terms; material changes will be notified 30 days in advance.'], products: ['Terminal — In-person payments hardware and SDKs.', 'Radar — Fraud prevention powered by network data.', 'Atlas — Company incorporation in days.', 'Billing — Subscriptions, invoices and revenue recovery.'], }; const arr = map[surface] ?? ['Welcome to our company. We build tools that help teams move faster.', 'Trusted by thousands of businesses worldwide.', 'Read our latest news and product updates.', 'Contact us to learn more about enterprise plans.']; return arr[i % arr.length]; } function buildCompany(row, idx) { const [name, domain, country, city, lat, lon, inds, pub, ticker, exchange, founded, band, importance, desc] = row; const slug = slugify(name); const cid = id('co'); const tier = importance >= 90 ? 1 : importance >= 75 ? 2 : importance >= 55 ? 3 : 4; const created = NOW - ri(120, 420) * DAY; // sensors const nSensors = tier === 1 ? ri(28, 63) : tier === 2 ? ri(16, 32) : tier === 3 ? ri(8, 18) : ri(4, 10); const compSensors = []; const surfacesUsed = []; for (let i = 0; i < nSensors; i++) { const surface = i < SURFACES.length ? SURFACES[i] : pick(SURFACES); surfacesUsed.push(surface); const sid = id('sen'); const stier = surface === 'homepage' || surface === 'newsroom' || surface === 'careers' ? pick(['A', 'B']) : surface === 'legal' || surface === 'sitemap' ? pick(['D', 'E']) : pick(['B', 'C', 'C', 'D']); const statusRoll = rnd(); const status = statusRoll < 0.86 ? 'active' : statusRoll < 0.93 ? 'failing' : statusRoll < 0.97 ? 'paused' : 'retired'; const obs = ri(40, 2400); const snaps = ri(3, 12); const chg = Math.floor(snaps * (0.4 + rnd())); const path = SURFACE_PATH[surface] ?? `/${surface}`; const url = `https://${domain}${path}${i >= SURFACES.length ? `?p=${i}` : ''}`; const lastRun = NOW - ri(1, 300) * 60_000; const failing = status === 'failing'; const sensor = { id: sid, company_id: cid, surface, connector_id: CONNECTOR_FOR[surface] ?? 'generic_html', url, canonical_url: url, domain, status, tier: stier, quality_score: r1(45 + rnd() * 55), discovery_confidence: r1(0.55 + rnd() * 0.45), discovery_method: pick(['navigation', 'sitemap', 'url_pattern', 'json_ld', 'manual']), current_interval_s: TIER_INTERVAL[stier] * (failing ? 4 : 1), next_run_at: iso(lastRun + TIER_INTERVAL[stier] * 1000), last_run_at: iso(lastRun), last_success_at: failing ? iso(NOW - ri(2, 6) * DAY) : iso(lastRun), last_change_at: iso(NOW - ri(1, 30) * DAY), last_status: failing ? pick([403, 429, 503, 0]) : 200, last_failure_class: failing ? pick(FAILURE_CLASSES) : null, consecutive_failures: failing ? ri(3, 40) : 0, observation_count: obs, snapshot_count: snaps, change_count: chg, meaningful_change_count: Math.floor(chg * 0.35), event_count: 0, created_at: iso(created + ri(0, 10) * DAY), _versions: [], _changes: [], }; // snapshots (versions) and changes let prev = null; let t = created + ri(1, 20) * DAY; for (let v = 1; v <= snaps; v++) { const snapId = id('snap'); t += ri(2, 20) * DAY; if (t > NOW) t = NOW - ri(0, 3) * 3600_000; const blocks = makeBlocks(surface, ri(8, 20)); const snap = { id: snapId, sensor_id: sid, version_no: v, fetched_at: iso(t), title: `${name} — ${surface.replace('_', ' ')}`, language: pick(['en', 'en', 'en', 'fr', 'de', 'ja']), text_length: blocks.reduce((a, b) => a + b.text.length, 0) * ri(8, 20), block_count: blocks.length, extracted_summary: surface === 'careers' ? { jobs: ri(5, 200) } : surface === 'pricing' ? { plans: ri(2, 5) } : surface === 'leadership' ? { people: ri(4, 14) } : surface === 'locations' ? { locations: ri(1, 12) } : { blocks: blocks.length }, content_hash: `sha256:${Array.from({ length: 16 }, () => B32[Math.floor(rnd() * 32)].toLowerCase()).join('')}`, previous_snapshot_id: prev ? prev.id : null, _blocks: blocks, _text: blocks.map((b) => b.text).join('\n\n'), }; snapshots.set(snapId, snap); sensor._versions.push(snap); if (prev) { const chgId = id('chg'); const added = blocks.slice(0, ri(0, 3)).map((b) => ({ key: b.key, kind: b.kind, path: b.path, before: null, after: b.text, weight: r1(0.3 + rnd() * 0.7), similarity: null })); const removed = prev._blocks.slice(-ri(0, 2)).map((b) => ({ key: b.key, kind: b.kind, path: b.path, before: b.text, after: null, weight: r1(0.3 + rnd() * 0.7), similarity: null })); const modified = prev._blocks.slice(1, 1 + ri(0, 3)).map((b, k) => ({ key: b.key, kind: b.kind, path: b.path, before: b.text, after: (blocks[k + 1] ?? blocks[0]).text, weight: r1(0.3 + rnd() * 0.7), similarity: r1(0.4 + rnd() * 0.5) })); const sig = clamp(r1(0.1 + (added.length + removed.length + modified.length) * 0.12 + rnd() * 0.25), 0.02, 0.98); const reasons = []; if (added.length) reasons.push(`${added.length} new block${added.length > 1 ? 's' : ''} (${added.map((a) => a.kind).join(', ')})`); if (removed.length) reasons.push(`${removed.length} block${removed.length > 1 ? 's' : ''} no longer present`); if (modified.length) reasons.push(`${modified.length} block${modified.length > 1 ? 's' : ''} modified with low similarity`); if (surface === 'pricing') reasons.push('structured pricing fields changed'); if (surface === 'careers') reasons.push('job count changed'); if (!reasons.length) reasons.push('text delta below noise threshold'); const change = { id: chgId, sensor_id: sid, surface, company_id: cid, detected_at: snap.fetched_at, significance: sig, kind: sig < 0.2 ? 'noise' : sig < 0.4 ? 'minor' : sig < 0.65 ? 'meaningful' : sig < 0.85 ? 'major' : 'critical', blocks_added: added.length, blocks_removed: removed.length, blocks_modified: modified.length, text_delta_ratio: r1(sig * 0.6), similarity: r1(1 - sig * 0.7), snapshot_before: prev.id, snapshot_after: snapId, diff: { added, removed, modified, moved: [], counts: { added: added.length, removed: removed.length, modified: modified.length, unchanged: Math.max(0, blocks.length - added.length - modified.length) }, text_delta_ratio: r1(sig * 0.6), similarity: r1(1 - sig * 0.7), reasons }, structured_delta: surface === 'careers' ? { jobs_added: added.length + ri(0, 4), jobs_removed: removed.length } : surface === 'pricing' ? { plans_changed: modified.length } : {}, _events: [], }; changes.set(chgId, change); sensor._changes.push(change); } prev = snap; } sensors.set(sid, sensor); compSensors.push(sensor); } // entities const jobs = []; const nJobs = tier === 1 ? ri(60, 240) : tier === 2 ? ri(20, 90) : ri(3, 30); for (let i = 0; i < nJobs; i++) { const title = pick(JOB_TITLES); const cityRow = chance(0.5) ? [city, country] : pick(CITIES); const first = NOW - ri(1, 120) * DAY; const removed = chance(0.22); const removedAt = removed ? first + ri(5, 60) * DAY : null; jobs.push({ id: id('job'), title, department: pick(DEPARTMENTS), location_text: `${cityRow[0]}, ${cityRow[1]}`, city: cityRow[0], country: cityRow[1], remote: chance(0.35), employment_type: pick(['full_time', 'full_time', 'contract', 'internship']), seniority: pick(['junior', 'mid', 'senior', 'staff', 'lead']), url: `https://${domain}/careers/${slugify(title)}-${i}`, posted_at: iso(first - ri(0, 3) * DAY), first_seen_at: iso(first), last_seen_at: iso(removed ? Math.min(NOW, removedAt) : NOW - ri(0, 3) * 3600_000), removed_at: removed && removedAt < NOW ? iso(removedAt) : null, status: removed && removedAt < NOW ? 'no_longer_listed' : 'open', is_ai: /AI|Machine Learning|LLM|Research/.test(title) || chance(0.1), }); } const people = []; for (let i = 0; i < ri(5, 12); i++) { const removed = chance(0.2); const first = NOW - ri(30, 400) * DAY; people.push({ id: id('per'), name: PEOPLE[(idx * 3 + i) % PEOPLE.length], title: TITLES[i % TITLES.length], role_category: i < 6 ? 'c_suite' : 'vp', is_executive: i < 8, first_seen_at: iso(first), last_seen_at: iso(removed ? first + ri(10, 200) * DAY : NOW - ri(0, 2) * DAY), removed_at: removed ? iso(first + ri(10, 200) * DAY) : null, status: removed ? 'no_longer_listed' : 'listed', source_url: `https://${domain}/about/leadership`, source: 'page' }); } // a couple of Wikidata executives also appear on the monitored page (exercise the name merge → both chips) for (const [pname, ptitle] of (WD_PEOPLE[slug] ?? []).slice(0, 1)) people.unshift({ id: id('per'), name: pname, title: ptitle.split(' and ')[0], role_category: 'c_suite', is_executive: true, first_seen_at: iso(created + 5 * DAY), last_seen_at: iso(NOW - DAY), removed_at: null, status: 'listed', source_url: `https://${domain}/about/leadership`, source: 'page' }); const products = []; for (let i = 0; i < ri(3, 10); i++) { const removed = chance(0.15); const first = NOW - ri(30, 400) * DAY; const pname = PRODUCT_NAMES[(idx * 5 + i) % PRODUCT_NAMES.length]; products.push({ id: id('prd'), name: pname, category: pick(['platform', 'api', 'app', 'hardware', 'service']), description: `${pname} by ${name}.`, url: `https://${domain}/products/${slugify(pname)}`, first_seen_at: iso(first), last_seen_at: iso(removed ? first + ri(10, 200) * DAY : NOW - ri(0, 2) * DAY), removed_at: removed ? iso(first + ri(10, 200) * DAY) : null, status: removed ? 'removed' : 'listed' }); } const plans = []; const planNames = ['Starter', 'Growth', 'Scale', 'Enterprise']; let pv = 1; for (let i = 0; i < ri(2, 4); i++) { const pname = planNames[i]; const enterprise = pname === 'Enterprise'; let price = enterprise ? null : [29, 99, 299][i] ?? 49; const versions = ri(1, 3); let from = NOW - ri(200, 400) * DAY; for (let v = 1; v <= versions; v++) { const last = v === versions; const to = last ? null : from + ri(40, 120) * DAY; plans.push({ id: id('pln'), plan_name: pname, price, price_text: enterprise ? 'Contact sales' : `$${price}/mo`, currency: enterprise ? null : 'USD', billing_period: enterprise ? null : 'month', unit: enterprise ? null : 'seat', features: enterprise ? ['Custom SLAs', 'Dedicated support', 'Audit logs', 'SSO'] : [`${[3, 10, 50][i] ?? 5} seats`, 'API access', v > 1 ? 'Priority support' : 'Community support'], contact_sales: enterprise, version_no: pv++, valid_from: iso(from), valid_to: to ? iso(to) : null, status: last ? 'current' : 'superseded', source_url: `https://${domain}/pricing` }); if (to) from = to; if (price !== null) price = Math.round(price * (1 + (rnd() * 0.3 - 0.05))); } } const locations = [{ id: id('loc'), kind: 'headquarters', name: `${name} HQ`, city, region: null, country, lat, lon, first_seen_at: iso(created), last_seen_at: iso(NOW - DAY), removed_at: null, status: 'listed', source_url: `https://${domain}/about/locations` }]; for (let i = 0; i < (tier <= 2 ? ri(3, 9) : ri(0, 3)); i++) { const c = pick(CITIES); const removed = chance(0.15); const first = NOW - ri(30, 400) * DAY; locations.push({ id: id('loc'), kind: pick(['office', 'office', 'office', 'lab', 'warehouse', 'store']), name: `${c[0]} office`, city: c[0], region: null, country: c[1], lat: c[2], lon: c[3], first_seen_at: iso(first), last_seen_at: iso(removed ? first + ri(10, 200) * DAY : NOW - DAY), removed_at: removed ? iso(first + ri(10, 200) * DAY) : null, status: removed ? 'no_longer_listed' : 'listed', source_url: `https://${domain}/about/locations` }); } const news = []; for (let i = 0; i < ri(5, 18); i++) { const t = NOW - ri(0, 120) * DAY; news.push({ id: id('nws'), title: `${name} ${pick(HEADLINES)}`, url: `https://${domain}/newsroom/${t}`, summary: 'First-party newsroom item.', category: pick(['press', 'product', 'company', 'research']), published_at: iso(t), first_seen_at: iso(t + ri(5, 240) * 60_000), language: 'en' }); } // metrics const activity = clamp(importance * 0.6 + rnd() * 40 - 10, 5, 99); const hiring30 = r1((rnd() - 0.42) * 60); const metrics = { activity_score: r1(activity), hiring_momentum_7d: r1(hiring30 / 3 + (rnd() - 0.5) * 8), hiring_momentum_30d: hiring30, hiring_momentum_90d: r1(hiring30 * 1.6 + (rnd() - 0.5) * 12), open_jobs: jobs.filter((j) => j.status === 'open').length, ai_adoption: r1(clamp(inds.includes('artificial-intelligence') ? 70 + rnd() * 30 : rnd() * 70, 0, 100)), product_velocity: r1(clamp(rnd() * 90, 0, 100)), geo_expansion: r1(clamp(rnd() * 80, 0, 100)), developer_momentum: r1(clamp((inds.includes('software') || inds.includes('cloud-infrastructure') ? 40 : 5) + rnd() * 60, 0, 100)), communication_activity: r1(rnd() * 100), pricing_activity: r1(rnd() * 60), leadership_activity: r1(rnd() * 50), corporate_change_index: 0, anomaly_score: r1(rnd() * 100), historical_coverage: r1(60 + rnd() * 40), }; metrics.corporate_change_index = r1(0.25 * clamp(50 + hiring30, 0, 100) + 0.2 * metrics.product_velocity + 0.15 * metrics.geo_expansion + 0.15 * metrics.leadership_activity + 0.1 * metrics.developer_momentum + 0.1 * metrics.communication_activity + 0.05 * metrics.pricing_activity); if (chance(0.12)) delete metrics.ai_adoption; // omit when no inputs (never fabricate) if (chance(0.1)) delete metrics.developer_momentum; const act30 = series(30, metrics.activity_score, 12); const hir90 = series(90, 50 + hiring30 / 2, 8); const seriesAll = { activity_score: series(90, metrics.activity_score, 10), hiring_momentum_30d: hir90.map((p) => ({ ...p, value: r1((p.value - 50) * 2) })), product_velocity: series(90, metrics.product_velocity, 9), ai_adoption: series(90, metrics.ai_adoption ?? 30, 6, 0.1), corporate_change_index: series(90, metrics.corporate_change_index, 7), open_jobs: series(90, 50, 4).map((p) => ({ ...p, value: Math.round(metrics.open_jobs * (0.7 + p.value / 160)) })) }; seriesAll.activity_score.splice(-30, 30, ...act30); const company = { id: cid, slug, display_name: name, legal_name: `${name}${pub ? ' Inc.' : ', Inc.'}`, canonical_domain: domain, website: `https://${domain}`, description: desc, industries: inds, industry_primary: inds[0], country, hq_city: city, hq_region: null, public_company: pub, ticker, exchange, founded_year: founded, employees_band: band, logo_url: null, profile: null, // filled after all companies exist (relationships reference peers) status: chance(0.94) ? 'ACTIVE' : 'POSSIBLY_INACTIVE', onboarding_status: 'active', importance, tier, metrics, counts: { sensors: compSensors.filter((s) => s.status === 'active').length, observations: compSensors.reduce((a, s) => a + s.observation_count, 0), changes: compSensors.reduce((a, s) => a + s.change_count, 0), events: 0, jobs_open: metrics.open_jobs }, last_event_at: null, last_observed_at: iso(NOW - ri(1, 90) * 60_000), sparkline: act30.map((p) => p.value), _lat: lat, _lon: lon, _created: created, _sensors: compSensors, _jobs: jobs, _people: people, _products: products, _plans: plans, _locations: locations, _news: news, _series: seriesAll, _hir90: hir90.map((p) => r1((p.value - 50) * 2)), _signals: [], _aliases: [name.toUpperCase(), `${name} Inc`, domain.split('.')[0]], }; companies.push(company); companiesBySlug.set(slug, company); companiesBySlug.set(cid, company); return company; } SEED.forEach((row, i) => buildCompany(row, i)); for (const c of companies) c.profile = NULL_PROFILE.has(c.slug) || NO_PROFILE_KEY.has(c.slug) ? makeProfile(c, null) : PROFILES[c.slug] ? makeProfile(c, PROFILES[c.slug]) : autoProfile(c); const NO_CATALOGUE = new Set(['anthropic', 'mistral-ai']); // no monitored catalogue surface → Products tab falls back to Wikidata products for (const c of companies) { c._relationships = relationsFor(c); c._facts = factsOf(c); c._people.push(...wikidataPeople(c)); if (NO_CATALOGUE.has(c.slug)) c._products = []; } // events function makeEvent(c, template, t, opts = {}) { const [type, subtype, [imLo, imHi], surfaces, titleFn, summaryFn, ovFn] = template; const p = { name: pick(PRODUCT_NAMES), plan: pick(['Starter', 'Growth', 'Scale', 'Team']), oldPrice: ri(19, 199), city: pick(CITIES)[0], country: COUNTRY_META[pick(Object.keys(COUNTRY_META))][0], jobs: ri(2, 14), n: ri(3, 72), pct: ri(5, 45), ai: ri(0, 9), from: ri(40, 300), section: pick(['7', '8.2', '12', '3.1', 'Data processing addendum', 'Authentication', 'Webhooks', 'Rate limits']), blocks: ri(2, 30), v: ri(3, 14), headline: pick(HEADLINES), partner: pick(PARTNERS), target: `${pick(['Nimbus', 'Lattice', 'Parcel', 'Quill', 'Beacon'])} ${pick(['Labs', 'Systems', 'AI', 'Technologies'])}`, delay: ri(3, 90), amount: `$${pick([40, 75, 120, 250, 500])}M`, kind: pick(['advisory', 'partial outage', 'degraded performance', 'disclosure']), oldHeadline: 'Payments for small businesses', newHeadline: 'The financial infrastructure platform for enterprises', tech: pick(TECHS), item: pick(['Q3 results', 'annual report', 'investor day materials', 'a shareholder letter']), year: 2025, name2: pick(PEOPLE), title: pick(TITLES), }; p.newPrice = subtype === 'PRICE_INCREASE' ? Math.round(p.oldPrice * (1.05 + rnd() * 0.3)) : Math.round(p.oldPrice * (0.7 + rnd() * 0.25)); p.to = subtype === 'JOB_COUNT_INCREASE' ? p.from + p.n : Math.max(0, p.from - p.n); if (type === 'LEADERSHIP') { const person = pick(c._people); p.name = person.name; p.title = person.title; } const [oldV, newV] = ovFn(c, p); const surface = pick(surfaces); const sensor = c._sensors.find((s) => s.surface === surface) ?? c._sensors[0]; const change = sensor._changes.length ? pick(sensor._changes) : null; const origin = pick(['deterministic', 'deterministic', 'deterministic', 'llm', 'hybrid', 'backfill']); const confidence = r1(clamp(0.45 + rnd() * 0.55 - (origin === 'llm' ? 0.12 : 0), 0.3, 0.99)); const label = confidence >= 0.95 ? 'VERIFIED' : confidence >= 0.85 ? 'HIGH_CONFIDENCE' : confidence >= 0.7 ? 'LIKELY' : confidence >= 0.55 ? 'INFERRED' : 'LOW_CONFIDENCE'; const importance = r1(imLo + rnd() * (imHi - imLo)); const statusRoll = rnd(); const eid = id('evt'); const ev = { id: eid, company: { id: c.id, slug: c.slug, display_name: c.display_name, canonical_domain: c.canonical_domain, country: c.country, logo_url: null }, event_type: type, event_subtype: subtype, importance, confidence, confidence_label: label, title: titleFn(c, p), summary: summaryFn(c, p), old_value: oldV, new_value: newV, payload: { template: subtype, ...(type === 'HIRING' ? { count_before: p.from, count_after: p.to } : {}), ...(type === 'PRICING' ? { plan: p.plan, price_before: p.oldPrice, price_after: p.newPrice, currency: 'USD' } : {}) }, entities: type === 'LEADERSHIP' ? { person: p.name, title: p.title } : type === 'LOCATION' ? { city: p.city, country: p.country } : type === 'PRODUCT' ? { product: p.name } : {}, tags: [...new Set([type.toLowerCase(), surface, ...(p.ai > 4 && type === 'HIRING' ? ['ai'] : [])])], detected_at: iso(t), effective_at: chance(0.5) ? iso(t - ri(0, 3) * DAY) : null, published_at: type === 'COMMUNICATION' || type === 'M&A' ? iso(t - ri(5, 240) * 60_000) : null, source_url: sensor.url, surface, sensor_id: sensor.id, change_id: change ? change.id : null, cluster_id: chance(0.3) ? id('cls') : null, origin, model_name: origin === 'llm' || origin === 'hybrid' ? 'qwen3.6-35b-a3b-4bit' : null, prompt_version: origin === 'llm' || origin === 'hybrid' ? 'event-classifier/v3' : null, status: opts.live ? 'active' : statusRoll < 0.94 ? 'active' : statusRoll < 0.97 ? 'retracted' : statusRoll < 0.99 ? 'review' : 'duplicate', sources: [{ source_url: sensor.url, surface, detected_at: iso(t), kind: 'primary', sensor_id: sensor.id }], }; if (chance(0.4)) { const other = pick(c._sensors); ev.sources.push({ source_url: other.url, surface: other.surface, detected_at: iso(t + ri(2, 180) * 60_000), kind: 'corroboration', sensor_id: other.id }); } if (change) change._events.push(ev.id); sensor.event_count += 1; return ev; } for (const c of companies) { const n = c.tier === 1 ? ri(90, 260) : c.tier === 2 ? ri(40, 120) : c.tier === 3 ? ri(12, 50) : ri(3, 15); for (let i = 0; i < n; i++) { const t = NOW - Math.floor(Math.pow(rnd(), 1.6) * 365 * DAY) - ri(0, 3600_000); events.push(makeEvent(c, pick(EVENT_TEMPLATES), t)); } } // make sure the most recent hours are populated for the live feed for (let i = 0; i < 60; i++) { const c = pick(companies); events.push(makeEvent(c, pick(EVENT_TEMPLATES), NOW - ri(1, 360) * 60_000)); } events.sort((a, b) => (a.detected_at < b.detected_at ? 1 : -1)); for (const e of events) { eventsById.set(e.id, e); const c = companiesBySlug.get(e.company.slug); if (!perCompany.has(c.slug)) perCompany.set(c.slug, []); perCompany.get(c.slug).push(e); } for (const c of companies) { const list = perCompany.get(c.slug) ?? []; c.counts.events = list.filter((e) => e.status === 'active').length; c.last_event_at = list[0]?.detected_at ?? null; } // signals const SIGNAL_KINDS = [['hiring_surge', 'Hiring surge signal'], ['hiring_freeze', 'Hiring slowdown signal'], ['launch_buildup', 'Possible launch preparation signal'], ['international_expansion', 'International expansion signal'], ['pricing_migration', 'Pricing migration signal'], ['developer_push', 'Developer ecosystem push'], ['enterprise_repositioning', 'Enterprise repositioning signal'], ['ai_acceleration', 'AI acceleration signal']]; const signals = []; for (const c of companies) { for (let i = 0; i < ri(0, 3); i++) { const [kind, label] = pick(SIGNAL_KINDS); const s = { id: id('sig'), company_id: c.id, scope: 'company', scope_key: c.slug, kind, strength: r1(0.3 + rnd() * 0.7), confidence: r1(0.4 + rnd() * 0.5), title: `${label} — ${c.display_name}`, explanation: kind === 'launch_buildup' ? 'Documentation, careers and changelog surfaces changed together within 9 days; historically this pattern preceded a product listing in 4 of 7 monitored cases for this company. Presented as a signal, not a fact.' : kind === 'hiring_surge' ? `Open listings are ${ri(20, 80)} % above the 90-day baseline, concentrated in ${pick(DEPARTMENTS)}.` : 'Derived from per-company baselines of monitored surfaces.', evidence: { events: ri(2, 12), surfaces: ri(2, 5), window_days: 30 }, window_days: 30, detected_at: iso(NOW - ri(1, 20) * DAY), status: 'active' }; signals.push(s); c._signals.push(s); } } for (const [slug, ind] of Object.entries(IND).slice(0, 8)) signals.push({ id: id('sig'), company_id: null, scope: 'industry', scope_key: slug, kind: 'ai_acceleration', strength: r1(0.3 + rnd() * 0.6), confidence: r1(0.5 + rnd() * 0.4), title: `AI hiring acceleration in ${ind.name}`, explanation: 'Share of AI-tagged listings rose across monitored companies in this industry.', evidence: { companies: ri(3, 12) }, window_days: 30, detected_at: iso(NOW - ri(1, 10) * DAY), status: 'active' }); signals.push({ id: id('sig'), company_id: null, scope: 'global', scope_key: null, kind: 'pricing_migration', strength: 0.61, confidence: 0.72, title: 'SaaS pricing pages shifting to usage-based tiers', explanation: `${ri(8, 20)} monitored pricing pages added usage units in 30 days.`, evidence: { companies: 14 }, window_days: 30, detected_at: iso(NOW - 2 * DAY), status: 'active' }); // trends const trends = TREND_TERMS.map((term) => ({ term, mentions: ri(12, 480), companies: ri(3, 30), momentum: r1((rnd() - 0.3) * 120), series: Array.from({ length: 14 }, () => ri(0, 40)) })).sort((a, b) => b.momentum - a.momentum); // industries and countries function industryRow(slug) { const ind = IND[slug]; const cs = companies.filter((c) => c.industries.includes(slug)); const evs = cs.flatMap((c) => perCompany.get(c.slug) ?? []).filter((e) => e.status === 'active'); const avg = (k) => { const v = cs.map((c) => c.metrics[k]).filter((x) => typeof x === 'number'); return v.length ? r1(v.reduce((a, b) => a + b, 0) / v.length) : null; }; const byType = {}; for (const e of evs.filter((e) => e.detected_at > iso(NOW - 30 * DAY))) byType[e.event_type] = (byType[e.event_type] ?? 0) + 1; return { slug, name: ind.name, parent_slug: ind.parent_slug, companies: cs.length, events_7d: evs.filter((e) => e.detected_at > iso(NOW - 7 * DAY)).length, events_30d: evs.filter((e) => e.detected_at > iso(NOW - 30 * DAY)).length, hiring_momentum_30d: avg('hiring_momentum_30d'), activity_score: avg('activity_score'), ai_adoption: avg('ai_adoption'), top_event_types: Object.entries(byType).sort((a, b) => b[1] - a[1]).slice(0, 3).map((x) => x[0]), _companies: cs, _events: evs }; } function countryRow(code) { const [name, region, lat, lon] = COUNTRY_META[code]; const cs = companies.filter((c) => c.country === code); const evs = cs.flatMap((c) => perCompany.get(c.slug) ?? []).filter((e) => e.status === 'active'); const avg = (k) => { const v = cs.map((c) => c.metrics[k]).filter((x) => typeof x === 'number'); return v.length ? r1(v.reduce((a, b) => a + b, 0) / v.length) : null; }; const mix = {}; for (const c of cs) for (const i of c.industries) mix[i] = (mix[i] ?? 0) + 1; return { code, name, region, companies: cs.length, events_7d: evs.filter((e) => e.detected_at > iso(NOW - 7 * DAY)).length, events_30d: evs.filter((e) => e.detected_at > iso(NOW - 30 * DAY)).length, hiring_momentum_30d: avg('hiring_momentum_30d'), activity_score: avg('activity_score'), industry_mix: Object.entries(mix).map(([industry, companies]) => ({ industry, companies })).sort((a, b) => b.companies - a.companies), lat, lon, _companies: cs, _events: evs }; } const industryRows = () => Object.keys(IND).map(industryRow).filter((r) => r.companies > 0).sort((a, b) => b.events_30d - a.events_30d); const countryRows = () => Object.keys(COUNTRY_META).map(countryRow).filter((r) => r.companies > 0).sort((a, b) => b.events_30d - a.events_30d); // global daily history + index const history = []; { let idx = 100; for (let i = 364; i >= 0; i--) { const t = NOW - i * DAY; idx = clamp(idx + (rnd() - 0.48) * 3, 70, 150); const dayEvents = events.filter((e) => day(new Date(e.detected_at).getTime()) === day(t)); const byType = {}; for (const e of dayEvents) byType[e.event_type] = (byType[e.event_type] ?? 0) + 1; const growth = 1 - i / 600; history.push({ day: day(t), companies_active: Math.round(companies.length * growth), sensors_active: Math.round(sensors.size * growth), observations: Math.round((18000 + rnd() * 6000) * growth), changes: Math.round((900 + rnd() * 400) * growth), meaningful_changes: Math.round((260 + rnd() * 120) * growth), events: dayEvents.length, events_by_type: byType, jobs_open: Math.round(12000 * growth + rnd() * 800), jobs_new: ri(80, 400), jobs_removed: ri(60, 380), activity_index: r1(idx) }); } } function stats() { const obs = [...sensors.values()].reduce((a, s) => a + s.observation_count, 0); const first = Math.min(...companies.map((c) => c._created)); return { companies: companies.length, companies_active: companies.filter((c) => c.status === 'ACTIVE').length, sensors: sensors.size, sensors_active: [...sensors.values()].filter((s) => s.status === 'active').length, observations: obs + liveTicks * 37, snapshots: [...sensors.values()].reduce((a, s) => a + s.snapshot_count, 0), changes: changes.size + liveTicks * 3, meaningful_changes: [...changes.values()].filter((c) => c.significance >= 0.4).length + liveTicks, events: events.filter((e) => e.status === 'active').length, jobs_open: companies.reduce((a, c) => a + c.counts.jobs_open, 0), countries: new Set(companies.map((c) => c.country)).size, industries: new Set(companies.flatMap((c) => c.industries)).size, observations_today: 21560 + liveTicks * 37, changes_today: 1130 + liveTicks * 3, events_today: events.filter((e) => e.detected_at.slice(0, 10) === day(NOW) && e.status === 'active').length, dataset_started_at: iso(first), dataset_age_days: Math.round((NOW - first) / DAY), oldest_history_days: Math.round((NOW - first) / DAY), last_observation_at: iso(Date.now() - ri(3, 40) * 1000), archive: { objects: 1_284_310 + liveTicks * 30, bytes: 412_000_000_000 + liveTicks * 800_000 } }; } function mapBuckets(metric) { const buckets = new Map(); for (const c of companies) { const key = `${c.country}:${c.hq_city}`; if (!buckets.has(key)) buckets.set(key, { lat: c._lat, lon: c._lon, country: c.country, city: c.hq_city, companies: 0, events_30d: 0, jobs_open: 0, top: [] }); const b = buckets.get(key); b.companies += 1; b.events_30d += (perCompany.get(c.slug) ?? []).filter((e) => e.detected_at > iso(NOW - 30 * DAY)).length; b.jobs_open += c.counts.jobs_open; b.top.push({ slug: c.slug, display_name: c.display_name, importance: c.importance }); } for (const b of buckets.values()) b.top = b.top.sort((a, z) => z.importance - a.importance).slice(0, 3).map(({ slug, display_name }) => ({ slug, display_name })); return [...buckets.values()].sort((a, b) => b[metric] - a[metric]); } function rankings(kind, window, country, industry, limit) { let cs = companies.filter((c) => (!country || c.country === country.toUpperCase()) && (!industry || c.industries.includes(industry))); const wf = { '24h': 0.25, '7d': 0.6, '30d': 1, '90d': 1.3, '1y': 1.6 }[window] ?? 1; const val = (c) => { switch (kind) { case 'hiring_growth': return c.metrics.hiring_momentum_30d * wf; case 'hiring_decline': return c.metrics.hiring_momentum_30d * wf; case 'product_velocity': return c.metrics.product_velocity; case 'ai_active': return c.metrics.ai_adoption ?? -1; case 'geo_expansion': return c.metrics.geo_expansion; case 'developer_momentum': return c.metrics.developer_momentum ?? -1; case 'pricing_changes': return (perCompany.get(c.slug) ?? []).filter((e) => e.event_type === 'PRICING').length * wf; case 'unusual_activity': return c.metrics.anomaly_score; default: return c.metrics.activity_score; } }; cs = cs.filter((c) => val(c) >= 0); cs.sort((a, b) => (kind === 'hiring_decline' ? val(a) - val(b) : val(b) - val(a))); return cs.slice(0, limit).map((c, i) => ({ ...pub(c), rank: i + 1, value: r1(val(c)), delta: chance(0.8) ? r1((rnd() - 0.5) * 20) : null })); } const pub = (c) => { const { _lat, _lon, _created, _sensors, _jobs, _people, _products, _plans, _locations, _news, _series, _hir90, _signals, _aliases, _relationships, _facts, ...rest } = c; if (NO_PROFILE_KEY.has(c.slug)) delete rest.profile; // API builds that predate the profile field return rest; }; const pubSensor = (s) => { const { _versions, _changes, ...rest } = s; return rest; }; const pubChange = (c) => { const { _events, ...rest } = c; return rest; }; const pubSnap = (s) => { const { _blocks, _text, ...rest } = s; return rest; }; const ref = (c) => ({ id: c.id, slug: c.slug, display_name: c.display_name, canonical_domain: c.canonical_domain, country: c.country, logo_url: null }); // ------------------------------------------------------------------------------------------------ live stream let liveTicks = 0; const sseClients = new Set(); setInterval(() => { const c = pick(companies); const ev = makeEvent(c, pick(EVENT_TEMPLATES), Date.now() - ri(0, 2000), { live: true }); events.unshift(ev); eventsById.set(ev.id, ev); (perCompany.get(c.slug) ?? perCompany.set(c.slug, []).get(c.slug)).unshift(ev); c.counts.events += 1; c.last_event_at = ev.detected_at; liveTicks += 1; const frame = `event: event\nid: ${ev.id}\ndata: ${JSON.stringify(ev)}\n\n`; for (const res of sseClients) res.write(frame); }, 4000); setInterval(() => { for (const res of sseClients) res.write(`event: heartbeat\ndata: ${JSON.stringify({ at: new Date().toISOString(), clients: sseClients.size })}\n\n`); }, 20000); // ------------------------------------------------------------------------------------------------ owner / admin state const watchlists = new Map(); // token -> Set(slug) const alerts = new Map(); // token -> Alert[] const adminToken = process.env.CA_ADMIN_TOKEN ?? 'dev-admin-token'; // ------------------------------------------------------------------------------------------------ helpers function paginate(items, q, defaultPer = 25) { const page = Math.max(1, Number(q.get('page') ?? 1)); const per = clamp(Number(q.get('per_page') ?? defaultPer), 1, 200); const total = items.length; return { items: items.slice((page - 1) * per, page * per), page, per_page: per, total, pages: Math.max(1, Math.ceil(total / per)) }; } function filterEvents(list, q) { let out = list; const g = (k) => q.get(k); if (g('event_type')) out = out.filter((e) => e.event_type === g('event_type').toUpperCase()); if (g('event_subtype')) out = out.filter((e) => e.event_subtype === g('event_subtype').toUpperCase()); if (g('country')) out = out.filter((e) => (e.company.country ?? '').toUpperCase() === g('country').toUpperCase()); if (g('industry')) out = out.filter((e) => companiesBySlug.get(e.company.slug)?.industries.includes(g('industry'))); if (g('since')) out = out.filter((e) => e.detected_at > g('since')); if (g('until')) out = out.filter((e) => e.detected_at < g('until')); if (g('min_importance')) out = out.filter((e) => e.importance >= Number(g('min_importance'))); if (g('min_confidence')) out = out.filter((e) => e.confidence >= Number(g('min_confidence'))); if (g('surface')) out = out.filter((e) => e.surface === g('surface')); if (g('origin')) out = out.filter((e) => e.origin === g('origin')); if (g('company')) out = out.filter((e) => e.company.slug === g('company')); if (g('status')) out = out.filter((e) => e.status === g('status')); if (g('q')) { const s = g('q').toLowerCase(); out = out.filter((e) => e.title.toLowerCase().includes(s) || (e.summary ?? '').toLowerCase().includes(s) || e.company.display_name.toLowerCase().includes(s)); } if (g('sort') === 'importance') out = [...out].sort((a, b) => b.importance - a.importance); return out; } const TIMELINE_MAP = { products: ['PRODUCT'], jobs: ['HIRING'], pricing: ['PRICING'], leadership: ['LEADERSHIP'], locations: ['LOCATION'], legal: ['LEGAL'], news: ['COMMUNICATION', 'PARTNERSHIP', 'M&A', 'FINANCING', 'INVESTOR_RELATIONS'], developer: ['DEVELOPER', 'TECHNOLOGY'] }; function json(res, status, body, extra = {}) { const data = JSON.stringify(body); res.writeHead(status, { 'content-type': 'application/json; charset=utf-8', 'access-control-allow-origin': '*', 'access-control-allow-headers': 'content-type, x-ca-owner-token, x-ca-admin-token', 'access-control-allow-methods': 'GET,POST,DELETE,OPTIONS', 'x-api-version': 'mock-1', ...extra }); res.end(data); } const notFound = (res, what = 'not found') => json(res, 404, { detail: what }); function readBody(req) { return new Promise((resolve) => { let b = ''; req.on('data', (c) => (b += c)); req.on('end', () => { try { resolve(b ? JSON.parse(b) : {}); } catch { resolve({}); } }); }); } function csv(rows) { if (!rows.length) return ''; const keys = Object.keys(rows[0]).filter((k) => typeof rows[0][k] !== 'object' || rows[0][k] === null); const esc = (v) => (v === null || v === undefined ? '' : /[",\n]/.test(String(v)) ? `"${String(v).replace(/"/g, '""')}"` : String(v)); return [keys.join(','), ...rows.map((r) => keys.map((k) => esc(r[k])).join(','))].join('\n'); } // ------------------------------------------------------------------------------------------------ router const server = createServer(async (req, res) => { const url = new URL(req.url, `http://${req.headers.host ?? 'localhost'}`); const q = url.searchParams; let path = url.pathname.replace(/\/$/, '') || '/'; if (req.method === 'OPTIONS') return json(res, 204, {}); if (path === '/health' || path === '/ready' || path === '/api/v1/health' || path === '/api/v1/ready') return json(res, 200, { status: 'ok', service: 'company-atlas-mock', time: new Date().toISOString() }); if (!path.startsWith('/api/v1')) return notFound(res); path = path.slice('/api/v1'.length) || '/'; const seg = path.split('/').filter(Boolean); const owner = req.headers['x-ca-owner-token']; const admin = req.headers['x-ca-admin-token']; try { // ---- mock assets (sample logos; not part of the API contract) if (seg[0] === '_mock' && (seg[1] === 'logo' || seg[1] === 'icon') && seg[2]) { const slug = seg[2].replace(/\.svg$/, ''); if (!companiesBySlug.has(slug)) return notFound(res, 'logo not found'); res.writeHead(200, { 'content-type': 'image/svg+xml', 'cache-control': 'public, max-age=3600', 'access-control-allow-origin': '*' }); return res.end(logoSvg(slug, seg[1] === 'icon')); } // ---- platform if (path === '/stats') return json(res, 200, stats(), { 'cache-control': 'public, max-age=60' }); if (path === '/stats/history') return json(res, 200, { items: history.slice(-clamp(Number(q.get('days') ?? 90), 1, 365)) }); if (path === '/system') return json(res, 200, { sensors_online: [...sensors.values()].filter((s) => s.status === 'active').length, sensors_failing: [...sensors.values()].filter((s) => s.status === 'failing').length, observations_today: 21560 + liveTicks * 37, events_today: stats().events_today, countries_covered: new Set(companies.map((c) => c.country)).size, queue_lag_s: ri(2, 40), scheduler_last_tick_at: iso(Date.now() - ri(1, 20) * 1000), fetch_per_min: ri(280, 460), success_rate_24h: r1(96 + rnd() * 3.5) }); if (path === '/pulse') { const active = events.filter((e) => e.status === 'active'); const idxSeries = history.slice(-30).map((h) => ({ day: h.day, value: h.activity_index, confidence: 0.9 })); const last = idxSeries[idxSeries.length - 1].value; const wk = idxSeries[idxSeries.length - 8].value; return json(res, 200, { stats: stats(), live: active.slice(0, 12), movers: [...companies].sort((a, b) => b.metrics.corporate_change_index - a.metrics.corporate_change_index).slice(0, 10).map(pub), hiring: [...companies].sort((a, b) => b.metrics.hiring_momentum_30d - a.metrics.hiring_momentum_30d).slice(0, 8).map(pub), launches: active.filter((e) => e.event_subtype === 'PRODUCT_LAUNCH').slice(0, 8), pricing: active.filter((e) => e.event_type === 'PRICING').slice(0, 8), ai: [...companies].filter((c) => typeof c.metrics.ai_adoption === 'number').sort((a, b) => b.metrics.ai_adoption - a.metrics.ai_adoption).slice(0, 8).map(pub), industries: industryRows().slice(0, 12).map(({ _companies, _events, ...r }) => r), countries: countryRows().slice(0, 12).map(({ _companies, _events, ...r }) => r), trending: trends.slice(0, 10), activity_index: { value: last, delta_7d: r1(((last - wk) / wk) * 100), series: idxSeries }, map: mapBuckets('events_30d') }, { 'cache-control': 'public, max-age=60' }); } if (path === '/live') { const limit = clamp(Number(q.get('limit') ?? 50), 1, 500); let list = events.filter((e) => e.status === 'active'); list = filterEvents(list, q); return json(res, 200, { items: list.slice(0, limit) }, { 'cache-control': 'no-store' }); } if (path === '/live/stream') { res.writeHead(200, { 'content-type': 'text/event-stream', 'cache-control': 'no-store, no-transform', connection: 'keep-alive', 'access-control-allow-origin': '*', 'x-accel-buffering': 'no' }); res.write(`: connected\n\n`); const since = q.get('since'); if (since) for (const e of filterEvents(events.filter((e) => e.status === 'active' && e.detected_at > since), q).slice(0, 20).reverse()) res.write(`event: event\nid: ${e.id}\ndata: ${JSON.stringify(e)}\n\n`); sseClients.add(res); req.on('close', () => sseClients.delete(res)); return; } // ---- companies if (path === '/companies/compare') { const slugs = (q.get('companies') ?? '').split(',').map((s) => s.trim()).filter(Boolean).slice(0, 6); const cs = slugs.map((s) => companiesBySlug.get(s)).filter(Boolean); if (cs.length < 2) return json(res, 400, { detail: 'compare needs 2–6 known companies' }); const metrics = {}; for (const k of ['activity_score', 'hiring_momentum_30d', 'product_velocity', 'ai_adoption', 'geo_expansion', 'developer_momentum', 'corporate_change_index', 'open_jobs']) { metrics[k] = {}; for (const c of cs) if (typeof c.metrics[k] === 'number') metrics[k][c.slug] = c.metrics[k]; } const seriesOut = {}; const events_30d = {}; const jobs = {}; const locations = {}; for (const c of cs) { seriesOut[c.slug] = c._series.activity_score; const by = {}; for (const e of (perCompany.get(c.slug) ?? []).filter((e) => e.detected_at > iso(NOW - 30 * DAY) && e.status === 'active')) by[e.event_type] = (by[e.event_type] ?? 0) + 1; events_30d[c.slug] = by; jobs[c.slug] = { open: c.counts.jobs_open, ai_open: c._jobs.filter((j) => j.status === 'open' && j.is_ai).length, new_30d: c._jobs.filter((j) => j.first_seen_at > iso(NOW - 30 * DAY)).length }; locations[c.slug] = c._locations.filter((l) => l.status === 'listed').length; } return json(res, 200, { companies: cs.map(pub), metrics, series: seriesOut, events_30d, jobs, locations }); } if (path === '/companies') { let list = [...companies]; const g = (k) => q.get(k); if (g('q')) { const s = g('q').toLowerCase(); list = list.filter((c) => c.display_name.toLowerCase().includes(s) || c.canonical_domain.includes(s) || c._aliases.some((a) => a.toLowerCase().includes(s))); } if (g('country')) list = list.filter((c) => c.country === g('country').toUpperCase()); if (g('industry')) list = list.filter((c) => c.industries.includes(g('industry'))); if (g('tier')) list = list.filter((c) => String(c.tier) === g('tier')); if (g('public')) list = list.filter((c) => c.public_company === (g('public') === '1' || g('public') === 'true')); if (g('status')) list = list.filter((c) => c.status.toLowerCase() === g('status').toLowerCase()); if (g('has_events')) list = list.filter((c) => (c.counts.events > 0) === (g('has_events') === '1' || g('has_events') === 'true')); const sort = g('sort') ?? 'activity'; const cmp = { activity: (a, b) => b.metrics.activity_score - a.metrics.activity_score, events: (a, b) => b.counts.events - a.counts.events, hiring: (a, b) => b.metrics.hiring_momentum_30d - a.metrics.hiring_momentum_30d, name: (a, b) => a.display_name.localeCompare(b.display_name), importance: (a, b) => b.importance - a.importance, recent: (a, b) => (b.last_event_at ?? '').localeCompare(a.last_event_at ?? '') }[sort]; if (cmp) list.sort(cmp); const page = paginate(list, q); const spark = g('sparkline') === '1'; page.items = page.items.map((c) => { const p = pub(c); if (!spark) delete p.sparkline; return p; }); return json(res, 200, page); } if (seg[0] === 'companies' && seg[1]) { const c = companiesBySlug.get(decodeURIComponent(seg[1])); if (!c) return notFound(res, 'company not found'); const sub = seg[2]; const list = perCompany.get(c.slug) ?? []; if (!sub) { return json(res, 200, { ...pub(c), aliases: c._aliases, domains: [{ domain: c.canonical_domain, kind: 'canonical' }, { domain: `docs.${c.canonical_domain}`, kind: 'subdomain' }, { domain: `status.${c.canonical_domain}`, kind: 'subdomain' }], relationships: c._relationships, facts: c._facts, metrics_detail: Object.entries(c.metrics).map(([metric, value]) => ({ metric, value, confidence: r1(0.6 + rnd() * 0.35), computed_at: iso(NOW - ri(5, 120) * 60_000), formula_version: 'v1.0', inputs: { sensors: c.counts.sensors, events_30d: list.filter((e) => e.detected_at > iso(NOW - 30 * DAY)).length } })), sensors_by_surface: c._sensors.reduce((a, s) => ((a[s.surface] = (a[s.surface] ?? 0) + 1), a), {}), coverage: { historical_coverage: c.metrics.historical_coverage, first_observed_at: iso(c._created), days_observed: Math.round((NOW - c._created) / DAY), sensor_uptime: r1(90 + rnd() * 9.5) }, signals: c._signals, sparklines: { activity_30d: c.sparkline, hiring_90d: c._hir90 } }); } if (sub === 'events') return json(res, 200, paginate(filterEvents(list, q), q)); if (sub === 'timeline') { const f = q.get('filter') ?? 'all'; const limit = clamp(Number(q.get('limit') ?? 200), 1, 500); const types = TIMELINE_MAP[f]; const items = (types ? list.filter((e) => types.includes(e.event_type)) : list).slice(0, limit).map((e) => ({ ...e, day: e.detected_at.slice(0, 10) })); const days = {}; for (const e of items) days[e.day] = (days[e.day] ?? 0) + 1; return json(res, 200, { items, days: Object.entries(days).map(([day, count]) => ({ day, count })) }); } if (sub === 'metrics') { const days = clamp(Number(q.get('days') ?? 90), 7, 365); const s = {}; for (const [k, v] of Object.entries(c._series)) s[k] = v.slice(-days); return json(res, 200, { current: Object.entries(c.metrics).map(([metric, value]) => ({ metric, value, confidence: r1(0.6 + rnd() * 0.35), computed_at: iso(NOW - ri(5, 120) * 60_000), formula_version: 'v1.0', inputs: {} })), series: s }); } if (sub === 'jobs') { let jobs = [...c._jobs]; const st = q.get('status') ?? 'open'; if (st === 'open') jobs = jobs.filter((j) => j.status === 'open'); if (st === 'removed') jobs = jobs.filter((j) => j.status === 'no_longer_listed'); if (q.get('q')) jobs = jobs.filter((j) => j.title.toLowerCase().includes(q.get('q').toLowerCase())); if (q.get('country')) jobs = jobs.filter((j) => j.country === q.get('country').toUpperCase()); if (q.get('ai') === '1') jobs = jobs.filter((j) => j.is_ai); jobs.sort((a, b) => b.first_seen_at.localeCompare(a.first_seen_at)); const open = c._jobs.filter((j) => j.status === 'open'); const byC = {}; const byD = {}; for (const j of open) { byC[j.country] = (byC[j.country] ?? 0) + 1; byD[j.department] = (byD[j.department] ?? 0) + 1; } const page = paginate(jobs, q, 50); page.meta = { summary: { open: open.length, new_7d: c._jobs.filter((j) => j.first_seen_at > iso(NOW - 7 * DAY)).length, removed_7d: c._jobs.filter((j) => j.removed_at && j.removed_at > iso(NOW - 7 * DAY)).length, ai_open: open.filter((j) => j.is_ai).length, by_country: Object.entries(byC).map(([country, n]) => ({ country, n })).sort((a, b) => b.n - a.n), by_department: Object.entries(byD).map(([department, n]) => ({ department, n })).sort((a, b) => b.n - a.n), remote_ratio: open.length ? r1(open.filter((j) => j.remote).length / open.length) : null } }; return json(res, 200, page); } if (sub === 'people') return json(res, 200, { listed: c._people.filter((p) => p.status === 'listed'), no_longer_listed: c._people.filter((p) => p.status !== 'listed') }); if (sub === 'products') return json(res, 200, { listed: c._products.filter((p) => p.status === 'listed'), removed: c._products.filter((p) => p.status !== 'listed') }); if (sub === 'pricing') return json(res, 200, { current: c._plans.filter((p) => p.status === 'current'), history: c._plans.filter((p) => p.status !== 'current') }); if (sub === 'locations') return json(res, 200, { items: c._locations, countries: [...new Set(c._locations.filter((l) => l.status === 'listed').map((l) => l.country))] }); if (sub === 'news') return json(res, 200, { items: [...c._news].sort((a, b) => b.published_at.localeCompare(a.published_at)).slice(0, clamp(Number(q.get('limit') ?? 50), 1, 200)) }); if (sub === 'sensors') return json(res, 200, { items: c._sensors.map(pubSensor) }); if (sub === 'history') return json(res, 200, { sensors: c._sensors.filter((s) => s._versions.length).map((s) => ({ ...pubSensor(s), versions: [...s._versions].reverse().slice(0, 20).map(pubSnap) })) }); if (sub === 'similar') return json(res, 200, { items: companies.filter((o) => o !== c && (o.industries.some((i) => c.industries.includes(i)) || o.country === c.country)).sort((a, b) => Math.abs(a.importance - c.importance) - Math.abs(b.importance - c.importance)).slice(0, clamp(Number(q.get('limit') ?? 8), 1, 24)).map(pub) }); return notFound(res); } // ---- provenance if (seg[0] === 'sensors' && seg[1]) { const s = sensors.get(seg[1]); if (!s) return notFound(res, 'sensor not found'); const c = companies.find((x) => x.id === s.company_id); if (!seg[2]) return json(res, 200, { ...pubSensor(s), company: ref(c), latest_snapshot: s._versions.length ? pubSnap(s._versions[s._versions.length - 1]) : null }); if (seg[2] === 'snapshots') return json(res, 200, { items: [...s._versions].reverse().slice(0, clamp(Number(q.get('limit') ?? 50), 1, 200)).map(pubSnap) }); if (seg[2] === 'changes') return json(res, 200, { items: [...s._changes].reverse().slice(0, clamp(Number(q.get('limit') ?? 50), 1, 200)).map(pubChange) }); } if (seg[0] === 'snapshots' && seg[1]) { const s = snapshots.get(seg[1]); if (!s) return notFound(res, 'snapshot not found'); if (seg[2] === 'diff' && seg[3]) { const o = snapshots.get(seg[3]); if (!o) return notFound(res, 'snapshot not found'); const before = s.fetched_at < o.fetched_at ? s : o; const after = before === s ? o : s; const existing = [...changes.values()].find((c) => c.snapshot_before === before.id && c.snapshot_after === after.id); const diff = existing ? existing.diff : { added: after._blocks.slice(0, 2).map((b) => ({ key: b.key, kind: b.kind, path: b.path, before: null, after: b.text, weight: 0.5, similarity: null })), removed: before._blocks.slice(-1).map((b) => ({ key: b.key, kind: b.kind, path: b.path, before: b.text, after: null, weight: 0.5, similarity: null })), modified: before._blocks.slice(1, 3).map((b, i) => ({ key: b.key, kind: b.kind, path: b.path, before: b.text, after: after._blocks[i + 1]?.text ?? '', weight: 0.5, similarity: 0.6 })), moved: [], counts: { added: 2, removed: 1, modified: 2 }, text_delta_ratio: 0.18, similarity: 0.81, reasons: ['computed on demand between non-adjacent versions'] }; return json(res, 200, { before: pubSnap(before), after: pubSnap(after), diff }); } return json(res, 200, { ...pubSnap(s), text: s._text, blocks: s._blocks, extracted: s.extracted_summary }); } if (seg[0] === 'changes' && seg[1]) { const ch = changes.get(seg[1]); if (!ch) return notFound(res, 'change not found'); const c = companies.find((x) => x.id === ch.company_id); return json(res, 200, { ...pubChange(ch), events: ch._events.map((id) => eventsById.get(id)).filter(Boolean), company: ref(c) }); } // ---- events if (path === '/events/types') { const cutoff = iso(NOW - 30 * DAY); const byType = {}; for (const e of events.filter((e) => e.detected_at > cutoff && e.status === 'active')) { byType[e.event_type] ??= { event_type: e.event_type, count_30d: 0, subtypes: {} }; byType[e.event_type].count_30d += 1; byType[e.event_type].subtypes[e.event_subtype] = (byType[e.event_type].subtypes[e.event_subtype] ?? 0) + 1; } return json(res, 200, { types: Object.values(byType).map((t) => ({ ...t, subtypes: Object.entries(t.subtypes).map(([event_subtype, count_30d]) => ({ event_subtype, count_30d })) })).sort((a, b) => b.count_30d - a.count_30d) }); } if (path === '/events/summary') { const days = clamp(Number(q.get('days') ?? 7), 1, 365); const group = q.get('group') ?? 'type'; const cur = events.filter((e) => e.detected_at > iso(NOW - days * DAY) && e.status === 'active'); const prev = events.filter((e) => e.detected_at > iso(NOW - 2 * days * DAY) && e.detected_at <= iso(NOW - days * DAY) && e.status === 'active'); const keyOf = (e) => (group === 'country' ? e.company.country : group === 'industry' ? companiesBySlug.get(e.company.slug)?.industry_primary : e.event_type); const count = (list) => list.reduce((a, e) => ((a[keyOf(e)] = (a[keyOf(e)] ?? 0) + 1), a), {}); const a = count(cur); const b = count(prev); return json(res, 200, { items: Object.entries(a).map(([key, count]) => ({ key, count, delta_pct: b[key] ? r1(((count - b[key]) / b[key]) * 100) : null })).sort((x, y) => y.count - x.count) }); } if (path === '/events') return json(res, 200, paginate(filterEvents(events.filter((e) => q.get('status') ? true : e.status !== 'duplicate'), q), q)); if (seg[0] === 'events' && seg[1]) { const e = eventsById.get(seg[1]); if (!e) return notFound(res, 'event not found'); const ch = e.change_id ? changes.get(e.change_id) : null; return json(res, 200, { ...e, change: ch ? pubChange({ ...ch, diff: undefined, structured_delta: undefined }) : null }); } // ---- rankings, atlases if (path === '/rankings') return json(res, 200, { kind: q.get('kind') ?? 'most_active', window: q.get('window') ?? '30d', items: rankings(q.get('kind') ?? 'most_active', q.get('window') ?? '30d', q.get('country'), q.get('industry'), clamp(Number(q.get('limit') ?? 50), 1, 200)) }, { 'cache-control': 'public, max-age=60' }); if (path === '/industries') return json(res, 200, { items: industryRows().map(({ _companies, _events, ...r }) => r) }); if (seg[0] === 'industries' && seg[1]) { if (!IND[seg[1]]) return notFound(res, 'industry not found'); const r = industryRow(seg[1]); const cs = r._companies; const open = cs.reduce((a, c) => a + c.counts.jobs_open, 0); const { _companies, _events, ...row } = r; const cc = {}; for (const c of cs) cc[c.country] = (cc[c.country] ?? 0) + 1; return json(res, 200, { ...row, description: `Monitored companies classified under ${row.name}.`, companies: [...cs].sort((a, b) => b.metrics.activity_score - a.metrics.activity_score).slice(0, 24).map(pub), events: _events.slice(0, 20), hiring: { open, new_30d: ri(20, 400), removed_30d: ri(10, 300), momentum_30d: row.hiring_momentum_30d }, series: series(90, row.activity_score ?? 50, 6), countries: Object.entries(cc).map(([country, companies]) => ({ country, companies })).sort((a, b) => b.companies - a.companies), trending: trends.slice(0, 8) }); } if (path === '/countries') return json(res, 200, { items: countryRows().map(({ _companies, _events, ...r }) => r) }); if (seg[0] === 'countries' && seg[1]) { const code = seg[1].toUpperCase(); if (!COUNTRY_META[code]) return notFound(res, 'country not found'); const r = countryRow(code); const { _companies, _events, ...row } = r; const cs = r._companies; return json(res, 200, { ...row, companies: [...cs].sort((a, b) => b.metrics.activity_score - a.metrics.activity_score).slice(0, 24).map(pub), events: _events.slice(0, 20), movers: [...cs].sort((a, b) => b.metrics.corporate_change_index - a.metrics.corporate_change_index).slice(0, 10).map(pub), new_entrants: [...cs].sort((a, b) => b._created - a._created).slice(0, 10).map(pub), series: series(90, row.activity_score ?? 50, 6), industries: industryRows().filter((i) => cs.some((c) => c.industries.includes(i.slug))).map(({ _companies, _events, ...x }) => x) }); } if (path === '/signals') { let list = signals; if (q.get('kind')) list = list.filter((s) => s.kind === q.get('kind')); if (q.get('scope')) list = list.filter((s) => s.scope === q.get('scope')); return json(res, 200, { items: list.slice(0, clamp(Number(q.get('limit') ?? 50), 1, 200)) }); } if (path === '/trends') return json(res, 200, { items: trends.slice(0, clamp(Number(q.get('limit') ?? 30), 1, 100)) }); if (path === '/map') return json(res, 200, { buckets: mapBuckets(q.get('metric') === 'companies' ? 'companies' : q.get('metric') === 'hiring' ? 'jobs_open' : 'events_30d') }); if (path === '/index') { const s = history.map((h) => ({ day: h.day, value: h.activity_index, confidence: 0.9 })); const last = s[s.length - 1].value; const byType = {}; for (const e of events.filter((e) => e.detected_at > iso(NOW - 30 * DAY))) byType[e.event_type] = (byType[e.event_type] ?? 0) + 1; return json(res, 200, { value: last, baseline: 100, delta_7d: r1(((last - s[s.length - 8].value) / s[s.length - 8].value) * 100), delta_30d: r1(((last - s[s.length - 31].value) / s[s.length - 31].value) * 100), series: s, by_type: byType, by_country: countryRows().slice(0, 12).map((c) => ({ key: c.code, value: r1(80 + rnd() * 60) })), by_industry: industryRows().slice(0, 12).map((i) => ({ key: i.slug, value: r1(80 + rnd() * 60) })), formula_version: 'gcai-v1.0' }); } // ---- search if (path === '/search/suggest') { const s = (q.get('q') ?? '').toLowerCase().trim(); const items = []; if (s) { for (const c of companies) if (c.display_name.toLowerCase().includes(s) || c.canonical_domain.includes(s)) items.push({ kind: 'company', label: c.display_name, sublabel: `${c.canonical_domain} · ${c.country}`, href: `/company/${c.slug}` }); for (const i of Object.values(IND)) if (i.name.toLowerCase().includes(s)) items.push({ kind: 'industry', label: i.name, sublabel: 'Industry', href: `/industry/${i.slug}` }); for (const [code, [name]] of Object.entries(COUNTRY_META)) if (name.toLowerCase().includes(s) || code.toLowerCase() === s) items.push({ kind: 'country', label: name, sublabel: code, href: `/country/${code.toLowerCase()}` }); for (const t of [...new Set(EVENT_TEMPLATES.map((t) => t[0]))]) if (t.toLowerCase().includes(s)) items.push({ kind: 'event_type', label: t, sublabel: 'Event type', href: `/events?event_type=${encodeURIComponent(t)}` }); } return json(res, 200, { items: items.slice(0, 10) }, { 'cache-control': 'no-store' }); } if (path === '/search') { const s = (q.get('q') ?? '').toLowerCase().trim(); const t0 = performance.now(); const limit = clamp(Number(q.get('limit') ?? 10), 1, 50); const words = s.split(/\s+/).filter(Boolean); const hit = (txt) => words.some((w) => txt.toLowerCase().includes(w)); const cs = companies.filter((c) => hit(c.display_name) || hit(c.canonical_domain) || c.industries.some((i) => hit(IND[i].name)) || hit(COUNTRY_META[c.country][0])); return json(res, 200, { query: q.get('q') ?? '', companies: cs.slice(0, limit).map(pub), events: events.filter((e) => e.status === 'active' && (hit(e.title) || hit(e.summary ?? ''))).slice(0, limit), industries: Object.keys(IND).filter((k) => hit(IND[k].name)).map(industryRow).map(({ _companies, _events, ...r }) => r), countries: Object.keys(COUNTRY_META).filter((k) => hit(COUNTRY_META[k][0])).map(countryRow).map(({ _companies, _events, ...r }) => r), people: companies.flatMap((c) => c._people.filter((p) => hit(p.name) || hit(p.title ?? '')).map((p) => ({ ...p, company: ref(c) }))).slice(0, limit), products: companies.flatMap((c) => c._products.filter((p) => hit(p.name)).map((p) => ({ ...p, company: ref(c) }))).slice(0, limit), took_ms: Math.round(performance.now() - t0) }, { 'cache-control': 'no-store' }); } if (path === '/ask') { const s = (q.get('q') ?? '').toLowerCase(); const filters = {}; for (const [code, [name]] of Object.entries(COUNTRY_META)) if (s.includes(name.toLowerCase())) filters.country = code; for (const i of Object.values(IND)) if (s.includes(i.name.toLowerCase())) filters.industry = i.slug; if (/\bai\b|machine learning|llm/.test(s)) filters.ai = true; if (/hiring|jobs|engineer/.test(s)) filters.event_type = 'HIRING'; if (/pric/.test(s)) filters.event_type = 'PRICING'; if (/office|expan|countr/.test(s)) filters.event_type = 'LOCATION'; if (/launch|product/.test(s)) filters.event_type = 'PRODUCT'; if (/leader|exec|ceo|cto/.test(s)) filters.event_type = 'LEADERSHIP'; let cs = companies.filter((c) => (!filters.country || c.country === filters.country) && (!filters.industry || c.industries.includes(filters.industry))); if (filters.ai) cs = cs.filter((c) => (c.metrics.ai_adoption ?? 0) > 40 || c._jobs.some((j) => j.is_ai && j.status === 'open')); cs.sort((a, b) => b.metrics.activity_score - a.metrics.activity_score); let evs = events.filter((e) => e.status === 'active' && (!filters.event_type || e.event_type === filters.event_type) && (!filters.country || e.company.country === filters.country) && (!filters.industry || companiesBySlug.get(e.company.slug)?.industries.includes(filters.industry))); const answer = cs.length ? `${cs.length} monitored ${cs.length === 1 ? 'company matches' : 'companies match'} this question${filters.country ? ` in ${COUNTRY_META[filters.country][0]}` : ''}${filters.industry ? ` (${IND[filters.industry].name})` : ''}. ${evs.length ? `${Math.min(evs.length, 200)} related structured events were detected in the monitored record; the most recent are listed below with their sources.` : 'No related structured events were detected yet.'} This is a routed structured query over observed public pages, not an opinion.` : 'No monitored company matches this question yet. Try a broader industry or country, or search company names directly.'; return json(res, 200, { interpretation: filters, answer, companies: cs.slice(0, 10).map(pub), events: evs.slice(0, 10), sources: evs.slice(0, 10).map((e) => e.source_url).filter(Boolean) }, { 'cache-control': 'no-store' }); } // ---- watchlist & alerts if (path.startsWith('/watchlist') || path.startsWith('/alerts')) { if (!owner || String(owner).length < 24) return json(res, 401, { detail: 'X-CA-Owner-Token required (≥ 24 chars)' }); const key = String(owner); if (!watchlists.has(key)) watchlists.set(key, new Set()); if (!alerts.has(key)) alerts.set(key, []); const wl = watchlists.get(key); if (path === '/watchlist' && req.method === 'GET') { const cs = [...wl].map((s) => companiesBySlug.get(s)).filter(Boolean); const evs = events.filter((e) => e.status === 'active' && wl.has(e.company.slug)).slice(0, 30); return json(res, 200, { items: cs.map(pub), events: evs }, { 'cache-control': 'no-store' }); } if (path === '/watchlist' && req.method === 'POST') { const body = await readBody(req); const c = companiesBySlug.get(body.company); if (!c) return notFound(res, 'company not found'); wl.add(c.slug); return json(res, 201, { ok: true, company: c.slug, items: wl.size }); } if (seg[0] === 'watchlist' && seg[1] && req.method === 'DELETE') { wl.delete(decodeURIComponent(seg[1])); return json(res, 200, { ok: true, items: wl.size }); } const al = alerts.get(key); if (path === '/alerts' && req.method === 'GET') return json(res, 200, { items: al }, { 'cache-control': 'no-store' }); if (path === '/alerts' && req.method === 'POST') { const body = await readBody(req); if (!body.name) return json(res, 422, { detail: 'name required' }); const a = { id: id('alr'), name: body.name, company: body.company ?? null, condition: body.condition ?? {}, channel: body.channel === 'webhook' ? 'webhook' : 'web', target: body.target ?? null, created_at: new Date().toISOString(), status: 'active' }; al.push(a); return json(res, 201, a); } if (path === '/alerts/deliveries') { const items = al.slice(0, 5).flatMap((a) => events.filter((e) => e.status === 'active' && (!a.company || e.company.slug === a.company) && (!a.condition.event_types?.length || a.condition.event_types.includes(e.event_type))).slice(0, 4).map((e) => ({ id: id('dlv'), alert_id: a.id, alert_name: a.name, event_id: e.id, event: e, channel: a.channel, status: 'delivered', delivered_at: e.detected_at }))); return json(res, 200, { items: items.slice(0, clamp(Number(q.get('limit') ?? 50), 1, 200)) }, { 'cache-control': 'no-store' }); } if (seg[0] === 'alerts' && seg[1] && req.method === 'DELETE') { alerts.set(key, al.filter((a) => a.id !== seg[1])); return json(res, 200, { ok: true }); } } // ---- exports & docs if (seg[0] === 'export') { const [name, fmt] = (seg[1] ?? '').split('.'); let rows = []; if (name === 'events') rows = filterEvents(events.filter((e) => e.status === 'active'), q).slice(0, clamp(Number(q.get('limit') ?? 10000), 1, 10000)).map(({ sources, payload, entities, company, ...e }) => ({ ...e, company_slug: company.slug, company: company.display_name, tags: e.tags.join('|') })); else if (name === 'companies') rows = companies.filter((c) => (!q.get('country') || c.country === q.get('country').toUpperCase()) && (!q.get('industry') || c.industries.includes(q.get('industry')))).map((c) => ({ ...pub(c), industries: c.industries.join('|'), metrics: undefined, counts: undefined, sparkline: undefined, activity_score: c.metrics.activity_score, sensors: c.counts.sensors, events: c.counts.events })); else if (name === 'jobs') rows = companies.filter((c) => !q.get('company') || c.slug === q.get('company')).flatMap((c) => c._jobs.map((j) => ({ ...j, company: c.slug }))); else return notFound(res); if (fmt === 'csv') { res.writeHead(200, { 'content-type': 'text/csv; charset=utf-8', 'content-disposition': `attachment; filename="${name}.csv"` }); return res.end(csv(rows)); } if (fmt === 'ndjson') { res.writeHead(200, { 'content-type': 'application/x-ndjson' }); return res.end(rows.map((r) => JSON.stringify(r)).join('\n')); } return json(res, 200, { items: rows }); } if (path === '/sitemap') { const kind = q.get('kind') ?? 'companies'; const page = Number(q.get('page') ?? 0); const items = kind === 'companies' ? companies.filter((c) => c.counts.events > 2).map((c) => ({ slug: c.slug, updated_at: c.last_event_at })) : kind === 'industries' ? industryRows().map((i) => ({ slug: i.slug, updated_at: null })) : countryRows().map((c) => ({ slug: c.code.toLowerCase(), updated_at: null })); const per = 5000; return json(res, 200, { items: items.slice(page * per, (page + 1) * per), pages: Math.max(1, Math.ceil(items.length / per)) }); } if (path === '/methodology') { return json(res, 200, { metrics: [ { metric: 'activity_score', formula_version: 'v1.0', description: 'Coverage-normalised rate of meaningful changes and structured events across a company’s monitored surfaces over 30 days, weighted by surface importance, scaled 0–100 against the population baseline.', inputs: ['meaningful_changes_30d', 'events_30d', 'surface_weights', 'sensors_active', 'population_baseline'] }, { metric: 'hiring_momentum_30d', formula_version: 'v1.0', description: 'Percentage change in publicly listed open roles over 30 days, adjusted for listings that disappeared and re-appeared within 48 h.', inputs: ['jobs_open_t0', 'jobs_open_t1', 'jobs_new', 'jobs_removed'] }, { metric: 'product_velocity', formula_version: 'v1.0', description: 'Rate of product, documentation, changelog and API events per 90 days, normalised by the number of product-related sensors.', inputs: ['product_events_90d', 'developer_events_90d', 'sensors_product'] }, { metric: 'ai_adoption', formula_version: 'v1.1', description: 'Observable public AI signals only: AI-tagged listings share, AI product pages, AI mentions in documentation and first-party communications. Never claims internal usage.', inputs: ['ai_jobs_share', 'ai_products', 'ai_docs_mentions', 'ai_news_mentions'] }, { metric: 'geo_expansion', formula_version: 'v1.0', description: 'New countries and cities appearing on locations and careers surfaces over 90 days.', inputs: ['new_countries_90d', 'new_cities_90d', 'jobs_new_countries'] }, { metric: 'developer_momentum', formula_version: 'v1.0', description: 'Documentation, changelog and API surface change rate; public repository activity where available.', inputs: ['docs_changes_90d', 'changelog_entries_90d', 'api_events_90d'] }, { metric: 'corporate_change_index', formula_version: 'v1.0', description: '0.25 hiring + 0.20 product + 0.15 geographic + 0.15 leadership + 0.10 developer + 0.10 communication + 0.05 pricing; weights are provisional.', inputs: ['hiring_momentum_30d', 'product_velocity', 'geo_expansion', 'leadership_activity', 'developer_momentum', 'communication_activity', 'pricing_activity'] }, { metric: 'anomaly_score', formula_version: 'v1.0', description: 'Deviation of the last 7 days from the company’s own 90-day baseline of changes and events (z-score mapped to 0–100).', inputs: ['baseline_changes_per_week', 'changes_7d', 'events_7d'] }, { metric: 'historical_coverage', formula_version: 'v1.0', description: 'Historical Completeness Score: share of days since onboarding with at least one successful observation per active surface, penalised for failed periods.', inputs: ['days_observed', 'days_since_onboarding', 'sensor_uptime', 'failed_periods'] }, ], significance_bands: [ { label: 'noise', min: 0, max: 0.2 }, { label: 'minor', min: 0.2, max: 0.4 }, { label: 'meaningful', min: 0.4, max: 0.65 }, { label: 'major', min: 0.65, max: 0.85 }, { label: 'critical', min: 0.85, max: 1 }, ], event_types: [...new Set(EVENT_TEMPLATES.map((t) => t[0]))], confidence_labels: { VERIFIED: 'Confirmed by two independent first-party surfaces or a structured feed.', HIGH_CONFIDENCE: 'Deterministic extraction from a structured surface, single source.', LIKELY: 'Deterministic extraction from unstructured HTML with a stable block identity.', INFERRED: 'Interpretation produced by an enrichment model from a deterministic change.', LOW_CONFIDENCE: 'Weak or partially corroborated signal; kept for transparency.' }, }); } // ---- admin if (seg[0] === 'admin') { if (!admin || String(admin) !== adminToken) return json(res, 401, { detail: 'invalid admin token' }); const sub = seg[1]; if (sub === 'overview') { const byS = {}; const byT = {}; for (const s of sensors.values()) { byS[s.status] = (byS[s.status] ?? 0) + 1; byT[s.tier] = (byT[s.tier] ?? 0) + 1; } const failures = {}; for (const f of FAILURE_CLASSES) failures[f] = ri(0, 60); return json(res, 200, { companies_by_status: { ACTIVE: companies.filter((c) => c.status === 'ACTIVE').length, POSSIBLY_INACTIVE: companies.filter((c) => c.status !== 'ACTIVE').length }, sensors_by_status: byS, sensors_by_tier: byT, queue: { pending: ri(120, 900), running: ri(8, 32), dead: ri(0, 14), oldest_pending_s: ri(5, 600) }, llm: { pending: ri(0, 40), done_today: ri(80, 400), failed_today: ri(0, 6), budget_left: r1(rnd() * 100) }, failures_24h_by_class: failures, fetch_rate_1h: ri(15000, 26000), change_rate_1h: ri(600, 1400), meaningful_rate_1h: ri(120, 400), storage: stats().archive, workers: ['M2U64-w1', 'M2U64-w2', 'M2U64-w3', 'M2U64-browser'].map((name) => ({ name, last_seen_at: iso(Date.now() - ri(1, 60) * 1000), inflight: ri(0, 8) })), cost_today: { fetch: r1(rnd() * 3), browser: r1(rnd() * 2), llm: r1(rnd() * 6) } }); } if (sub === 'connectors') return json(res, 200, { items: CONNECTORS.map(([cid, name, version, category]) => ({ id: cid, name, version, category, enabled: cid !== 'lever_connector', sensors_active: [...sensors.values()].filter((s) => s.connector_id === cid && s.status === 'active').length, sensors_failing: [...sensors.values()].filter((s) => s.connector_id === cid && s.status === 'failing').length, success_rate_24h: r1(90 + rnd() * 10), avg_latency_ms: ri(200, 2400), change_rate_24h: r1(rnd() * 12), errors_24h: ri(0, 40), last_run_at: iso(Date.now() - ri(1, 400) * 1000) })) }); if (sub === 'sensors' && !seg[2]) { let list = [...sensors.values()]; const g = (k) => q.get(k); if (g('status')) list = list.filter((s) => s.status === g('status')); if (g('domain')) list = list.filter((s) => s.domain.includes(g('domain'))); if (g('connector')) list = list.filter((s) => s.connector_id === g('connector')); if (g('company')) list = list.filter((s) => companies.find((c) => c.id === s.company_id)?.slug === g('company')); const f = g('filter'); if (f === 'healthy') list = list.filter((s) => s.status === 'active' && s.consecutive_failures === 0); if (f === 'failing') list = list.filter((s) => s.status === 'failing'); if (f === 'stale') list = list.filter((s) => new Date(s.last_success_at).getTime() < NOW - 2 * DAY); if (f === 'blocked') list = list.filter((s) => s.last_failure_class === 'BOT_CHALLENGE' || s.last_status === 403); if (f === 'redirected') list = list.filter((s) => s.last_failure_class === 'REDIRECT'); if (f === 'low_quality') list = list.filter((s) => s.quality_score < 55); if (f === 'high_activity') list = list.filter((s) => s.change_count > 8); const page = paginate(list, q, 50); page.items = page.items.map((s) => ({ ...pubSensor(s), company: ref(companies.find((c) => c.id === s.company_id)) })); return json(res, 200, page); } if (sub === 'sensors' && seg[2] && seg[3] && req.method === 'POST') { const s = sensors.get(seg[2]); if (!s) return notFound(res, 'sensor not found'); const body = await readBody(req); const action = seg[3]; if (action === 'pause') s.status = 'paused'; if (action === 'resume') s.status = 'active'; if (action === 'retire') s.status = 'retired'; if (action === 'retry' || action === 'run_now') { s.status = 'active'; s.consecutive_failures = 0; s.next_run_at = new Date().toISOString(); } if (action === 'set_interval' && body.interval_s) s.current_interval_s = Number(body.interval_s); if (action === 'set_connector' && body.connector_id) s.connector_id = body.connector_id; return json(res, 200, { ok: true, sensor: pubSensor(s), action }); } if (sub === 'companies' && !seg[2]) { if (req.method === 'POST') { const body = await readBody(req); if (!body.website) return json(res, 422, { detail: 'website required' }); const domain = String(body.website).replace(/^https?:\/\//, '').replace(/\/.*$/, ''); const c = buildCompany([body.display_name || domain.split('.')[0], domain, (body.country || 'US').toUpperCase(), 'Unknown', 0, 0, body.industries?.length ? body.industries : ['technology'], false, null, null, null, null, 30, null], companies.length); c.onboarding_status = 'pending'; return json(res, 201, pub(c)); } let list = [...companies]; if (q.get('onboarding_status')) list = list.filter((c) => c.onboarding_status === q.get('onboarding_status')); const page = paginate(list, q, 50); page.items = page.items.map(pub); return json(res, 200, page); } if (sub === 'companies' && seg[2] && seg[3] === 'rediscover') return json(res, 200, { ok: true, queued: true }); if (sub === 'failures') { const items = Array.from({ length: 120 }, () => { const s = pick([...sensors.values()]); return { id: id('fail'), sensor_id: s.id, company: ref(companies.find((c) => c.id === s.company_id)), domain: s.domain, failure_class: pick(FAILURE_CLASSES), status_code: pick([0, 403, 404, 429, 500, 503]), message: pick(['connect timeout after 20 s', 'challenge page detected (cf-mitigated)', 'schema validation failed: jobs[3].title missing', 'redirected to /careers-new (301)', 'rate limited by domain governor', 'dns: NXDOMAIN']), occurred_at: iso(Date.now() - ri(1, 1440) * 60_000), retry_at: iso(Date.now() + ri(5, 600) * 60_000) }; }).sort((a, b) => b.occurred_at.localeCompare(a.occurred_at)); return json(res, 200, paginate(q.get('class') ? items.filter((i) => i.failure_class === q.get('class')) : items, q, 50)); } if (sub === 'queue' && !seg[2]) { const items = Array.from({ length: 80 }, () => ({ id: id('job'), kind: pick(['fetch', 'fetch', 'fetch', 'discover', 'enrich', 'metrics', 'daily']), status: pick(['pending', 'pending', 'running', 'done', 'dead']), priority: ri(1, 100), attempts: ri(0, 4), scheduled_at: iso(Date.now() - ri(0, 3600) * 1000), started_at: chance(0.5) ? iso(Date.now() - ri(0, 600) * 1000) : null, finished_at: null, worker: chance(0.5) ? pick(['M2U64-w1', 'M2U64-w2', 'M2U64-w3']) : null, ref: pick([...sensors.keys()]), error: chance(0.1) ? 'TIMEOUT' : null })); const filtered = items.filter((i) => (!q.get('kind') || i.kind === q.get('kind')) && (!q.get('status') || i.status === q.get('status'))); const counts = {}; for (const i of items) counts[i.status] = (counts[i.status] ?? 0) + 1; return json(res, 200, { items: filtered, counts }); } if (sub === 'queue' && seg[2] === 'requeue-dead') return json(res, 200, { ok: true, requeued: ri(0, 14) }); if (sub === 'llm') { const items = Array.from({ length: 60 }, () => ({ id: id('llm'), kind: pick(['classify', 'summarize', 'extract_event', 'industry_tag']), status: pick(['done', 'done', 'done', 'pending', 'failed']), model: pick(['qwen3-4b-instruct-2507-4bit', 'qwen3.6-35b-a3b-4bit']), prompt_version: pick(['event-classifier/v3', 'event-summary/v2']), change_id: pick([...changes.keys()]), event_id: chance(0.7) ? pick(events).id : null, tokens_in: ri(400, 6000), tokens_out: ri(50, 600), cost_estimate: r1(rnd() * 0.02 * 100) / 100, created_at: iso(Date.now() - ri(0, 1440) * 60_000), finished_at: chance(0.8) ? iso(Date.now() - ri(0, 1000) * 60_000) : null, error: chance(0.1) ? 'schema validation failed' : null })); return json(res, 200, paginate(q.get('status') ? items.filter((i) => i.status === q.get('status')) : items, q, 50)); } if (sub === 'reviews' && !seg[2]) { const items = Array.from({ length: 24 }, () => { const e = pick(events); return { id: id('rev'), kind: pick(['major_event', 'low_confidence_extraction', 'company_merge', 'sensor_migration', 'legal_sensitive']), status: chance(0.8) ? 'open' : 'resolved', subject: e.title, ref_id: e.id, company: e.company, reason: pick(['importance ≥ 0.9', 'confidence < 0.55', 'two companies share a domain', 'URL moved; content identity uncertain', 'mentions litigation']), created_at: iso(Date.now() - ri(1, 5000) * 60_000), resolved_at: null, resolution: null }; }); return json(res, 200, { items: q.get('status') ? items.filter((i) => i.status === q.get('status')) : items }); } if (sub === 'reviews' && seg[2] && req.method === 'POST') return json(res, 200, { ok: true, id: seg[2], ...(await readBody(req)) }); if (sub === 'events' && seg[2] && seg[3] && req.method === 'POST') { const e = eventsById.get(seg[2]); if (!e) return notFound(res, 'event not found'); e.status = seg[3] === 'retract' ? 'retracted' : 'active'; return json(res, 200, { ok: true, status: e.status }); } if (sub === 'quality') return json(res, 200, { coverage: { companies_active_pct: r1(92 + rnd() * 6), sensors_active_pct: r1(84 + rnd() * 8) }, freshness: { sensors_checked_24h_pct: r1(88 + rnd() * 10), stale: ri(20, 140) }, duplicate_rate: r1(rnd() * 4), event_confidence_avg: r1(0.7 + rnd() * 0.2), unknown_surfaces: ri(30, 200), failed_sensors: [...sensors.values()].filter((s) => s.status === 'failing').length, calibration: { correct: ri(300, 600), duplicate: ri(5, 40), noise: ri(10, 60), misclassified: ri(3, 30) } }); if (sub === 'costs') { const days = clamp(Number(q.get('days') ?? 30), 1, 90); const items = []; for (let i = days - 1; i >= 0; i--) for (const [dimension, key] of [['fetch', 'http'], ['fetch', 'browser'], ['llm', 'qwen3.6-35b'], ['storage', 'objects']]) items.push({ day: day(NOW - i * DAY), dimension, key, units: ri(1000, 30000), cost_estimate: r1(rnd() * 8 * 100) / 100 }); return json(res, 200, { items, per_1000_companies: r1(rnd() * 40 + 10), per_million_observations: r1(rnd() * 6 + 1), per_meaningful_event: r1(rnd() * 0.05 * 1000) / 1000 }); } if (sub === 'cache' && seg[2] === 'clear') return json(res, 200, { ok: true, cleared: ri(4, 40) }); } return notFound(res); } catch (e) { console.error(e); return json(res, 500, { detail: `mock error: ${e.message}` }); } }); server.listen(PORT, '127.0.0.1', () => { console.log(`Company Atlas mock API on http://127.0.0.1:${PORT}/api/v1 — ${companies.length} companies, ${sensors.size} sensors, ${events.length} events, ${changes.size} changes. Admin token: ${adminToken}`); });