diff --git a/docs/screenshots/impact-signals-grid.png b/docs/screenshots/impact-signals-grid.png new file mode 100644 index 00000000..510e6419 Binary files /dev/null and b/docs/screenshots/impact-signals-grid.png differ diff --git a/docs/screenshots/impact-signals-livebar.png b/docs/screenshots/impact-signals-livebar.png new file mode 100644 index 00000000..c938d6af Binary files /dev/null and b/docs/screenshots/impact-signals-livebar.png differ diff --git a/docs/screenshots/impact-signals-modal.png b/docs/screenshots/impact-signals-modal.png new file mode 100644 index 00000000..1f841009 Binary files /dev/null and b/docs/screenshots/impact-signals-modal.png differ diff --git a/docs/screenshots/impact-signals-platforms.png b/docs/screenshots/impact-signals-platforms.png new file mode 100644 index 00000000..0b9e5eb3 Binary files /dev/null and b/docs/screenshots/impact-signals-platforms.png differ diff --git a/src/app/impact/page.tsx b/src/app/impact/page.tsx new file mode 100644 index 00000000..ec39b16d --- /dev/null +++ b/src/app/impact/page.tsx @@ -0,0 +1,124 @@ +import type { Metadata } from 'next' +import Breadcrumb from '@/components/Breadcrumb' +import ImpactDashboard, { type LiveMetric, type LiveOutputs } from '@/components/ImpactDashboard' +import MeasuringQuestions from '@/components/MeasuringQuestions' +import { fetchSimocracyStats } from '@/lib/simocracy' +import { fetchGainforestStats } from '@/lib/gainforest' +import { fetchGlowStats } from '@/lib/glow' +import { resolveAllSignals } from '@/lib/market-signals' +import { FIELD_COLOR, HAND_COLOR } from '@/lib/inflection-points' + +// Pull live output metrics for the Economies & Governance inflection points from +// the same sources as the FA2 live dashboard. These are Q3 OUTPUTS (the work +// PL-backed teams have produced) — never Q2 progress toward a threshold. +export const revalidate = 60 + +async function fetchLiveOutputs(): Promise { + const compact = (n: number) => + new Intl.NumberFormat('en-US', { notation: 'compact', maximumFractionDigits: 1 }).format(n) + const out: LiveOutputs = {} + + const [sim, gf, glow] = await Promise.allSettled([ + fetchSimocracyStats(), + fetchGainforestStats(), + fetchGlowStats(), + ]) + + // A binding decision at scale — Simocracy (a PL-supported deliberation mechanism). + if (sim.status === 'fulfilled' && !sim.value.degraded) { + const t = sim.value.totals + const metrics: LiveMetric[] = [ + { n: t.uniqueHumans, label: 'participants' }, + { n: t.totalSims, label: 'simulations' }, + { n: t.totalGatherings, label: 'gatherings' }, + ] + .filter((m) => m.n > 0) + .map((m) => ({ value: compact(m.n), label: m.label })) + if (metrics.length) out['A binding decision at scale'] = metrics + } + + // Capital that pays on verified outcomes — GainForest + Glow (PL-backed MRV teams). + const verified: LiveMetric[] = [] + if (gf.status === 'fulfilled' && !gf.value.degraded) { + const g = gf.value + if (g.observations > 0) verified.push({ value: compact(g.observations), label: 'species observations' }) + if (g.certifiedOrgs > 0) verified.push({ value: compact(g.certifiedOrgs), label: 'certified orgs' }) + } + if (glow.status === 'fulfilled' && !glow.value.degraded) { + const gl = glow.value + if (gl.activeFarms > 0) verified.push({ value: compact(gl.activeFarms), label: 'active solar farms' }) + if (gl.carbon > 0) verified.push({ value: compact(gl.carbon), label: 'tCO₂ / wk' }) + } + if (verified.length) out['Capital that pays on verified outcomes'] = verified + + return out +} + +export const metadata: Metadata = { + title: 'Impact', + description: + 'How we measure whether PL R&D’s work matters: the inflection points we have pre-registered across every focus area, and how we will know if they happen.', +} + +export default async function ImpactPage() { + const [liveOutputs, marketSignals] = await Promise.all([ + fetchLiveOutputs(), + resolveAllSignals(), + ]) + return ( +
+ {/* Hero */} +
+ +
+

+ Our impact +

+

+ Across our four focus areas we have named a small set of{' '} + inflection points — specific, + observable, falsifiable shifts we believe would be catalytic, and that have not yet + happened. +

+ + Our methodology + + + + +
+
+ + {/* Inflection points — grey full-bleed section to set it apart from the rest of the site */} +
+
+

+ Inflection points we are tracking +

+

+ Select a focus area. Each card shows the defined threshold (did it happen), the cascade we + expect if it matters, and the PL contribution we would trace. +

+ +
+
+ + {/* Our methodology */} +
+

Our methodology

+

+ For every inflection point we ask three questions — different jobs that should not be + collapsed into a single score. We hold two axes apart:{' '} + our hand (the work + we control) and{' '} + the field (the + change that follows, with or without us). +

