// Sample data, realistic internal-app figures at a ~500-person co.

const OPERATORS = {
  ml: { id: "ml", name: "Maya Lindqvist",   initials: "ML", team: "Revenue Ops",        color: "#FFB98A" },
  rp: { id: "rp", name: "Rohan Patel",      initials: "RP", team: "Finance",            color: "#B4D0B0" },
  sj: { id: "sj", name: "Sam Jefferson",    initials: "SJ", team: "Customer Success",   color: "#D9C7E8" },
  ps: { id: "ps", name: "Priya Shah",       initials: "PS", team: "Customer Success",   color: "#C8B8E0" },
  tt: { id: "tt", name: "Thalia Torres",    initials: "TT", team: "Marketing",          color: "#F4C9B0" },
  ay: { id: "ay", name: "Ayaan Younis",     initials: "AY", team: "People Ops",         color: "#C7D9E8" },
  nc: { id: "nc", name: "Nora Chen",        initials: "NC", team: "Supply Chain",       color: "#E8D9C7" },
  dk: { id: "dk", name: "Diego Kovač",      initials: "DK", team: "Legal",              color: "#D0B0B4" },
};

const ME_OPERATOR = OPERATORS.ml;
const ME_CTO = { id: "cto", name: "Priya Rangarajan", initials: "PR", role: "CTO", company: "Meridia" };

