diff --git a/docs/screenshots/signals-gaps.png b/docs/screenshots/signals-gaps.png new file mode 100644 index 00000000..2521e201 Binary files /dev/null and b/docs/screenshots/signals-gaps.png differ diff --git a/docs/screenshots/signals-top.png b/docs/screenshots/signals-top.png new file mode 100644 index 00000000..6bbc8529 Binary files /dev/null and b/docs/screenshots/signals-top.png differ diff --git a/src/app/signals/page.tsx b/src/app/signals/page.tsx new file mode 100644 index 00000000..1b962dba --- /dev/null +++ b/src/app/signals/page.tsx @@ -0,0 +1,114 @@ +import type { Metadata } from 'next' +import Breadcrumb from '@/components/Breadcrumb' +import { + predictionMarketMeta, + predictionMarketMappings, + fetchPolymarketOdds, + type MarketMatch, +} from '@/lib/predictionMarkets' + +export const metadata: Metadata = { + title: 'Signals — Inflection points, priced by the crowd', + description: predictionMarketMeta.subtitle, +} + +// Revalidate hourly (odds are cached per-slug in the fetch helper too). +export const revalidate = 3600 + +const matchLabel: Record = { + direct: 'Direct market', + proxy: 'Proxy market', + gap: 'No market yet', +} + +const matchStyle: Record = { + direct: 'bg-emerald-50 text-emerald-700 border-emerald-200', + proxy: 'bg-amber-50 text-amber-700 border-amber-200', + gap: 'bg-gray-100 text-gray-500 border-gray-200', +} + +export default async function SignalsPage() { + // Fetch live odds per mapping (passing the mapping's question as a hint so + // multi-threshold events resolve to the right line). + const odds = await Promise.all( + predictionMarketMappings.map((m) => + m.market.slug ? fetchPolymarketOdds(m.market.slug, m.market.question) : Promise.resolve(null), + ), + ) + + return ( +
+ + +

+ {predictionMarketMeta.title} +

+

+ {predictionMarketMeta.subtitle} +

+ +
+ {predictionMarketMappings.map((m, i) => { + const o = odds[i] + const pct = o && o.yesPrice != null ? Math.round(o.yesPrice * 100) : null + return ( +
+
+ + {m.area} + + + {matchLabel[m.match]} + +
+ +
{m.opportunitySpace}
+

{m.inflectionPoint}

+ +
+ {m.match === 'gap' ? ( +

{m.market.question}

+ ) : ( +
+
+
{m.market.platform}
+ + {m.market.question} + +
+
+
+ {pct != null ? `${pct}%` : '—'} +
+
crowd yes
+
+
+ )} + {m.market.note && ( +

+ {m.market.note} +

+ )} +
+
+ ) + })} +
+ +

+ {predictionMarketMeta.disclaimer} +

