{
  "report": "ghost-job-signals",
  "quarter": "2026-Q3",
  "snapshotDate": "2026-09-16",
  "license": "CC BY 4.0",
  "methodologyUrl": "https://four-leaf.ai/research/methodology",
  "source": "Four-Leaf live job index, postings pulled directly from company career pages",
  "findings": [
    "The index held 147,565 active postings from 1,180 companies on 2026-09-16.",
    "26,268 active postings, 17.8%, had been live for more than 60 days.",
    "11,847 active postings, 8.0%, had been live for more than 120 days.",
    "1,342 distinct company and title pairs appeared 5 or more times in the index, and 310 appeared 12 or more times.",
    "20,912 active postings belonged to a role repeated 5 or more times at the same company.",
    "44,951 active postings, 30.5%, carried at least one structural ghost-job signal."
  ],
  "population": {
    "totalActivePostings": 147565,
    "companies": 1180,
    "postingsWithUnknownPostedDate": 24
  },
  "signals": {
    "liveOver60Days": {
      "count": 26268,
      "pct": 17.8
    },
    "liveOver120Days": {
      "count": 11847,
      "pct": 8.0
    },
    "distinctRolesRepeated5Plus": 1342,
    "distinctRolesRepeated12Plus": 310,
    "postingsInRolesRepeated5Plus": 20912,
    "anyStructuralSignal": {
      "count": 44951,
      "pct": 30.5
    }
  },
  "definitions": {
    "activePosting": "A row in the index flagged is_active, meaning the posting was still listed at the company source on the snapshot date.",
    "role": "A distinct company plus case-folded, trimmed job title.",
    "structuralGhostJobSignal": "A posting live for more than 60 days, OR one belonging to a role repeated 5 or more times at the same company. Computed over every active posting from raw columns. It is a prompt to verify a listing, not a finding that the listing is fake.",
    "ageUnknown": "A posting with no posted_at cannot satisfy either age test, so the 24 such postings count toward the denominator and never toward the 60 or 120 day figures."
  },
  "notPublishedHere": {
    "contentSignals": "The ghost job checker also reads the language of an individual ad. That analysis runs per lookup and has never been run across the index, so no index-wide share of it exists and none is reported here.",
    "applyLinkLiveness": "Apply-link liveness is checked per lookup for signed-in users, not across the index, so it is absent from these figures.",
    "storedLegitimacyTier": "scraped_jobs.legitimacy_tier is a cached column refreshed in capped daily batches, so at any moment it is a mix of tiers stamped weeks apart rather than a snapshot. It is deliberately not used here."
  },
  "reproduce": {
    "note": "This query returns every figure above, in the order they are listed. Run it against the postings index.",
    "sql": "with active as (\n  select company, lower(btrim(title)) as title_norm, posted_at\n  from scraped_jobs where is_active\n), dupes as (\n  select company, title_norm, count(*) as n from active group by 1, 2\n), j as (\n  select a.*, d.n,\n    (a.posted_at is not null and a.posted_at < now() - interval  '60 days') as stale_60,\n    (a.posted_at is not null and a.posted_at < now() - interval '120 days') as stale_120,\n    (d.n >= 5) as reposted_5plus\n  from active a join dupes d using (company, title_norm)\n)\nselect\n  count(*) as total_active_postings,\n  count(distinct company) as companies,\n  count(*) filter (where posted_at is null) as unknown_posted_date,\n  count(*) filter (where stale_60) as live_over_60d,\n  round(100.0 * count(*) filter (where stale_60) / count(*), 1) as live_over_60d_pct,\n  count(*) filter (where stale_120) as live_over_120d,\n  round(100.0 * count(*) filter (where stale_120) / count(*), 1) as live_over_120d_pct,\n  (select count(*) from dupes where n >= 5) as roles_repeated_5plus,\n  (select count(*) from dupes where n >= 12) as roles_repeated_12plus,\n  count(*) filter (where reposted_5plus) as postings_in_repeated_roles,\n  count(*) filter (where stale_60 or reposted_5plus) as any_signal,\n  round(100.0 * count(*) filter (where stale_60 or reposted_5plus) / count(*), 1) as any_signal_pct\nfrom j;"
  }
}