// Realistic internal-app usage at a ~500-person company.
// DAU < WAU < unique-30d. PTO Bot hits most of the company; specialized tools hit their team only.
const APPS = [
  { id: "quote-copilot",       name: "Quote Copilot",       owner: "ml", team: "Revenue Ops",
    audit: 92, cost: 1840, costBreakdown: { compute: 320, apis: 520, llm: 1000 },
    dau: 22, wau: 54, uniqueMau: 86, monthlyUsers: 24, creators: 4, dauTrend: "+18% 30d",
    tests: { total: 38, passing: 37, failing: ["quote totals match Salesforce (operator-authored)"] }, depsAge: 4, deploys7d: 12, lastDeploy: "2h ago",
    env: "prod+staging", stack: ["Next.js 14", "Vercel AI SDK", "Postgres", "Stripe"], generator: "Claude Code",
    flags: ["stuck-in-staging"],
    stagedVersion: "v124", prodVersion: "v123", stagingHeldReason: "Test failed: quote totals match Salesforce · also Salesforce REST blocked by org posture",
    connections: [
      { type: "db",   name: "deals.postgres",      det: true },
      { type: "db",   name: "quotes.postgres",     det: true },
      { type: "saas", name: "Salesforce REST",     det: true },
      { type: "saas", name: "Stripe",              det: true },
      { type: "llm",  name: "Anthropic · Sonnet",  det: false },
      { type: "saas", name: "DocuSign",            det: true },
    ]},
  { id: "churn-early-warning", name: "Churn Early Warning", owner: "sj", team: "Customer Success",
    audit: 78, cost: 820, costBreakdown: { compute: 140, apis: 320, llm: 360 },
    dau: 8, wau: 18, uniqueMau: 26, monthlyUsers: 11, creators: 2, dauTrend: "+6% 30d",
    tests: { total: 14, passing: 13 }, depsAge: 11, deploys7d: 3, lastDeploy: "1d ago",
    env: "prod+staging", stack: ["FastAPI", "Snowflake", "OpenAI"], generator: "Cursor", flags: ["infra-drift"],
    connections: [
      { type: "db",   name: "warehouse.snowflake", det: true },
      { type: "svc",  name: "zendesk-sync (int)",  det: true },
      { type: "llm",  name: "OpenAI · GPT-4.1",    det: false },
      { type: "saas", name: "Hubspot",             det: true },
    ]},
  { id: "vendor-intake",       name: "Vendor Intake Form",  owner: "dk", team: "Legal",
    audit: 64, cost: 180, costBreakdown: { compute: 40, apis: 70, llm: 70 },
    dau: 2, wau: 9, uniqueMau: 22, monthlyUsers: 6, creators: 1, dauTrend: "steady",
    tests: { total: 6, passing: 5 }, depsAge: 34, deploys7d: 1, lastDeploy: "6d ago",
    env: "prod+staging", stack: ["Remix", "Postgres"], generator: "Lovable", flags: ["deps-stale", "shared-key"],
    connections: [
      { type: "db",   name: "vendors.postgres",    det: true },
      { type: "saas", name: "Ironclad",            det: true },
      { type: "llm",  name: "Anthropic · Haiku",   det: false },
    ]},
  { id: "campaign-studio",     name: "Campaign Studio",     owner: "tt", team: "Marketing",
    audit: 86, cost: 2640, costBreakdown: { compute: 320, apis: 520, llm: 1800 },
    dau: 6, wau: 14, uniqueMau: 22, monthlyUsers: 18, creators: 3, dauTrend: "+32% 30d",
    tests: { total: 22, passing: 22 }, depsAge: 7, deploys7d: 9, lastDeploy: "4h ago",
    env: "prod+staging", stack: ["Next.js", "S3", "Replicate"], generator: "v0", flags: [],
    connections: [
      { type: "db",   name: "campaigns.postgres",  det: true },
      { type: "saas", name: "Mailgun",             det: true },
      { type: "saas", name: "Segment",             det: true },
      { type: "llm",  name: "Replicate · SDXL",    det: false },
      { type: "llm",  name: "OpenAI · GPT-4.1",    det: false },
    ]},
  { id: "invoice-matcher",     name: "Invoice Matcher",     owner: "rp", team: "Finance",
    audit: 81, cost: 680, costBreakdown: { compute: 180, apis: 300, llm: 200 },
    dau: 4, wau: 11, uniqueMau: 18, monthlyUsers: 9, creators: 2, dauTrend: "+4% 30d",
    tests: { total: 18, passing: 18 }, depsAge: 9, deploys7d: 4, lastDeploy: "3d ago",
    env: "prod+staging", stack: ["Python", "Postgres"], generator: "Claude Code", flags: [],
    connections: [
      { type: "db",   name: "finance.postgres",    det: true },
      { type: "saas", name: "NetSuite",            det: true },
      { type: "llm",  name: "Anthropic · Sonnet",  det: false },
    ]},
  { id: "pto-bot",             name: "PTO Bot",             owner: "ay", team: "People Ops",
    audit: 89, cost: 140, costBreakdown: { compute: 40, apis: 60, llm: 40 },
    dau: 38, wau: 182, uniqueMau: 454, monthlyUsers: 62, creators: 1, dauTrend: "+11% 30d",
    tests: { total: 9, passing: 9 }, depsAge: 6, deploys7d: 0, lastDeploy: "12d ago",
    env: "prod", stack: ["Slack Bolt", "Postgres"], generator: "Bolt", flags: [],
    connections: [
      { type: "db",   name: "hr.postgres",         det: true },
      { type: "saas", name: "Slack",               det: true },
      { type: "saas", name: "BambooHR",            det: true },
    ]},
  { id: "supplier-portal",     name: "Supplier Portal",     owner: "nc", team: "Supply Chain",
    audit: 72, cost: 540, costBreakdown: { compute: 120, apis: 260, llm: 160 },
    dau: 9, wau: 24, uniqueMau: 38, monthlyUsers: 14, creators: 2, dauTrend: "+22% 30d",
    tests: { total: 11, passing: 10 }, depsAge: 18, deploys7d: 2, lastDeploy: "4d ago",
    env: "prod+staging", stack: ["SvelteKit", "Postgres"], generator: "Lovable", flags: ["shared-key"],
    connections: [
      { type: "db",   name: "suppliers.postgres",  det: true },
      { type: "saas", name: "SAP Ariba",           det: true },
      { type: "llm",  name: "OpenAI · GPT-4o",     det: false },
    ]},
  { id: "onboard-wizard",      name: "Onboarding Wizard",   owner: "ml", team: "Revenue Ops",
    audit: 88, cost: 380, costBreakdown: { compute: 90, apis: 160, llm: 130 },
    dau: 7, wau: 18, uniqueMau: 26, monthlyUsers: 12, creators: 2, dauTrend: "+9% 30d",
    tests: { total: 15, passing: 15 }, depsAge: 5, deploys7d: 6, lastDeploy: "7h ago",
    env: "prod+staging", stack: ["Next.js", "Postgres"], generator: "Claude Code", flags: [],
    connections: [
      { type: "db",   name: "deals.postgres",      det: true },
      { type: "saas", name: "Salesforce REST",     det: true },
      { type: "llm",  name: "Anthropic · Sonnet",  det: false },
    ]},
  { id: "nps-pulse",           name: "NPS Pulse",           owner: "sj", team: "Customer Success",
    audit: 83, cost: 220, costBreakdown: { compute: 40, apis: 100, llm: 80 },
    dau: 5, wau: 19, uniqueMau: 48, monthlyUsers: 22, creators: 2, dauTrend: "+3% 30d",
    tests: { total: 8, passing: 8 }, depsAge: 8, deploys7d: 1, lastDeploy: "2d ago",
    env: "prod+staging", stack: ["Remix", "Postgres"], generator: "Bolt", flags: [],
    connections: [
      { type: "db",   name: "warehouse.snowflake", det: true },
      { type: "saas", name: "Typeform",            det: true },
      { type: "llm",  name: "OpenAI · GPT-4.1",    det: false },
    ]},
];