+
+ ) +} diff --git a/src/data/prediction-markets.json b/src/data/prediction-markets.json new file mode 100644 index 00000000..79c2c58b --- /dev/null +++ b/src/data/prediction-markets.json @@ -0,0 +1,121 @@ +{ + "meta": { + "title": "Inflection points, priced by the crowd", + "subtitle": "An experiment: each PL R&D inflection point mapped to the closest live prediction market on Polymarket / Kalshi. Where a market exists, the crowd's probability is a running scoreboard for our bets. Where none exists, the gap is itself a signal of how early or contrarian the bet is.", + "disclaimer": "Prototype for discussion. Odds are fetched live from public prediction-market APIs and are proxies, not exact restatements of our inflection points. Not investment advice; nothing here endorses gambling." + }, + "mappings": [ + { + "area": "AI & Robotics", + "areaSlug": "ai-robotics", + "opportunitySpace": "Open Compute Networks", + "inflectionPoint": "A decentralized / open compute network trains a model competitive with the hyperscalers' frontier.", + "match": "proxy", + "market": { + "platform": "Polymarket", + "question": "Will an open-weights (Chinese) model be the best AI model by Dec 31?", + "slug": "will-a-chinese-company-have-the-best-ai-model-by-december-31", + "url": "https://polymarket.com/event/will-a-chinese-company-have-the-best-ai-model-by-december-31", + "note": "Open-weights momentum is the best available proxy for open/distributed compute reaching the frontier." + } + }, + { + "area": "AI & Robotics", + "areaSlug": "ai-robotics", + "opportunitySpace": "Embodied AI & Robotics Data Networks", + "inflectionPoint": "Robotics datasets and embodied models reach the behavioral repertoire needed for real-world deployment.", + "match": "proxy", + "market": { + "platform": "Polymarket", + "question": "Will Tesla release a consumer Optimus humanoid by Dec 31, 2026?", + "slug": "will-tesla-release-optimus-by-june-30-2026", + "url": "https://polymarket.com/event/will-tesla-release-optimus-by-june-30-2026", + "note": "Commercial humanoid release is a visible downstream marker of embodied-AI data maturity. Figure F.03 reliability markets are a second proxy." + } + }, + { + "area": "AI & Robotics", + "areaSlug": "ai-robotics", + "opportunitySpace": "Agent Coordination & Agent-Native Economic Infrastructure", + "inflectionPoint": "Autonomous agents coordinate and transact across organizations without human intermediation.", + "match": "gap", + "market": { + "platform": "—", + "question": "No direct market yet — agents already trade ON Polymarket, but none prices agent-to-agent economies.", + "slug": "", + "url": "", + "note": "A genuine white space. Could be worth proposing/seeding such a market." + } + }, + { + "area": "Digital Human Rights", + "areaSlug": "digital-human-rights", + "opportunitySpace": "Portable Identity, Credentials & Trust", + "inflectionPoint": "A 100M+ service identifies users without state/platform KYC via self-sovereign identity.", + "match": "direct", + "market": { + "platform": "Polymarket", + "question": "Over 30M humans verified on World Network by Dec 31?", + "slug": "over-30m-humans-verified-on-world-network-by-december-31", + "url": "https://polymarket.com/event/over-30m-humans-verified-on-world-network-by-december-31", + "note": "Proof-of-human adoption at scale is the clearest live analogue to the portable-identity inflection." + } + }, + { + "area": "Digital Human Rights", + "areaSlug": "digital-human-rights", + "opportunitySpace": "Verifiable Public Knowledge & Provenance", + "inflectionPoint": "Frontier AI + major institutions adopt cryptographic content provenance as a baseline.", + "match": "gap", + "market": { + "platform": "—", + "question": "No clean market yet (EU AI Act Art. 50 enforcement, Aug 2026, is a candidate to track).", + "slug": "", + "url": "", + "note": "C2PA / SynthID adoption is measurable but not yet a liquid market — another white space." + } + }, + { + "area": "Neuro", + "areaSlug": "neurotech", + "opportunitySpace": "Neural Augmentation (BCI)", + "inflectionPoint": "An FDA-cleared BCI opens a third-party app layer, normalizing elective implantation.", + "match": "proxy", + "market": { + "platform": "Polymarket", + "question": "Will Neuralink's valuation hit $75B by Dec 31?", + "slug": "will-neuralinks-valuation-hit-by-december-31", + "url": "https://polymarket.com/event/will-neuralinks-valuation-hit-by-december-31", + "note": "Valuation / FDA-milestone markets track BCI momentum; a dedicated FDA-clearance market would be the direct measure." + } + }, + { + "area": "Economies & Governance", + "areaSlug": "economies-governance", + "opportunitySpace": "Sovereign Digital Public Infrastructure", + "inflectionPoint": "A nation-state runs core systems (identity, payments, registries) on crypto rails.", + "match": "proxy", + "market": { + "platform": "Polymarket", + "question": "Over 30M humans verified on World Network by Dec 31?", + "slug": "over-30m-humans-verified-on-world-network-by-december-31", + "url": "https://polymarket.com/event/over-30m-humans-verified-on-world-network-by-december-31", + "note": "World becoming a mandated digital-identity layer is one of our own examples; shares the World market as a proxy." + } + }, + { + "area": "Economies & Governance", + "areaSlug": "economies-governance", + "opportunitySpace": "Crypto-Native Governance & Decentralized Climate Finance", + "inflectionPoint": "A city/jurisdiction adopts crypto-native governance; a billion-dollar DePIN climate business emerges.", + "match": "gap", + "market": { + "platform": "—", + "question": "No liquid market yet for network-state governance adoption or DePIN climate scale.", + "slug": "", + "url": "", + "note": "Long-horizon, illiquid themes — the absence of a market underlines how contrarian these bets are." + } + } + ] +} diff --git a/src/lib/predictionMarkets.ts b/src/lib/predictionMarkets.ts new file mode 100644 index 00000000..379453f9 --- /dev/null +++ b/src/lib/predictionMarkets.ts @@ -0,0 +1,98 @@ +import mappingData from '@/data/prediction-markets.json' + +export type MarketMatch = 'direct' | 'proxy' | 'gap' + +export type MarketMapping = { + area: string + areaSlug: string + opportunitySpace: string + inflectionPoint: string + match: MarketMatch + market: { + platform: string + question: string + slug: string + url: string + note: string + } +} + +export type LiveOdds = { + yesPrice: number | null // 0..1 + question: string | null + fetchedAt: string +} + +export const predictionMarketMeta = (mappingData as { meta: { title: string; subtitle: string; disclaimer: string } }).meta +export const predictionMarketMappings = (mappingData as { mappings: MarketMapping[] }).mappings + +const GAMMA = 'https://gamma-api.polymarket.com' + +/** + * Fetch the current "Yes" probability for a Polymarket event by slug. + * Uses the public Gamma API (no auth). Returns the highest-priced Yes outcome + * across the event's markets as a simple headline number for the prototype. + */ +export async function fetchPolymarketOdds(slug: string, hint?: string): Promise { + const empty: LiveOdds = { yesPrice: null, question: null, fetchedAt: new Date().toISOString() } + if (!slug) return empty + try { + const res = await fetch(`${GAMMA}/events?slug=${encodeURIComponent(slug)}`, { + // Revalidate hourly so the page stays fresh without hammering the API. + next: { revalidate: 3600 }, + }) + if (!res.ok) return empty + const events = (await res.json()) as Array<{ + title?: string + markets?: Array<{ question?: string; outcomes?: string; outcomePrices?: string }> + }> + const event = events?.[0] + if (!event?.markets?.length) return empty + + // Parse every sub-market's Yes price once. + const parsed = event.markets + .map((m) => { + const outcomes = safeParse(m.outcomes) + const prices = safeParse(m.outcomePrices) + if (!outcomes || !prices) return null + const yesIdx = outcomes.findIndex((o) => o.toLowerCase() === 'yes') + if (yesIdx === -1) return null + const yes = Number(prices[yesIdx]) + if (Number.isNaN(yes)) return null + return { yes, question: m.question || event.title || '' } + }) + .filter((x): x is { yes: number; question: string } => x != null) + if (!parsed.length) return empty + + // If the mapping gives a hint (e.g. a "$75B" threshold), prefer the + // sub-market whose question shares a distinctive token with it. This keeps + // multi-threshold events (Neuralink valuation, etc.) on the right line + // instead of defaulting to the near-certain lowest threshold. + const token = hint ? distinctiveToken(hint) : null + const pick = + (token && parsed.find((m) => m.question.toLowerCase().includes(token))) || + parsed[0] + return { yesPrice: pick.yes, question: pick.question, fetchedAt: new Date().toISOString() } + } catch { + return empty + } +} + +// Pull a distinctive token (a $-amount or number) from the mapping question +// to disambiguate multi-threshold events. +function distinctiveToken(s: string): string | null { + const money = s.match(/\$[0-9]+(?:\.[0-9]+)?[bmk]?/i) + if (money) return money[0].toLowerCase() + const num = s.match(/[0-9]+m\b|[0-9]{2,}/i) + return num ? num[0].toLowerCase() : null +} + +function safeParse(s?: string): string[] | null { + if (!s) return null + try { + const v = JSON.parse(s) + return Array.isArray(v) ? v.map(String) : null + } catch { + return null + } +}