+ +
+
+ ) +} diff --git a/src/app/insights/page.tsx b/src/app/insights/page.tsx index 54bfe72d..82da13e9 100644 --- a/src/app/insights/page.tsx +++ b/src/app/insights/page.tsx @@ -18,7 +18,12 @@ const FALLBACK_CARDS = { 'card-blog': { title: 'Blog' }, } -export default async function InsightsPage() { +export default async function InsightsPage({ + searchParams, +}: { + searchParams: Promise<{ area?: string }> +}) { + const { area: initialArea } = await searchParams const page = await fetchPage('insights') const hero = getSection(page, 'hero') const heroTitle = hero?.title || FALLBACK_HERO_TITLE @@ -109,7 +114,7 @@ export default async function InsightsPage() { )} - + diff --git a/src/components/ImpactDashboard.tsx b/src/components/ImpactDashboard.tsx new file mode 100644 index 00000000..362a6f90 --- /dev/null +++ b/src/components/ImpactDashboard.tsx @@ -0,0 +1,586 @@ +'use client' + +import { useEffect, useMemo, useState } from 'react' +import { + ROLE_META, + PL_ROLE_ORDER, + FIELD_COLOR, + HAND_COLOR, + LIVE_COLOR, + FIELD_STAGES, + FOCUS_AREAS, + INFLECTION_POINTS, + stageIndexForStatus, + type FocusAreaKey, + type InflectionPoint, + type PLRole, +} from '@/lib/inflection-points' +import { AreaIcon, type AreaIconType } from '@/components/AreaIcons' +import type { MarketSignal } from '@/lib/market-signals' + +type Filter = FocusAreaKey + +/** Live output metrics for a point, keyed by the point's title. Fetched server-side. */ +export type LiveMetric = { value: string; label: string } +export type LiveOutputs = Record +/** Prediction-market crowd signal per point, keyed by title. Fetched server-side. */ +export type MarketSignals = Record + +const PLATFORM_LABEL: Record<'polymarket' | 'kalshi', string> = { + polymarket: 'Polymarket', + kalshi: 'Kalshi', +} + +// Generic footnote for cards/points that surface a live signal. +const LIVE_SIGNAL_NOTE = + 'Live signals from a PL-supported mechanism. This may be limited to contribution evidence — not evidence of inflection point crossing.' + +const FA_ICON: Record = { + 'digital-human-rights': 'shield', + 'economies-governance': 'hexagon', + 'ai-robotics': 'neural', + neurotech: 'brain', +} + +export default function ImpactDashboard({ + liveOutputs = {}, + marketSignals = {}, +}: { + liveOutputs?: LiveOutputs + marketSignals?: MarketSignals +}) { + const [filter, setFilter] = useState('digital-human-rights') + const [active, setActive] = useState(null) + + const visible = useMemo( + () => INFLECTION_POINTS.filter((p) => p.area === filter), + [filter], + ) + + return ( +
+ {/* Vertical tabs */} +
+ {FOCUS_AREAS.map((fa) => ( + p.area === fa.key).length} + icon={FA_ICON[fa.key]} + active={filter === fa.key} + onClick={() => setFilter(fa.key)} + /> + ))} +
+ + {/* Content */} +
+ {visible.length > 0 ? ( +
+ {visible.map((p) => ( + setActive(p)} + /> + ))} +
+ ) : ( + + )} +
+ + {active && ( + setActive(null)} + /> + )} +
+ ) +} + +function Tab({ + label, + count, + active, + icon, + onClick, +}: { + label: string + count: number + active: boolean + icon?: AreaIconType + onClick: () => void +}) { + return ( + + ) +} + +/** Field-progress lifecycle meter — the “field” axis (teal). */ +function FieldMeter({ + status, + compact = false, +}: { + status: InflectionPoint['status'] + compact?: boolean +}) { + const reached = stageIndexForStatus(status) + return ( +
+
+ {FIELD_STAGES.map((_, i) => ( + + ))} +
+ {!compact && ( +
+ {FIELD_STAGES.map((s, i) => ( + + {s} + + ))} +
+ )} +
+ ) +} + +/** One pill per PL role, in canonical order. */ +function RoleChips({ roles, eyebrow = true }: { roles: PLRole[]; eyebrow?: boolean }) { + const ordered = PL_ROLE_ORDER.filter((r) => roles.includes(r)) + return ( + + {eyebrow && ( + PL role + )} + {ordered.map((r) => ( + + + {ROLE_META[r].label} + + + {ROLE_META[r].label} — {ROLE_META[r].description} + + + ))} + + ) +} + +/** Compact crowd-odds read for the FIELD axis on a card (non-interactive). */ +function CrowdSignalInline({ signal }: { signal: MarketSignal }) { + if (signal.match === 'gap') { + return ( +
+ + No market yet — unpriced bet +
+ ) + } + const pct = signal.prob != null ? Math.round(signal.prob * 100) : null + return ( +
+ + Crowd{signal.platform ? ` · ${PLATFORM_LABEL[signal.platform]}` : ''} + + {signal.question} + + {pct != null ? `${pct}%` : 'live'} + +
+ ) +} + +function InflectionCard({ + point, + metrics, + signal, + onOpen, +}: { + point: InflectionPoint + metrics?: LiveMetric[] + signal?: MarketSignal + onOpen: () => void +}) { + const fa = FOCUS_AREAS.find((f) => f.key === point.area)! + const stageLabel = FIELD_STAGES[stageIndexForStatus(point.status)] + + return ( + + ) +} + +/** Compact USD, e.g. $15k, $1.2M. */ +function formatUSD(n: number): string { + if (n >= 1_000_000) return `$${(n / 1_000_000).toFixed(n >= 10_000_000 ? 0 : 1)}M` + if (n >= 1_000) return `$${Math.round(n / 1_000)}k` + return `$${Math.round(n)}` +} + +/** Crowd-forecast row for the modal's horizontal Live-signal band (with market link). */ +function CrowdForecast({ signal, divider = false }: { signal: MarketSignal; divider?: boolean }) { + const pct = signal.prob != null ? Math.round(signal.prob * 100) : null + return ( +
+
+ + Crowd forecast + + {signal.platform && ( + + {PLATFORM_LABEL[signal.platform]} + {signal.viaFallback ? ' (fallback)' : ''} + + )} + {signal.volume != null && ( + + {formatUSD(signal.volume)} at stake + + )} + + {pct != null ? `${pct}%` : '—'} + +
+ {signal.url && ( + + {signal.question} + + )} +

+ {signal.note} Independent estimate on the field axis — not PL contribution, not a settled outcome. +

+
+ ) +} + +function InflectionModal({ + point, + metrics, + signal, + onClose, +}: { + point: InflectionPoint + metrics?: LiveMetric[] + signal?: MarketSignal + onClose: () => void +}) { + const fa = FOCUS_AREAS.find((f) => f.key === point.area)! + + // Close on Escape, and lock body scroll while open. + useEffect(() => { + const onKey = (e: KeyboardEvent) => { + if (e.key === 'Escape') onClose() + } + document.addEventListener('keydown', onKey) + const prev = document.body.style.overflow + document.body.style.overflow = 'hidden' + return () => { + document.removeEventListener('keydown', onKey) + document.body.style.overflow = prev + } + }, [onClose]) + + return ( +
+
e.stopPropagation()} + > + {/* Close */} + + +
+ {/* Header */} +
+ + + + {fa.label} + · + {point.opportunitySpace} +
+