// 15 more apps to fill out the fleet to 24. Lighter detail, just what FleetTable / AppTile need.
const APPS_EXTRA = [
  { id: "deal-desk-helper",   name: "Deal Desk Helper",     owner: "ml", team: "Revenue Ops",      audit: 84, cost: 240,  monthlyUsers: 7,  creators: 1, dauTrend: "+5% 30d",  tests: { total: 11, passing: 11 }, depsAge: 6,  deploys7d: 2, lastDeploy: "1d ago",  env: "prod",         stack: ["Next.js","Postgres"],     generator: "Cursor",       flags: [],              connections: [{type:"db",name:"deals.postgres",det:true},{type:"saas",name:"Salesforce REST",det:true}] },
  { id: "renewal-radar",      name: "Renewal Radar",        owner: "ps", team: "Customer Success", audit: 79, cost: 410,  monthlyUsers: 9,  creators: 1, dauTrend: "+8% 30d",  tests: { total: 9,  passing: 8  }, depsAge: 14, deploys7d: 1, lastDeploy: "3d ago",  env: "prod+staging", stack: ["FastAPI","Snowflake"],   generator: "Cursor",       flags: ["deps-stale"],  connections: [{type:"db",name:"warehouse.snowflake",det:true}] },
  { id: "contract-redliner",  name: "Contract Redliner",    owner: "dk", team: "Legal",            audit: 71, cost: 920,  monthlyUsers: 4,  creators: 1, dauTrend: "+12% 30d", tests: { total: 8,  passing: 7  }, depsAge: 9,  deploys7d: 3, lastDeploy: "11h ago", env: "prod+staging", stack: ["Next.js","Postgres"],     generator: "Claude Code",  flags: ["shared-key"],  connections: [{type:"saas",name:"Ironclad",det:true},{type:"llm",name:"Anthropic · Sonnet",det:false}] },
  { id: "lead-enricher",      name: "Lead Enricher",        owner: "tt", team: "Marketing",        audit: 76, cost: 360,  monthlyUsers: 5,  creators: 1, dauTrend: "+3% 30d",  tests: { total: 6,  passing: 6  }, depsAge: 12, deploys7d: 2, lastDeploy: "2d ago",  env: "prod",         stack: ["Python","Postgres"],     generator: "Lovable",      flags: [],              connections: [{type:"saas",name:"Clearbit",det:true},{type:"saas",name:"Hubspot",det:true}] },
  { id: "ap-triage",          name: "AP Triage",            owner: "rp", team: "Finance",          audit: 88, cost: 190,  monthlyUsers: 6,  creators: 1, dauTrend: "steady",   tests: { total: 14, passing: 14 }, depsAge: 4,  deploys7d: 0, lastDeploy: "8d ago",  env: "prod",         stack: ["Python","Postgres"],     generator: "Claude Code",  flags: [],              connections: [{type:"saas",name:"NetSuite",det:true}] },
  { id: "expense-classifier", name: "Expense Classifier",   owner: "rp", team: "Finance",          audit: 82, cost: 280,  monthlyUsers: 11, creators: 1, dauTrend: "+7% 30d",  tests: { total: 12, passing: 12 }, depsAge: 8,  deploys7d: 1, lastDeploy: "4d ago",  env: "prod+staging", stack: ["FastAPI","Postgres"],     generator: "Cursor",       flags: [],              connections: [{type:"saas",name:"Brex",det:true},{type:"llm",name:"Anthropic · Haiku",det:false}] },
  { id: "headcount-planner",  name: "Headcount Planner",    owner: "ay", team: "People Ops",       audit: 74, cost: 130,  monthlyUsers: 8,  creators: 1, dauTrend: "+2% 30d",  tests: { total: 5,  passing: 4  }, depsAge: 22, deploys7d: 0, lastDeploy: "15d ago", env: "prod",         stack: ["Remix","Postgres"],       generator: "Bolt",         flags: ["deps-stale"],  connections: [{type:"saas",name:"BambooHR",det:true}] },
  { id: "interview-scheduler",name: "Interview Scheduler",  owner: "ay", team: "People Ops",       audit: 86, cost: 110,  monthlyUsers: 13, creators: 1, dauTrend: "+15% 30d", tests: { total: 7,  passing: 7  }, depsAge: 5,  deploys7d: 4, lastDeploy: "5h ago",  env: "prod",         stack: ["Slack Bolt","Postgres"],  generator: "Bolt",         flags: [],              connections: [{type:"saas",name:"Greenhouse",det:true},{type:"saas",name:"Slack",det:true}] },
  { id: "po-approval",        name: "PO Approval Bot",      owner: "nc", team: "Supply Chain",     audit: 80, cost: 200,  monthlyUsers: 5,  creators: 1, dauTrend: "+4% 30d",  tests: { total: 9,  passing: 9  }, depsAge: 7,  deploys7d: 1, lastDeploy: "2d ago",  env: "prod",         stack: ["Slack Bolt","Postgres"],  generator: "Claude Code",  flags: [],              connections: [{type:"saas",name:"SAP Ariba",det:true},{type:"saas",name:"Slack",det:true}] },
  { id: "inventory-watch",    name: "Inventory Watch",      owner: "nc", team: "Supply Chain",     audit: 68, cost: 480,  monthlyUsers: 4,  creators: 1, dauTrend: "+6% 30d",  tests: { total: 8,  passing: 6  }, depsAge: 28, deploys7d: 0, lastDeploy: "22d ago", env: "prod+staging", stack: ["Python","Snowflake"],     generator: "Cursor",       flags: ["deps-stale","infra-drift"], connections: [{type:"db",name:"warehouse.snowflake",det:true}] },
  { id: "support-summarizer", name: "Support Summarizer",   owner: "sj", team: "Customer Success", audit: 90, cost: 540,  monthlyUsers: 14, creators: 2, dauTrend: "+24% 30d", tests: { total: 11, passing: 11 }, depsAge: 3,  deploys7d: 5, lastDeploy: "2h ago",  env: "prod+staging", stack: ["Next.js","Postgres"],     generator: "Claude Code",  flags: [],              connections: [{type:"saas",name:"Zendesk",det:true},{type:"llm",name:"Anthropic · Sonnet",det:false}] },
  { id: "kb-bot",             name: "Knowledge Base Bot",   owner: "ay", team: "People Ops",       audit: 85, cost: 320,  monthlyUsers: 41, creators: 1, dauTrend: "+9% 30d",  tests: { total: 7,  passing: 7  }, depsAge: 6,  deploys7d: 2, lastDeploy: "1d ago",  env: "prod",         stack: ["Slack Bolt","Postgres"],  generator: "Bolt",         flags: [],              connections: [{type:"saas",name:"Notion",det:true},{type:"saas",name:"Slack",det:true},{type:"llm",name:"Anthropic · Haiku",det:false}] },
  { id: "release-notes-gen",  name: "Release Notes Gen",    owner: "tt", team: "Marketing",        audit: 78, cost: 160,  monthlyUsers: 6,  creators: 1, dauTrend: "+5% 30d",  tests: { total: 5,  passing: 5  }, depsAge: 10, deploys7d: 1, lastDeploy: "3d ago",  env: "prod",         stack: ["Next.js","Postgres"],     generator: "v0",           flags: [],              connections: [{type:"saas",name:"Linear",det:true},{type:"llm",name:"OpenAI · GPT-4.1",det:false}] },
  { id: "outbound-dialer",    name: "Outbound Dialer",      owner: "ml", team: "Revenue Ops",      audit: 73, cost: 720,  monthlyUsers: 8,  creators: 1, dauTrend: "+18% 30d", tests: { total: 10, passing: 9  }, depsAge: 13, deploys7d: 3, lastDeploy: "8h ago",  env: "prod+staging", stack: ["FastAPI","Postgres"],     generator: "Cursor",       flags: ["shared-key"],  connections: [{type:"saas",name:"Twilio",det:true},{type:"saas",name:"Salesforce REST",det:true}] },
  { id: "ticket-router",      name: "Ticket Router",        owner: "ps", team: "Customer Success", audit: 81, cost: 240,  monthlyUsers: 10, creators: 1, dauTrend: "+11% 30d", tests: { total: 8,  passing: 8  }, depsAge: 7,  deploys7d: 2, lastDeploy: "1d ago",  env: "prod",         stack: ["Python","Postgres"],     generator: "Claude Code",  flags: [],              connections: [{type:"saas",name:"Zendesk",det:true},{type:"llm",name:"Anthropic · Haiku",det:false}] },
];

