import type { Metadata } from 'next'; import Link from 'next/link'; import { TierBadge } from '@/components/ui/badges'; import { DataTable, Td, Th } from '@/components/ui/data-table'; import { Container, PageHeader, Section } from '@/components/ui/section'; import { Unavailable } from '@/components/ui/unavailable'; import { api, safe } from '@/lib/api'; import { fmtAgo, fmtInt, humanize } from '@/lib/format'; import { eventLabel, routes, TIER_LABELS } from '@/lib/site'; import type { Methodology } from '@/lib/types'; export const metadata: Metadata = { title: 'Methodology — provenance, tiers, confidence, quality score, events', description: 'How AI Atlas records facts: source tiers, confidence levels, temporal claims, conflict handling, the data-quality score, change events and estimates.', alternates: { canonical: '/methodology' } }; export const revalidate = 3600; /** The API may return dicts or lists for these vocabularies; normalise to rows. */ function rows(v: unknown, keyName: string): { key: string; label?: string; description?: string; extra?: Record }[] { if (!v) return []; if (Array.isArray(v)) return v.map((x) => (typeof x === 'string' ? { key: x } : { key: String((x as Record)[keyName] ?? (x as Record).key ?? (x as Record).name ?? ''), label: (x as Record).label as string | undefined, description: ((x as Record).description ?? (x as Record).text) as string | undefined, extra: x as Record })); if (typeof v === 'object') return Object.entries(v as Record).map(([k, d]) => (typeof d === 'string' ? { key: k, description: d } : { key: k, ...(d as Record), extra: d as Record })); return []; } export default async function MethodologyPage() { const m: Methodology | null = await safe(api.methodology()); const tiers = rows(m?.tiers, 'tier'); const conf = rows(m?.confidence_levels, 'key'); const events = rows(m?.event_types, 'event_type'); const extractors = rows(m?.extractors, 'key'); return (

AI Atlas is built from first-party connectors that read public documents directly: official documentation, pricing pages, model cards, release notes, papers, feeds, sitemaps and repositories. Nothing depends on a third-party data API. Every document is snapshotted and archived; every fact points back to a snapshot.

Facts are temporal claims: a property, a value, a source, a tier, a confidence, an extractor and a validity interval. When a better-or-equal source states a new value, the old claim is superseded (its interval closes) and the new one becomes current. When a worse source disagrees, the value is stored as conflicting and flagged for review — it is never averaged or silently overwritten. Missing means missing: the site shows “Unavailable” rather than a guess.

{m && tiers.length ? ( TierMeaningDescription {tiers.map((t, i) => ( {t.label ?? TIER_LABELS[Number(t.key)] ?? humanize(t.key)} {t.description ?? '—'} ))} ) : m ? (
    {[1, 2, 3, 4].map((t) =>
  • {TIER_LABELS[t]}
  • )}
) : ( )}

A tier 1 source is the entity's own publisher (a lab's documentation, a provider's pricing page, an arXiv listing for a paper). Tier 2 are quality secondary sources, tier 3 community sources, tier 4 unverified. A higher tier can supersede a lower one; the reverse produces a flagged conflict.

{m && conf.length ? (
{conf.map((c, i) => (
{c.key}
{c.description ?? c.label ?? '—'}
))}
) : ( )}

Default confidence follows the tier (tier 1 → high, tier 2 → medium, tiers 3–4 → low). A claim becomes conflicted when a current value is contradicted by another source. Extractors can raise confidence to verified when a value is confirmed by several independent tier 1–2 sources.

quality.score = 100 × (0.25 completeness + 0.25 primary-source ratio + 0.20 freshness + 0.15 agreement + 0.15 source diversity). It says how well AI Atlas knows an entity — how many expected attributes are filled, how much comes from tier 1, how recently it was re-observed, how few conflicts remain and how many independent sources agree. It says nothing about whether a model is good.

{m && m.metrics?.length > 0 && ( MetricDefinitionVersion {m.metrics.map((x, i) => ( {String(x.key ?? x.name ?? '—')} {String(x.description ?? x.formula ?? x.label ?? '—')}{x.unit ? · {String(x.unit)} : null} {x.version !== undefined ? String(x.version) : '—'} ))} )}

Material properties — context length, status, license, openness, parameters, release date, deprecation and retirement dates, versions, prices — emit events when they change. Noisy metrics (downloads, likes, stars) are stored as time series and never generate events. Descriptions and other soft text follow their own source without events. Each event has a category and an importance from 0 (minor) to 3 (major), and links to the source document that triggered it.

{m && events.length ? ( Event typeLabelCategoryRecordedLast seen {events.map((e, i) => ( {e.key} {e.label ?? e.description ?? eventLabel(e.key)} {String(e.extra?.category ?? '—')} {e.extra?.count !== undefined ? fmtInt(e.extra.count) : e.extra?.importance !== undefined ? `importance ${String(e.extra.importance)}` : '—'} {typeof e.extra?.last_seen_at === 'string' ? fmtAgo(e.extra.last_seen_at) : '—'} ))} ) : ( )}

Stage 1 runs on every document: DOM selectors, JSON-LD, tables, Markdown, feeds. Only documents flagged as needing it go to the local LLM factory (MacLustr, OpenAI-compatible), through versioned schemas with full token accounting. LLM-extracted values are marked as such in provenance. Improving a parser bumps its version and reprocesses archived snapshots — never a re-crawl.

{m && extractors.length > 0 && (
{extractors.map((x, i) => (
{x.key}
{x.description ?? x.label ?? '—'}
))}
)}

Benchmark results are append-only and carry their configuration (harness, prompting, number of shots, judge). Leaderboards rank current rows under the benchmark's own direction; results with different configurations are shown with their config so the reader can judge comparability. We do not compute composite indices.

The only derived figures on AI Atlas are hardware-fit estimates: memory need ≈ parameters × bytes per parameter (4-bit 0.5 × 1.15 overhead, 8-bit 1.0, fp16 2.0) plus a KV-cache allowance for the chosen context. They are labelled Estimated everywhere and never mixed with observed facts.

Connectors honour robots.txt, use per-domain rate limits and conditional requests, identify as AIAtlasBot, never bypass access controls and never collect private data. The list of sources and connector health is public on /sources.

); }