+ {point.title} +

+ + {/* Field progress — full width */} +
+
+ Progress against Inflection Point +
+ +
+ + {/* Two axes: our hand | the field */} +
+ {/* OUR HAND */} +
+
Our hand
+
+ + How is PL making a difference? +
+
+
+
+
Inputs
+

{point.contribution.inputs}

+
+
+
Activities
+

{point.contribution.activities}

+
+
+
Outputs
+

{point.contribution.outputs}

+
+
+
+ + {/* THE FIELD */} +
+
The field
+
+ + Did it happen? +
+
Outcome — the inflection point
+

{point.signal}

+
+ + Did it matter? +
+
Impact — the cascade
+

{point.cascade}

+
+
+ + {/* Full-width Live-signal band: PL-backed live outputs (Q3) + crowd forecast (field axis). */} +
+ {(point.liveEvidence || (signal && signal.match !== 'gap')) && ( + + )} + + {signal && signal.match === 'gap' && ( +
+
+ Crowd forecast +
+

{signal.note}

+
+ )} + + + See the latest {fa.label} insights + + + + +
+
+
+
+ ) +} + +function QBadge({ letter, color }: { letter: string; color: string }) { + return ( + + {letter} + + ) +} + +function EmptyState({ filter }: { filter: Filter }) { + const fa = FOCUS_AREAS.find((f) => f.key === filter) + return ( +
+

+ Inflection points for {fa?.label ?? 'this focus area'} are being defined. +

+

+ This focus area is still finalizing its plan of attack. Its inflection points will appear + here once they are set. +

+
+ ) +} diff --git a/src/components/InsightsExplorer.tsx b/src/components/InsightsExplorer.tsx index 1b7b04d0..d6368a7c 100644 --- a/src/components/InsightsExplorer.tsx +++ b/src/components/InsightsExplorer.tsx @@ -31,12 +31,16 @@ const DISPLAY_LIMIT = 9 export default function InsightsExplorer({ sections, areas, + initialArea, }: { sections: InsightSection[] areas: AreaDef[] + initialArea?: string }) { const [type, setType] = useState(ALL) - const [area, setArea] = useState(ALL) + const [area, setArea] = useState( + initialArea && areas.some((a) => a.slug === initialArea) ? initialArea : ALL, + ) const matchArea = (tile: InsightTile, a: string) => a === ALL || tile.areas.includes(a) diff --git a/src/components/MeasuringQuestions.tsx b/src/components/MeasuringQuestions.tsx new file mode 100644 index 00000000..95307196 --- /dev/null +++ b/src/components/MeasuringQuestions.tsx @@ -0,0 +1,171 @@ +'use client' + +import { useEffect, useState } from 'react' +import { FIELD_COLOR, HAND_COLOR, ROLE_META, PL_ROLE_ORDER } from '@/lib/inflection-points' + +function Badge({ letter, color }: { letter: string; color: string }) { + return ( + + {letter} + + ) +} + +export default function MeasuringQuestions() { + const [rolesOpen, setRolesOpen] = useState(false) + + return ( + <> +
+ {/* A — our hand (whole card opens the roles modal) */} + + + {/* B — the field */} + + + {/* C — the field */} + +
+ + {rolesOpen && setRolesOpen(false)} />} + + ) +} + +function FieldCard({ + letter, + title, + eyebrow, + body, + footRest, +}: { + letter: string + title: string + eyebrow: string + body: string + footRest: string +}) { + return ( +
+
+ +

{title}

+
+
+ {eyebrow} +
+

{body}

+

+ The field. {footRest} +

+
+ ) +} + +function RolesModal({ onClose }: { onClose: () => void }) { + useEffect(() => { + const onKey = (e: KeyboardEvent) => { + if (e.key === 'Escape') onClose() + } + document.addEventListener('keydown', onKey) + const prev = document.body.style.overflow + document.body.style.overflow = 'hidden' + return () => { + document.removeEventListener('keydown', onKey) + document.body.style.overflow = prev + } + }, [onClose]) + + return ( +
+
e.stopPropagation()}> + + +
+ Question A · Our hand +
+

+ Six roles, matched to the bottleneck each one releases +

+

+ Every card tags the roles PL played. Match the instrument to the bottleneck — a point can + be reached with little PL involvement, which is still a win for the field, and we record + our role honestly. +

+ +
+ {PL_ROLE_ORDER.map((r) => ( +
+
+ + {ROLE_META[r].label} +
+

{ROLE_META[r].description}

+
+ ))} +
+ +

+ Each role answers a different bottleneck. On a card, the tags under “our hand” + tell you which ones PL brought to that specific inflection point. +

+
+
+ ) +} diff --git a/src/lib/inflection-points.ts b/src/lib/inflection-points.ts new file mode 100644 index 00000000..7d69cc33 --- /dev/null +++ b/src/lib/inflection-points.ts @@ -0,0 +1,386 @@ +// Cross-focus-area inflection points and how we measure them. +// +// Each focus area names a small set of inflection points: specific, observable, +// falsifiable shifts we believe would be catalytic and that have NOT yet happened +// as of 2026. They are hypotheses, not descriptions of the present. We judge our +// work against three questions, mapped to the fields on every point: +// +// Q1 (cascade) Did it matter? The second-order effects it should unlock. +// Q2 (signal) Did it happen? A pre-registered threshold — yes/no + date. +// Q3 (contribution) Did our work make it happen? PL's inputs -> activities -> outputs on the +// critical path (the planned-work side of the +// logic model), traced honestly. +// +// IMPORTANT — these are distinct jobs and are NOT collapsed into one score. A point +// can be reached (Q2) and matter (Q1) with low PL contribution (Q3); that is still a +// win for the field. So we track field progress (Q1 & Q2) on one axis and PL's +// contribution (Q3) on a separate, independent axis. +// +// Source: "Inflection points across PL R&D, and how we will measure them." + +export type InflectionStatus = 'watching' | 'early-signal' | 'tripped' + +/** PL's pre-registered role(s) on the critical path — claims to be evidenced, not a credit score. */ +export type PLRole = 'infrastructure' | 'legibility' | 'connection' | 'capital' | 'translation' | 'permission' + +/** Canonical display order for role pills, so cards read consistently. */ +export const PL_ROLE_ORDER: PLRole[] = ['infrastructure', 'legibility', 'connection', 'capital', 'translation', 'permission'] + +// Two-axis color system used across the impact dashboard: +// FIELD = the change in the world (outcomes + impact) — moves with or without us (black) +// HAND = our planned work / the PL toolkit — the axis we control with partners (PL blue) +export const FIELD_COLOR = '#131316' +export const HAND_COLOR = '#1982F4' +/** Live-signal accent — the pulsing dot on points with live outputs (green). */ +export const LIVE_COLOR = '#22c55e' + +/** + * Q3 contribution, structured along the planned-work side of the logic model. + * Inputs (resources committed) -> Activities (what we do) -> Outputs (what gets produced). + * The outcomes and impact these aim at are tracked on the field axis (Q2, Q1). + */ +export type Contribution = { + inputs: string + activities: string + outputs: string +} + +/** A pointer to live activity that is contribution evidence (Q3) — NOT a Q2 threshold reading. */ +export type LiveEvidence = { + label: string + href: string + note: string +} + +export type InflectionPoint = { + /** Focus-area slug, matches /areas/. */ + area: FocusAreaKey + /** The opportunity space this bet lives in. */ + opportunitySpace: string + /** The inflection point, stated as a hypothesis. */ + title: string + /** Q2 — observable threshold that says it happened (not yet true). */ + signal: string + /** Q1 — why it matters / the cascade to watch. */ + cascade: string + /** Q3 — PL contribution to trace, as inputs -> activities -> outputs. */ + contribution: Contribution + /** Q3, summarized as the PL role(s) on the critical path — the instruments we bring. */ + roles: PLRole[] + /** Field-progress lifecycle state. All start 'watching' — none reached as of 2026. */ + status: InflectionStatus + /** Optional live activity from PL-backed teams — strictly Q3 evidence, never Q2 progress. */ + liveEvidence?: LiveEvidence +} + +export type FocusAreaKey = + | 'digital-human-rights' + | 'economies-governance' + | 'ai-robotics' + | 'neurotech' + +export type FocusAreaMeta = { + key: FocusAreaKey + label: string + /** Short legacy code used in the strategy docs. */ + code: string + href: string + /** Accent color (hex from the theme) for badges and the field-progress meter. */ + accent: string +} + +export const FOCUS_AREAS: FocusAreaMeta[] = [ + { key: 'digital-human-rights', label: 'Digital Human Rights', code: 'FA1', href: '/areas/digital-human-rights/', accent: '#1982F4' }, + { key: 'economies-governance', label: 'Economies & Governance', code: 'FA2', href: '/areas/economies-governance/', accent: '#12bfdf' }, + { key: 'ai-robotics', label: 'AI & Robotics', code: 'FA3', href: '/areas/ai-robotics/', accent: '#3966FE' }, + { key: 'neurotech', label: 'Neurotech', code: 'FA4', href: '/areas/neurotech/', accent: '#E51A66' }, +] + +// The logic-model chain: planned work (inputs/activities/outputs) → intended +// results (outcomes/impact). Shared by the Measuring-impact section, the three- +// questions explainer, and the per-point detail modal so the vocabulary lives +// in one place. +export const LOGIC_MODEL = [ + { key: 'inputs', label: 'Inputs', body: 'Funding, teams, convenings, standards we commit.' }, + { key: 'activities', label: 'Activities', body: 'Seeding teams, building primitives, setting standards.' }, + { key: 'outputs', label: 'Outputs', body: 'Teams funded, deployments, papers, ventures.' }, + { key: 'outcomes', label: 'Outcomes', body: 'Adoption, capital inflows, new entrants.' }, + { key: 'impact', label: 'Impact', body: 'The lasting shift: an inflection point that holds.' }, +] as const +export type LogicStageKey = (typeof LOGIC_MODEL)[number]['key'] + +// ── Field-progress lifecycle (Q1 & Q2). Deliberately separate from PL contribution. ── +export const FIELD_STAGES = ['Defined', 'Emerging', 'Reached', 'Scaling'] as const +export type FieldStage = (typeof FIELD_STAGES)[number] + +/** How far along the field axis a point sits, given its status. */ +export function stageIndexForStatus(status: InflectionStatus): number { + switch (status) { + case 'watching': + return 0 // threshold defined, waiting at it + case 'early-signal': + return 1 + case 'tripped': + return 2 + } +} + +export const STATUS_META: Record = { + watching: { + label: 'Defined', + description: 'The threshold is defined and pre-registered. No movement toward it yet.', + color: '#6b6d79', + }, + 'early-signal': { + label: 'Emerging', + description: 'Leading indicators are moving toward the threshold.', + color: '#1982F4', + }, + tripped: { + label: 'Reached', + description: 'The defined threshold has been crossed.', + color: '#12bfdf', + }, +} + +export const ROLE_META: Record = { + infrastructure: { + label: 'Infrastructure', + description: 'The open, neutral rail this runs on did not exist. PL builds and maintains it (libp2p / IPFS / Filecoin lineage).', + }, + legibility: { + label: 'Legibility', + description: 'The field lacked a shared map. PL adds roadmaps, taxonomies, benchmarks, and written artifacts.', + }, + connection: { + label: 'Connection', + description: 'Too few connections blocked progress. PL convenes the people who need to collide: dinners, retreats, residencies, hackathons.', + }, + capital: { + label: 'Capital', + description: 'Pre-commercial work needed patient funding. PL runs grants and prizes and helps peer funders deploy theirs.', + }, + translation: { + label: 'Translation', + description: 'The work was ready to leave the lab. PL helps convert it into ventures, pilots, and deployments.', + }, + permission: { + label: 'Permission', + description: 'The rules did not yet recognize the technology. PL engages standards, policy, and regulatory pathways.', + }, +} + +export const INFLECTION_POINTS: InflectionPoint[] = [ + // ── FA1 · Digital Human Rights ─────────────────────────────────────────── + { + area: 'digital-human-rights', + opportunitySpace: 'Censorship-Resistant Communication', + title: 'Communication that cannot be switched off', + signal: + 'A consumer-scale connectivity provider operates without state licensing or identity gating, and a metadata-resistant messenger crosses tens of millions of users; a population stays connected through a deliberate shutdown.', + cascade: + 'Censoring speech and assembly becomes impractical, not just illegal; organizing survives adversarial conditions.', + contribution: { + inputs: 'The libp2p / IPFS open-source networking stack; funding for resilient-comms and private-messaging teams.', + activities: 'Maintaining the substrate, funding teams, and contributing to interoperability standards.', + outputs: 'libp2p / IPFS deployments and the funded comms and messaging teams building on them.', + }, + roles: ['infrastructure', 'capital'], + status: 'early-signal', + }, + { + area: 'digital-human-rights', + opportunitySpace: 'Portable Identity, Credentials & Trust', + title: 'Personhood without the state in the loop', + signal: + 'A service at >100M people verifies unique humans for everyday use without a nation-state ID or KYC.', + cascade: + 'Recognition stops being rented from platforms and states; privacy-preserving personhood becomes safe to build on.', + contribution: { + inputs: 'Convening capacity across identity protocols; seed funding for portable-credential initiatives.', + activities: 'Convening identity-protocol teams and seeding / funding portable-credential work.', + outputs: 'The identity and credential initiatives PL has seeded or funded.', + }, + roles: ['connection', 'capital'], + status: 'watching', + }, + { + area: 'digital-human-rights', + opportunitySpace: 'Verifiable Public Knowledge & Provenance', + title: 'Provenance becomes the default for truth', + signal: + 'Two consecutive frontier-model generations ship attested provenance by default, and a major platform or archive adopts content-addressed provenance as default.', + cascade: + 'A public record that can prove its own integrity becomes the precondition for trustworthy information in the AI era.', + contribution: { + inputs: 'Content addressing (IPFS) as the provenance substrate; funding for provenance and verifiable-compute teams.', + activities: 'Providing the content-addressing substrate and backing provenance / verifiable-compute teams.', + outputs: 'Content-addressed provenance tooling and the PL-backed teams building it.', + }, + roles: ['infrastructure', 'capital'], + status: 'early-signal', + }, + { + area: 'digital-human-rights', + opportunitySpace: 'Sovereign Infrastructure for AI & Agents', + title: 'Agents run on open rails', + signal: + 'A frontier-scale model is trained across independent decentralized hardware, or a meaningful share of agent-to-agent economic activity settles on open permissionless compute / storage / identity.', + cascade: + 'The rights architecture of the agent economy is set in the open rather than by whoever owns the cluster.', + contribution: { + inputs: 'The Filecoin / open-compute portfolio; PL capital and coordination across storage, compute, and identity.', + activities: 'Building open compute and storage rails and bridging them with identity for agents.', + outputs: 'Filecoin and the open-compute portfolio; integrations across storage, compute, and identity.', + }, + roles: ['infrastructure', 'connection', 'capital'], + status: 'watching', + }, + + // ── FA2 · Economies & Governance ───────────────────────────────────────── + { + area: 'economies-governance', + opportunitySpace: 'Sovereign Digital Public Infrastructure', + title: 'Programmable government in production', + signal: + 'At least one sovereign moves >$1B/yr of real public funds through programmable, real-time-auditable rails; 3+ jurisdictions use selective-disclosure credentials for a high-stakes function (election, passport, census).', + cascade: + 'Digital government crosses from digitization to transformation; a reference deployment others can copy.', + contribution: { + inputs: 'Standards and procurement playbooks; convening capacity with sovereigns and builders; funding for DPI primitives.', + activities: 'Writing standards and playbooks, convening sovereigns with builders, and funding DPI primitives.', + outputs: 'Published playbooks, convened sovereign–builder cohorts, and funded DPI primitives.', + }, + roles: ['connection', 'capital', 'permission'], + status: 'watching', + }, + { + area: 'economies-governance', + opportunitySpace: 'Computational Coordination & Governance', + title: 'A binding decision at scale', + signal: + 'A city or government makes a consequential, binding decision through a computational mechanism with tens of thousands participating, beating the legacy process on cost, turnout, or trust.', + cascade: + 'Deliberation tools move from advisory to part of real decision-making infrastructure.', + contribution: { + inputs: 'Support for computational-deliberation mechanisms (e.g. Simocracy, broad-listening tools); convening capacity.', + activities: 'Supporting mechanism teams and convening government teams with tool teams.', + outputs: 'Simocracy and broad-listening tools, and the government–tool convenings around them.', + }, + roles: ['connection', 'capital'], + status: 'watching', + liveEvidence: { + label: 'Simocracy governance simulation — live participation', + href: '/areas/economies-governance/impact/live-dashboard/', + note: 'Live activity from a PL-supported mechanism. This is contribution evidence (Q3) from a simulation — not the binding-decision-in-government threshold (Q2).', + }, + }, + { + area: 'economies-governance', + opportunitySpace: 'Programmable Capital Allocation', + title: 'Public goods become a financeable category', + signal: + '>$1B/yr flows through programmable allocation, a mainstream allocator (DFI, pension, sovereign fund) treats it as infrastructure, and a material real-world outcome is documented.', + cascade: + 'Funding public goods becomes a durable capital market rather than a niche.', + contribution: { + inputs: 'Hypercerts (PL origin) and the Gitcoin / Funding-the-Commons lineage; PL evidence and standards work.', + activities: 'Originating allocation mechanisms, building evidence and standards, and converting work into ventures.', + outputs: 'Hypercerts, Funding the Commons, and the ventures spun out of this lineage.', + }, + roles: ['infrastructure', 'capital', 'translation'], + status: 'early-signal', + }, + { + area: 'economies-governance', + opportunitySpace: 'Verifiable Real-World Infrastructure & Systems', + title: 'Capital that pays on verified outcomes', + signal: + 'A $1B+ climate or public-goods fund disburses against independently verified real-world outcomes, faster and cheaper than a legacy audit.', + cascade: + 'Verification becomes the rail capital runs on; the loop back to better decisions closes.', + contribution: { + inputs: 'Funding for MRV / outcome-verification teams (e.g. GainForest, Glow); benchmark and standards convening.', + activities: 'Backing MRV teams and convening benchmark and standards work for outcome verification.', + outputs: 'GainForest, Glow, and the verification benchmarks and standards they inform.', + }, + roles: ['legibility', 'connection', 'capital'], + status: 'early-signal', + liveEvidence: { + label: 'GainForest & Glow — live verification activity', + href: '/areas/economies-governance/impact/live-dashboard/', + note: 'Live output from PL-backed MRV teams on this critical path. Contribution evidence (Q3) — not the $1B-disbursed-against-verified-outcomes threshold (Q2).', + }, + }, + + // ── FA4 · Neurotech ────────────────────────────────────────────────────── + { + area: 'neurotech', + opportunitySpace: 'Neural Augmentation (BCI)', + title: 'The BCI app store', + signal: + 'A regulator clears a standardized software / API layer for a commercial BCI (with medical guardrails), and the first third-party app launches and is adopted.', + cascade: + 'BCI value compounds after surgery; a developer ecosystem forms; demand shifts toward elective use.', + contribution: { + inputs: 'PL Neuro standards work for a BCI component ecosystem; convening capacity across regulators, device makers, and developers.', + activities: 'Defining the BCI component-ecosystem standard and convening regulators, makers, and developers.', + outputs: 'A draft BCI component / API standard and the regulator–maker–developer convenings around it.', + }, + roles: ['connection', 'permission'], + status: 'watching', + }, + { + area: 'neurotech', + opportunitySpace: 'Biologically Inspired Intelligence (NeuroAI)', + title: 'Neural distillation', + signal: + 'A major lab matches frontier reasoning by training on human neural data at a fraction of the parameters / energy, or venture funding surges into consumer EEG to harvest cognitive data for AI.', + cascade: + 'High-fidelity neural data becomes as valuable to AI as text; comp-neuro talent flow reverses.', + contribution: { + inputs: 'The PL Neuro talent network bridging AI labs and comp neuro; investment in neural-data infrastructure and norms.', + activities: 'Bridging AI-lab and comp-neuro talent and building neural-data infrastructure and norms.', + outputs: 'The PL Neuro talent network and the neural-data infrastructure and norms it seeds.', + }, + roles: ['infrastructure', 'connection', 'capital'], + status: 'watching', + }, + { + area: 'neurotech', + opportunitySpace: 'Biologically Inspired Intelligence (NeuroAI)', + title: 'The neuromorphic energy pivot', + signal: + 'A brain-inspired model matches state-of-the-art performance at 3+ orders of magnitude better energy efficiency, and frontier labs begin acquiring neuromorphic startups.', + cascade: + 'Neurally derived design becomes foundational to commercial AI; AI is tethered to neuroscience.', + contribution: { + inputs: 'Funding for NeuroAI / neuromorphic research and demos; benchmark design defining the efficiency target.', + activities: 'Funding neuromorphic research and demos and defining the efficiency benchmark.', + outputs: 'PL-funded NeuroAI demos and the energy-efficiency benchmarks that frame the target.', + }, + roles: ['legibility', 'capital'], + status: 'watching', + }, + { + area: 'neurotech', + opportunitySpace: 'Whole Organism Emulation (WBE)', + title: 'Memory retrieval in simulation', + signal: + 'A reconstructed mouse connectome simulated in silico reproduces a specific behavior the biological mouse learned before its connectome was harvested.', + cascade: + 'WBE turns from speculation into a benchmarked engineering discipline; serious policy engagement begins.', + contribution: { + inputs: 'PL Neuro benchmark definition; connectomics workshops and throughput targets; engineering capacity for a demo.', + activities: 'Defining the WBE benchmark, running connectomics workshops, and engineering a reference demo.', + outputs: 'The WBE benchmark, connectomics throughput targets, and a PL-engineered demo.', + }, + roles: ['legibility', 'connection'], + status: 'watching', + }, +] + +export function pointsForArea(area: FocusAreaKey | 'all'): InflectionPoint[] { + if (area === 'all') return INFLECTION_POINTS + return INFLECTION_POINTS.filter((p) => p.area === area) +} diff --git a/src/lib/market-signals.ts b/src/lib/market-signals.ts new file mode 100644 index 00000000..050cf05f --- /dev/null +++ b/src/lib/market-signals.ts @@ -0,0 +1,300 @@ +// Prediction-market "field" signal for each inflection point. +// +// Each inflection point can be paired with the prediction market that most +// closely matches its pre-registered threshold (Q2). The platform is chosen per +// point on match quality, NOT convenience: +// - Polymarket — deepest liquidity for crypto/AI/identity/BCI-valuation themes. +// - Kalshi — regulated venue; better for US-regulatory / adoption-count themes. +// +// A market read is an *external, independent* estimate on the FIELD axis +// ("will it happen?") — it is never PL contribution (Q3) and never a settled Q2. +// Where no market exists, that gap is itself informative: the bet is early or +// contrarian enough that no one is pricing it yet. + +export type Platform = 'polymarket' | 'kalshi' +export type SignalMatch = 'direct' | 'proxy' | 'gap' + +type MarketRef = + | { platform: 'polymarket'; slug: string; hint?: string; question: string; url: string } + | { platform: 'kalshi'; ticker: string; question: string; url: string } + +export type MarketMapping = { + /** Must match InflectionPoint.title exactly. */ + title: string + match: SignalMatch + /** Best-match market (drives the platform label). Omitted for gaps. */ + primary?: MarketRef + /** Liquidity fallback used only if the primary returns no live price. */ + fallback?: MarketRef + note: string +} + +export type MarketSignal = { + match: SignalMatch + platform: Platform | null + /** 0..1 crowd "yes" probability, or null when unavailable. */ + prob: number | null + /** Total money traded through the market, in USD, or null when unavailable. */ + volume: number | null + question: string | null + url: string | null + /** True when prob came from the fallback rather than the best-match market. */ + viaFallback: boolean + note: string +} + +// ── Mapping: inflection point → closest market ──────────────────────────────── +export const MARKET_MAPPINGS: MarketMapping[] = [ + { + title: 'Communication that cannot be switched off', + match: 'gap', + note: 'No liquid market prices a metadata-resistant messenger at scale or surviving a shutdown — a genuine white space.', + }, + { + title: 'Personhood without the state in the loop', + match: 'proxy', + primary: { + platform: 'polymarket', + slug: 'over-30m-humans-verified-on-world-network-by-december-31', + question: 'Over 30M humans verified on World Network by Dec 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 closest live analogue; Polymarket has the deepest World/identity liquidity.', + }, + { + title: 'Provenance becomes the default for truth', + match: 'proxy', + primary: { + platform: 'kalshi', + ticker: 'KXAILEGISLATION-27-JAN01', + question: 'Will AI regulation become US law by 2027?', + url: 'https://kalshi.com/markets/kxailegislation/ai-regulation', + }, + note: 'Provenance mandates ride on AI regulation; Kalshi (regulated, US-policy focus) is the better-matched venue than any crypto market.', + }, + { + title: 'Agents run on open rails', + match: 'proxy', + primary: { + platform: 'polymarket', + slug: 'will-a-chinese-company-have-the-best-ai-model-by-december-31', + question: 'Will an open-weights model be the best AI model by Dec 31?', + url: 'https://polymarket.com/event/will-a-chinese-company-have-the-best-ai-model-by-december-31', + }, + note: 'Open-weights reaching the frontier is the best proxy for open/decentralized rails; Kalshi KXTOPAI (LM Arena) is the regulated alternative.', + }, + { + title: 'Programmable government in production', + match: 'proxy', + primary: { + platform: 'polymarket', + slug: 'over-30m-humans-verified-on-world-network-by-december-31', + question: 'Over 30M humans verified on World Network by Dec 31?', + url: 'https://polymarket.com/event/over-30m-humans-verified-on-world-network-by-december-31', + }, + note: 'Shares the World market — “World becomes a mandated digital-identity layer” is one of our own DPI examples. No market yet prices $1B/yr on programmable rails directly.', + }, + { + title: 'A binding decision at scale', + match: 'gap', + note: 'No market prices a binding, at-scale computational decision. We already surface a live Simocracy signal here (Q3 contribution, not Q2).', + }, + { + title: 'Public goods become a financeable category', + match: 'gap', + note: 'No liquid market prices $1B/yr flowing through programmable allocation — long-horizon white space.', + }, + { + title: 'Capital that pays on verified outcomes', + match: 'gap', + note: 'No market prices a $1B+ outcomes-verified climate fund. GainForest / Glow live outputs already appear here as Q3 evidence.', + }, + { + title: 'The BCI app store', + match: 'proxy', + primary: { + platform: 'kalshi', + ticker: 'KXNEURALINKCOUNT-26-40', + question: 'Will Neuralink implant ≥40 people in 2026?', + url: 'https://kalshi.com/markets/kxneuralinkcount/neuralink-count', + }, + fallback: { + platform: 'polymarket', + slug: 'will-neuralinks-valuation-hit-by-december-31', + hint: '$75B', + question: "Will Neuralink's valuation hit $75B by Dec 31?", + url: 'https://polymarket.com/event/will-neuralinks-valuation-hit-by-december-31', + }, + note: 'Implant-count (Kalshi) is the best adoption/scaling proxy for a commercial BCI ecosystem; Polymarket valuation is the liquidity fallback.', + }, + { + title: 'Neural distillation', + match: 'gap', + note: 'No market prices neural-data distillation matching frontier reasoning — too early to be liquid.', + }, + { + title: 'The neuromorphic energy pivot', + match: 'gap', + note: 'No market prices a neuromorphic model matching SOTA at 1000× efficiency — pure white space.', + }, + { + title: 'Memory retrieval in simulation', + match: 'gap', + note: 'No market prices whole-organism emulation reproducing learned behavior — the most contrarian bet, unpriced.', + }, +] + +export function mappingByTitle(): Record { + return Object.fromEntries(MARKET_MAPPINGS.map((m) => [m.title, m])) +} + +// ── Fetchers ───────────────────────────────────────────────────────────────── +const GAMMA = 'https://gamma-api.polymarket.com' +const KALSHI = 'https://api.elections.kalshi.com/trade-api/v2' +const REVALIDATE = 3600 + +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 + } +} + +function distinctiveToken(s?: string): string | null { + if (!s) return 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 +} + +type Quote = { prob: number; volume: number | null } + +async function fetchPolymarket(slug: string, hint?: string): Promise { + try { + const res = await fetch(`${GAMMA}/events?slug=${encodeURIComponent(slug)}`, { + next: { revalidate: REVALIDATE }, + }) + if (!res.ok) return null + const events = (await res.json()) as Array<{ + title?: string + markets?: Array<{ question?: string; outcomes?: string; outcomePrices?: string; volumeNum?: number }> + }> + const markets = events?.[0]?.markets + if (!markets?.length) return null + const parsed = 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 + const volume = typeof m.volumeNum === 'number' && m.volumeNum > 0 ? m.volumeNum : null + return { yes, volume, q: (m.question || '').toLowerCase() } + }) + .filter((x): x is { yes: number; volume: number | null; q: string } => x != null) + if (!parsed.length) return null + const token = distinctiveToken(hint) + const pick = (token && parsed.find((m) => m.q.includes(token))) || parsed[0] + return { prob: pick.yes, volume: pick.volume } + } catch { + return null + } +} + +async function fetchKalshi(ticker: string): Promise { + try { + const res = await fetch(`${KALSHI}/markets/${encodeURIComponent(ticker)}`, { + next: { revalidate: REVALIDATE }, + }) + if (!res.ok) return null + const m = ((await res.json()) as { market?: Record }).market + if (!m) return null + // dollar_volume is in USD; volume is in contracts (each settles $0-$1), so the + // contract count is a reasonable USD upper bound when no dollar figure is given. + const dollarVol = m.dollar_volume + const contractVol = m.volume + const volume = + typeof dollarVol === 'number' && dollarVol > 0 + ? dollarVol + : typeof contractVol === 'number' && contractVol > 0 + ? contractVol + : null + // Prices are in cents (0-100). Prefer last trade, else the bid/ask midpoint. + const last = m.last_price + if (typeof last === 'number' && last > 0) return { prob: last / 100, volume } + const bid = m.yes_bid + const ask = m.yes_ask + if (typeof bid === 'number' && typeof ask === 'number' && (bid > 0 || ask > 0)) { + return { prob: (bid + ask) / 2 / 100, volume } + } + return null + } catch { + return null + } +} + +async function fetchRef(ref: MarketRef): Promise { + return ref.platform === 'polymarket' + ? fetchPolymarket(ref.slug, ref.hint) + : fetchKalshi(ref.ticker) +} + +/** Resolve one mapping into a display-ready signal (best-match, with fallback). */ +export async function resolveSignal(m: MarketMapping): Promise { + if (m.match === 'gap' || !m.primary) { + return { match: 'gap', platform: null, prob: null, volume: null, question: null, url: null, viaFallback: false, note: m.note } + } + const primary = await fetchRef(m.primary) + if (primary != null) { + return { + match: m.match, + platform: m.primary.platform, + prob: primary.prob, + volume: primary.volume, + question: m.primary.question, + url: m.primary.url, + viaFallback: false, + note: m.note, + } + } + if (m.fallback) { + const fb = await fetchRef(m.fallback) + if (fb != null) { + return { + match: m.match, + platform: m.fallback.platform, + prob: fb.prob, + volume: fb.volume, + question: m.fallback.question, + url: m.fallback.url, + viaFallback: true, + note: m.note, + } + } + } + // Market exists but no live price available — still link it. + return { + match: m.match, + platform: m.primary.platform, + prob: null, + volume: null, + question: m.primary.question, + url: m.primary.url, + viaFallback: false, + note: m.note, + } +} + +/** Resolve every mapping, keyed by inflection-point title. */ +export async function resolveAllSignals(): Promise> { + const entries = await Promise.all( + MARKET_MAPPINGS.map(async (m) => [m.title, await resolveSignal(m)] as const), + ) + return Object.fromEntries(entries) +} diff --git a/src/lib/site-config.ts b/src/lib/site-config.ts index 72a2bd97..a56a4a8c 100644 --- a/src/lib/site-config.ts +++ b/src/lib/site-config.ts @@ -35,6 +35,7 @@ export const mainNav: NavItem[] = [ { name: 'Neurotech', url: '/areas/neurotech/' }, ], }, + { name: 'Impact', url: '/impact/' }, { name: 'Insights', url: '/insights/' }, { name: 'Team', url: '/authors/' }, ]