APPS.push(...APPS_EXTRA);

// Derived totals used in the UI, sized for a 100-400 person ICP.
// Fleet of 24 apps, 17 operators authoring them, 79 unique monthly users across the company.
const FLEET_TOTALS = {
  apps: 24,
  operators: 17,
  monthlyUsers: 79,
  monthlyCost: 14200,
};

// Signals = the CTO's decision queue. Each is a moment where Stoda needs a human call.
const SIGNALS = [
  { id: "s1", kind: "risk", sev: "risk",
    title: "Dependency tests failed in staging, 3 days to disable",
    path: "Quote Copilot · v124 · openai-node 4.52 → 4.55",
    detail: "Operator-authored test \"quote totals match Salesforce\" failed on staging after a dep bump. Operator (Maya) has been notified. Per the 3-day-stale rule, Stoda will disable Quote Copilot in 72 hours unless tests pass or you grant an exception.",
    cta: "Grant exception", action: "exception" },
  { id: "s3", kind: "risk", sev: "warn",
    title: "Campaign Studio trending over budget, disable on May 17",
    path: "Marketing · $2,640 of $3,200 · +32% MoM",
    detail: "AWS + Replicate spend is on pace to hit the team budget by May 17. Per the auto-disable-at-budget rule, Stoda will pause new deploys then. Increase the budget (permanent or temporary) or accept the pause.",
    cta: "Increase budget", action: "budget" },
  { id: "s4", kind: "opportunity", sev: "warn",
    title: "Shared API key across 4 apps, no rule configured",
    path: "OPENAI_API_KEY · $1,240/mo unattributed",
    detail: "Four apps share a single OpenAI key. No rule mandates per-app keys. Recommend mandating separate keys at deploy with a 7-day grace window so operators can migrate without breakage.",
    cta: "Configure rule", action: "rule-keys" },
  { id: "s5", kind: "opportunity", sev: "info",
    title: "Codify a shared contract for deals.postgres",
    path: "3 apps · Quote Copilot, Onboarding Wizard, Churn Early Warning",
    detail: "All three query deals.postgres directly. Codifying a shared read-contract prevents silent breakage when the schema evolves, and speeds future apps on the same data.",
    cta: "Review contract proposal", action: "contract" },
];

const RECOMMENDATIONS = [
  { id: "r1", kind: "knowledge", title: "Define a shared contract for deals.postgres",
    subtitle: "3 apps query this table directly",
    detail: "Generate a typed client and propagate to Quote Copilot, Onboarding Wizard, Churn Early Warning. Future migrations stop breaking apps silently.",
    impact: "Protects 3 apps · 37 DAU combined", cta: "Codify contract",
    apps: ["Quote Copilot", "Onboarding Wizard", "Churn Early Warning"] },
  { id: "r2", kind: "knowledge", title: "Document the Salesforce → Postgres sync path",
    subtitle: "2 apps rely on this implicit mapping",
    detail: "Quote Copilot and Onboarding Wizard both transform SF opportunity data into the `deals` schema, with slightly different rounding rules. Codify the mapping to eliminate the drift.",
    impact: "Eliminates a drift class", cta: "Propose mapping",
    apps: ["Quote Copilot", "Onboarding Wizard"] },
  { id: "r3", kind: "rule", title: "Require staging gate on all outbound-domain changes",
    subtitle: "Currently optional for 4 apps",
    detail: "Apps without the gate can introduce a new outbound domain and ship it in a single deploy. Making the gate global adds ~0 ops overhead.",
    impact: "Tightens 4 apps · zero-downtime", cta: "Turn on globally" },
  { id: "r4", kind: "rule", title: "Auto-apply tested dependency bundles",
    subtitle: "6 apps eligible · 0 incidents in last 90d",
    detail: "Deterministic tests already gate these. Turning on auto-apply removes ~2 hrs/week of operator upkeep.",
    impact: "Recovers ~2 hrs/wk per operator", cta: "Enable auto-apply" },
  { id: "r5", kind: "knowledge", title: "Name the LLM endpoints used across the fleet",
    subtitle: "6 distinct endpoints · 3 are non-deterministic",
    detail: "Stoda can pin response schemas on non-deterministic calls and raise an alert if a provider changes output shape.",
    impact: "Eliminates a whole class of silent breakage", cta: "Pin schemas" },
];

const SCHEMAS = [
  { name: "deals.postgres",     kind: "Postgres table",     apps: ["Quote Copilot", "Onboarding Wizard", "Churn Early Warning"], contract: "none",   health: "risk", reads: 128000, writes: 4200 },
  { name: "quotes.postgres",    kind: "Postgres table",     apps: ["Quote Copilot"], contract: "typed",  health: "ok",   reads: 42000,  writes: 3100 },
  { name: "warehouse.snowflake",kind: "Snowflake warehouse",apps: ["Churn Early Warning", "NPS Pulse"], contract: "typed",  health: "ok",   reads: 89000,  writes: 0 },
  { name: "campaigns.postgres", kind: "Postgres table",     apps: ["Campaign Studio"], contract: "typed",  health: "ok",   reads: 18000,  writes: 2200 },
  { name: "finance.postgres",   kind: "Postgres table",     apps: ["Invoice Matcher"], contract: "typed",  health: "ok",   reads: 22000,  writes: 800 },
  { name: "hr.postgres",        kind: "Postgres table",     apps: ["PTO Bot"], contract: "typed",  health: "ok",   reads: 14000,  writes: 1100 },
  { name: "suppliers.postgres", kind: "Postgres table",     apps: ["Supplier Portal"], contract: "typed",  health: "ok",   reads: 9400,   writes: 610 },
  { name: "vendors.postgres",   kind: "Postgres table",     apps: ["Vendor Intake Form"], contract: "partial",health: "warn", reads: 2100,   writes: 280 },
];

// --------- Rule categories w/ built-in tests ---------
// Each category groups a handful of rules. Each rule runs N pre-baked deterministic tests Stoda ships.
// "Built-in tests" = tests Stoda authored, not operator-authored workflow tests.
const RULE_CATEGORIES = [
  { id: "governance",  name: "Access & Ownership", icon: "Shield",   description: "Ownership, access reviews, evidence trails." },
  { id: "security",    name: "Security",         icon: "Lock",     description: "Keys, secrets, outbound surface, isolation." },
  { id: "pipeline",    name: "Pipeline",         icon: "Pipeline", description: "Staging gates, approvals, deploy hygiene." },
  { id: "quality",     name: "Quality",          icon: "Flask",    description: "Test coverage, LLM determinism, schema pinning." },
  { id: "cost",        name: "Cost",             icon: "Dollar",   description: "Budgets, attribution, runaway-spend guardrails." },
  { id: "network",     name: "Network",          icon: "Cloud",    description: "Allowlists, egress, DNS discipline." },
  { id: "data",        name: "Data",             icon: "Database", description: "Schema contracts, PII handling, backup proof." },
];

const RULES = [
  // SECURITY (5 rules · 132 built-in tests)
  { id: "rule-sec-1",  category: "security", name: "No secrets in code",
    status: "on",  coverage: 24, violations: 0, builtInTests: 34,
    summary: "Scans every deploy for hardcoded keys, tokens, and credential patterns across 140+ known vendor schemas." },
  { id: "rule-sec-3",  category: "security", name: "Outbound domain allowlist",
    status: "on",  coverage: 24, violations: 1, builtInTests: 21,
    summary: "Every outbound HTTP target is approved. New domains require signed approval." },
  { id: "rule-sec-4",  category: "security", name: "PII never sent to non-det endpoints",
    status: "on",  coverage: 23, violations: 0, builtInTests: 42,
    summary: "Tags PII at the schema level and blocks it from reaching LLM and analytics endpoints." },
  { id: "rule-sec-5",  category: "security", name: "SSO enforced on every app",
    status: "on",  coverage: 24, violations: 0, builtInTests: 17,
    summary: "Checks SSO wiring, session expiry, and role-claim presence on every route." },

  // PIPELINE (4 rules · 61 tests)
  { id: "rule-pipe-1", category: "pipeline", name: "Staging gate required",
    status: "partial", coverage: 20, violations: 4, builtInTests: 16,
    summary: "Every deploy must pass staging before prod. 4 apps opt out, all flagged." },
  { id: "rule-pipe-2", category: "pipeline", name: "Apps with >3 DAU require automated QA at staging pre-deploy",
    status: "on",  coverage: 24, violations: 0, builtInTests: 12,
    summary: "Once an app has more than 3 daily active users, every deploy must pass the automated staging QA suite before promotion." },
  { id: "rule-pipe-4", category: "pipeline", name: "Rollback plan exists",
    status: "on",  coverage: 24, violations: 0, builtInTests: 22,
    summary: "Every deploy ships with a validated rollback target. Verified on every release." },

  // QUALITY (4 rules · 88 tests)
  { id: "rule-qual-1", category: "quality", name: "Deterministic tests cover happy path",
    status: "on",  coverage: 24, violations: 0, builtInTests: 24,
    summary: "Every app has at least one test covering its primary workflow end-to-end." },
  { id: "rule-qual-3", category: "quality", name: "Dependencies ≤ 30 days stale",
    status: "on",  coverage: 23, violations: 1, builtInTests: 27,
    summary: "Flags packages older than 30 days. Auto-apply bundle available." },

  // COST (3 rules · 29 tests)
  { id: "rule-cost-1", category: "cost", name: "LLM budget cap per app",
    status: "off", coverage: 0,  violations: 0, builtInTests: 8,
    summary: "Per-app monthly LLM cap. Recommended: $1,500 default. Not yet turned on." },
  { id: "rule-cost-2", category: "cost", name: "Alert on 2x week-over-week spend",
    status: "on",  coverage: 24, violations: 1, builtInTests: 9,
    summary: "Routes to owner if a single app's cost doubles week-over-week." },

  // NETWORK (3 rules · 48 tests)
  { id: "rule-net-1",  category: "network", name: "No inbound from public internet",
    status: "on",  coverage: 24, violations: 0, builtInTests: 15,
    summary: "Apps must sit behind the org VPN or identity-aware proxy." },
  { id: "rule-net-2",  category: "network", name: "TLS 1.3+ only on outbound",
    status: "on",  coverage: 24, violations: 0, builtInTests: 22,
    summary: "Checks cipher suites and certificate chains on every outbound target." },
  { id: "rule-net-3",  category: "network", name: "DNS queries logged",
    status: "on",  coverage: 24, violations: 0, builtInTests: 11,
    summary: "DNS resolution is logged to the control plane for audit replay." },

  // DATA (3 rules · 54 tests)
  { id: "rule-data-1", category: "data", name: "Multi-app schemas have typed contracts",
    status: "partial", coverage: 7, violations: 1, builtInTests: 16,
    summary: "Every schema used by 2+ apps needs a codified contract. 1 violation: deals.postgres." },
  { id: "rule-data-2", category: "data", name: "Backup restore tested in last 90 days",
    status: "on",  coverage: 24, violations: 0, builtInTests: 19,
    summary: "Restore drill runs monthly. Stoda validates data integrity against a known-good snapshot." },
  { id: "rule-data-3", category: "data", name: "PII columns tagged and encrypted",
    status: "on",  coverage: 24, violations: 0, builtInTests: 19,
    summary: "Schema crawler tags known PII patterns and verifies at-rest encryption." },

  // GOVERNANCE (3 rules · 33 tests)
  { id: "rule-gov-1",  category: "governance", name: "Owner of record required",
    status: "on",  coverage: 24, violations: 0, builtInTests: 8,
    summary: "Every app has a named operator. Missing-owner apps cannot deploy." },
  { id: "rule-gov-2", category: "governance", name: "Access reviews quarterly",
    status: "on",  coverage: 24, violations: 0, builtInTests: 11,
    summary: "Who can deploy what, reviewed every quarter. Next review: May 15." },
];

const BLOCKED_DEPLOYS = [
  { id: "b1", app: "Quote Copilot",        version: "v124", reason: "Operator test failed: quote totals match Salesforce",           when: "14 min ago", author: "ml", status: "held" },
  { id: "b2", app: "Supplier Portal",      version: "v087", reason: "New outbound domain not on allowlist: api.fixer.io",             when: "2 hr ago",   author: "nc", status: "held" },
  { id: "b3", app: "Campaign Studio",      version: "v215", reason: "Env var REPLICATE_TOKEN rotated mid-deploy",                     when: "yesterday",  author: "tt", status: "auto-fixed" },
  { id: "b4", app: "Churn Early Warning",  version: "v066", reason: "LLM endpoint returning non-deterministic schema on a det call",  when: "2 days ago", author: "sj", status: "resolved" },
];

const PIPELINE = {
  pending:  { count: 4, label: "Pending review" },
  staging:  { count: 7, label: "In staging" },
  gates:    { open: 11, blocked: 2 },
  prod:     { count: 24, label: "Live apps" },
};

// ---------- Services & shared resources ----------
// Promoted from inline list: services are first-class so we can pivot on shared keys / non-det LLM endpoints.
const SERVICES = [
  // sharedKey: env name when one secret is reused across multiple apps (the problem state, costs unattributed, blast radius all apps).
  // null when each app has its own per-app key (clean state, costs naturally attributed by key).
  { name: "Anthropic · Sonnet", kind: "LLM",   apps: ["Quote Copilot", "Onboarding Wizard", "Invoice Matcher"], det: false, cost: 1000, sharedKey: null,                  firstSeen: 180, note: "Per-app keys via Stoda key broker." },
  { name: "OpenAI · GPT-4.1",   kind: "LLM",   apps: ["Churn Early Warning", "Campaign Studio", "NPS Pulse"],   det: false, cost: 1240, sharedKey: "OPENAI_API_KEY",     firstSeen: 95,  note: "Single shared key across 3 apps, costs unattributed, blast radius all 3." },
  { name: "OpenAI · GPT-4o",    kind: "LLM",   apps: ["Supplier Portal"],                                       det: false, cost: 420,  sharedKey: null,                  firstSeen: 12 },
  { name: "Anthropic · Haiku",  kind: "LLM",   apps: ["Vendor Intake Form"],                                    det: false, cost: 180,  sharedKey: null,                  firstSeen: 60 },
  { name: "Replicate · SDXL",   kind: "LLM",   apps: ["Campaign Studio"],                                       det: false, cost: 1800, sharedKey: null,                  firstSeen: 22 },
  { name: "Salesforce REST",    kind: "SaaS",  apps: ["Quote Copilot", "Onboarding Wizard"],                    det: true,  cost: 340,  sharedKey: "SALESFORCE_TOKEN",   firstSeen: 180, policy: "allowlisted", note: "Shared service account, Salesforce only allows one per org." },
  { name: "Stripe",             kind: "SaaS",  apps: ["Quote Copilot"],                                          det: true,  cost: 120,  sharedKey: null,                  firstSeen: 240 },
  { name: "DocuSign",           kind: "SaaS",  apps: ["Quote Copilot"],                                          det: true,  cost: 80,   sharedKey: null,                  firstSeen: 210 },
  { name: "NetSuite",           kind: "SaaS",  apps: ["Invoice Matcher"],                                        det: true,  cost: 200,  sharedKey: null,                  firstSeen: 165 },
  { name: "BambooHR",           kind: "SaaS",  apps: ["PTO Bot"],                                                det: true,  cost: 90,   sharedKey: null,                  firstSeen: 150 },
  { name: "Slack",              kind: "SaaS",  apps: ["PTO Bot"],                                                det: true,  cost: 0,    sharedKey: null,                  firstSeen: 320 },
  { name: "Mailgun",            kind: "SaaS",  apps: ["Campaign Studio"],                                        det: true,  cost: 60,   sharedKey: null,                  firstSeen: 80 },
  { name: "Segment",            kind: "SaaS",  apps: ["Campaign Studio"],                                        det: true,  cost: 150,  sharedKey: null,                  firstSeen: 90 },
  { name: "Hubspot",            kind: "SaaS",  apps: ["Churn Early Warning"],                                    det: true,  cost: 180,  sharedKey: null,                  firstSeen: 110 },
  { name: "Ironclad",           kind: "SaaS",  apps: ["Vendor Intake Form"],                                     det: true,  cost: 110,  sharedKey: null,                  firstSeen: 130 },
  { name: "SAP Ariba",          kind: "SaaS",  apps: ["Supplier Portal"],                                        det: true,  cost: 210,  sharedKey: null,                  firstSeen: 75 },
  { name: "Typeform",           kind: "SaaS",  apps: ["NPS Pulse"],                                              det: true,  cost: 40,   sharedKey: null,                  firstSeen: 200 },
  { name: "Twilio · SMS",       kind: "SaaS",  apps: [],                                                         det: true,  cost: 0,    sharedKey: null,                  firstSeen: 6,   note: "Blocked from fleet, an app tried to call it 6 days ago." },
];

// Anything used by 2+ apps. Surfaced front-and-center on Connections.
const SHARED_RESOURCES = {
  schemas:  () => SCHEMAS.filter(s => s.apps.length > 1),
  services: () => SERVICES.filter(s => s.apps.length > 1),
};

// ---------- Cost attribution ----------
const TEAM_BUDGETS = [
  { team: "Revenue Ops",       owner: "ml", budget: 3500, spent: 2220, apps: 2, color: "#FFB98A" },
  { team: "Marketing",         owner: "tt", budget: 3200, spent: 2640, apps: 1, color: "#F4C9B0" },
  { team: "Customer Success",  owner: "sj", budget: 1500, spent: 1040, apps: 2, color: "#D9C7E8" },
  { team: "Finance",           owner: "rp", budget: 1200, spent: 680,  apps: 1, color: "#B4D0B0" },
  { team: "Supply Chain",      owner: "nc", budget: 800,  spent: 540,  apps: 1, color: "#E8D9C7" },
  { team: "People Ops",        owner: "ay", budget: 400,  spent: 140,  apps: 1, color: "#C7D9E8" },
  { team: "Legal",             owner: "dk", budget: 400,  spent: 180,  apps: 1, color: "#D0B0B4" },
];

// Top line items (actual services by spend)
const TOP_LINE_ITEMS = [
  { name: "OpenAI · GPT-4.1",    kind: "LLM", cost: 1240, apps: 3, trend: "+12%", unattributed: true,  note: "Shared key across 3 apps, no per-app attribution" },
  { name: "Replicate · SDXL",    kind: "LLM", cost: 1800, apps: 1, trend: "+32%", unattributed: false },
  { name: "Anthropic · Sonnet",  kind: "LLM", cost: 1000, apps: 1, trend: "+4%",  unattributed: false },
  { name: "Salesforce REST",     kind: "API", cost: 340,  apps: 2, trend: "flat", unattributed: false },
  { name: "NetSuite",            kind: "API", cost: 200,  apps: 1, trend: "flat", unattributed: false },
  { name: "AWS RDS · db.r6g",    kind: "Infra", cost: 980, apps: 6, trend: "+2%",  unattributed: false },
  { name: "AWS EKS · m6i",       kind: "Infra", cost: 720, apps: 9, trend: "+3%",  unattributed: false },
  { name: "Stripe",              kind: "API", cost: 120,  apps: 1, trend: "+6%",  unattributed: false },
];

// 30-day daily spend for forecasting
const COST_TREND_30D = Array.from({ length: 30 }, (_, i) => {
  const base = 420 + Math.sin(i / 4) * 40;
  const growth = i * 2.2;
  return Math.round(base + growth + ((i * 131) % 40));
});

const SPARK = (seed, n = 14) => {
  const out = []; let v = seed;
  for (let i = 0; i < n; i++) { v = (v * 9301 + 49297) % 233280; out.push(0.2 + (v / 233280) * 0.8); }
  return out;
};

window.DATA = {
  OPERATORS, ME_OPERATOR, ME_CTO, APPS, FLEET_TOTALS,
  SIGNALS, RECOMMENDATIONS, SCHEMAS,
  SERVICES, SHARED_RESOURCES,
  RULE_CATEGORIES, RULES,
  BLOCKED_DEPLOYS, PIPELINE,
  TEAM_BUDGETS, TOP_LINE_ITEMS, COST_TREND_30D,
  SPARK,
};
