SPB Git forge

spb/ai-atlas

Public
41commits 1branches 0releases
4.6 MBsize
maindefault branch
12 days agolast push
HTML 77.2% TypeScript 10.5% Python 9.6% JavaScript 2.5%
12.5 KB · 188 lines tsx
Raw Blame History
1import type { Metadata } from 'next';2import Link from 'next/link';3import { AdminTitle, JsonPre, KindChip, Mono, Notice, StatusChip } from '@/components/admin/ui';4import { DataTable, EmptyRow, Td, Th } from '@/components/ui/data-table';5import { Note } from '@/components/ui/section';6import { Unavailable } from '@/components/ui/unavailable';7import { adminApi, load, requireAdmin } from '@/lib/admin/admin-api';8import type { AdminQuality, CountSample } from '@/lib/admin/types';9import { cn } from '@/lib/cn';10import { fmtAgo, fmtInt, num } from '@/lib/format';11import { routes } from '@/lib/site';1213export const metadata: Metadata = { title: 'Data quality', robots: { index: false, follow: false } };14export const dynamic = 'force-dynamic';1516type Tile = { key: string; label: string; count: number | null; sample: unknown[]; href?: string; tone: 'neutral' | 'warn' | 'danger'; hint: string };1718function tile(key: string, label: string, cs: CountSample<unknown> | undefined, hint: string, opts: { href?: string; danger?: number } = {}): Tile {19  const count = num(cs?.count);20  const tone: Tile['tone'] = count === null || count === 0 ? 'neutral' : opts.danger !== undefined && count >= opts.danger ? 'danger' : 'warn';21  return { key, label, count, sample: (cs?.sample ?? []) as unknown[], href: opts.href, tone, hint };22}2324function SampleRow({ s }: { s: unknown }) {25  if (typeof s === 'string') return <span className="mono text-xs">{s}</span>;26  const o = (s ?? {}) as Record<string, unknown>;27  const slug = typeof o.slug === 'string' ? o.slug : null;28  const type = typeof o.entity_type === 'string' ? o.entity_type : 'model';29  const name = typeof o.name === 'string' ? o.name : typeof o.model === 'string' ? o.model : typeof o.reason === 'string' ? o.reason : typeof o.raw === 'string' ? `${String(o.domain ?? '')}: ${o.raw}` : null;30  return (31    <span className="flex flex-wrap items-center gap-x-2 text-xs">32      {slug ? (33        <Link href={routes.entity({ entity_type: type, slug })} className="text-ink hover:text-accent hover:underline">34          {name ?? slug}35        </Link>36      ) : (37        <span className="text-ink">{name ?? <Mono>{JSON.stringify(o).slice(0, 80)}</Mono>}</span>38      )}39      {typeof o.provider === 'string' && <span className="text-ink-3">· {o.provider}</span>}40      {typeof o.provider_model_id === 'string' && <Mono>{o.provider_model_id}</Mono>}41      {Array.isArray(o.quant_formats) && o.quant_formats.length > 0 && <Mono>{(o.quant_formats as unknown[]).join(', ')}</Mono>}42      {typeof o.health === 'string' && <StatusChip value={o.health} />}43      {typeof o.last_success_at === 'string' && <span className="text-ink-3">last success {fmtAgo(o.last_success_at)}</span>}44      {typeof o.count === 'number' && <span className="tnum text-ink-3">× {o.count}</span>}45      {typeof o.id === 'string' && !slug && <Mono>{o.id}</Mono>}46    </span>47  );48}4950export default async function AdminQualityPage({ searchParams }: { searchParams: Promise<Record<string, string | undefined>> }) {51  await requireAdmin();52  const sp = await searchParams;53  const res = await load(adminApi.quality());54  const q: AdminQuality | null = res.ok ? res.data : null;55  const tiles: Tile[] = q56    ? [57        tile('pending_decisions', 'Pending resolution decisions', q.duplicate_candidates?.pending_decisions, 'Candidate pairs awaiting a decision in Entity resolution.', { href: '/admin/entity-resolution' }),58        tile('review_merge_candidates', 'Merge candidates (review queue)', q.duplicate_candidates?.review_merge_candidates, 'merge_candidate items in the v1 review queue.', { href: '/admin/review?kind=merge_candidate' }),59        tile('unmapped_taxonomy_rows', 'Unmapped taxonomy rows', q.taxonomy_violations?.unmapped_taxonomy_rows, 'Raw labels the ontology could not map (domain: raw).'),60        tile('openness_unknown_vocab', 'Openness outside vocabulary', q.taxonomy_violations?.openness_unknown_vocab, 'Openness values not in open-source | open-weights | restricted-weights | proprietary | unknown.', { danger: 1 }),61        tile('status_unknown_vocab', 'Status outside vocabulary', q.taxonomy_violations?.status_unknown_vocab, 'Status values not in the status vocabulary.', { danger: 1 }),62        tile('license_unclassified', 'Unclassified licences', q.taxonomy_violations?.license_unclassified, 'Licence labels without a canonical key.'),63        tile('impossible_values', 'Impossible values (anomalies)', { count: q.impossible_values?.count, sample: q.impossible_values?.sample ?? [] }, 'Open anomaly flags by check — see Anomalies for resolve / ignore.', { href: '/admin/anomalies' }),64        tile('conflicting_t1_claims', 'Conflicting tier-1 claims', q.conflicting_t1_claims, 'Two official sources disagree on a current value.', { danger: 1, href: '/admin/review?kind=conflict' }),65        tile('models_without_organization', 'Models without organization', q.models_without_organization, 'Canonical models with no developer relation.'),66        tile('models_without_release_source', 'Models without release source', q.models_without_release_source, 'Canonical models whose release date has no sourced claim.'),67        tile('models_without_parameters', 'Models without parameters', q.models_without_parameters, 'Canonical models with no parameter_count claim (proprietary models are expected here).'),68        tile('orphan_benchmark_results', 'Orphan benchmark results', q.orphan_benchmark_results, 'Current results whose model was merged or is an artifact.', { danger: 1 }),69        tile('benchmarks_without_results', 'Benchmarks without results', q.benchmarks_without_results, 'Registered benchmarks no connector feeds yet.'),70        tile('unresolved_provider_deployments', 'Unresolved provider deployments', q.unresolved_provider_deployments, 'Price rows whose provider_model_id matches no identifier.'),71        tile('quantisations_typed_as_models', 'Quantisations typed as models', q.quantisations_typed_as_models, 'Name analysis says artifact but the row is a model.', { href: '/admin/entity-resolution?type=model' }),72        tile('stale_sources', 'Stale sources', q.stale_sources, 'Last success older than 3× the connector interval.', { href: '/admin/connectors' }),73        tile('empty_public_categories', 'Empty public categories', q.empty_public_categories, 'Entity types with a public listing but zero rows.'),74        tile('quarantined_runs_pending', 'Quarantined runs pending', q.quarantined_runs_pending, 'Held connector runs awaiting release or discard.', { href: '/admin/quarantine', danger: 1 }),75      ]76    : [];77  const queue = q?.review_queue_priority ?? [];78  const byCheck = q?.impossible_values?.by_check ?? [];79  return (80    <>81      <AdminTitle title="Data quality" lede="Live health of the dataset: duplicates, taxonomy, impossible values, coverage gaps, stale sources. Counts are computed on request; nothing here deletes anything — every tile points at a review action.">82        <Link href={routes.methodology()} className="text-xs text-ink-3 hover:text-ink">83          Anomaly checks →84        </Link>85      </AdminTitle>86      <Notice notice={sp.notice} level={sp.level} />87      {!res.ok ? (88        <Unavailable what="Quality dashboard" reason={res.error} />89      ) : (90        <>91          <ul className="grid grid-cols-2 border-l border-t border-rule md:grid-cols-3 xl:grid-cols-6" data-quality-tiles>92            {tiles.map((t) => (93              <li key={t.key} className="border-b border-r border-rule">94                <details className="group h-full">95                  <summary className="block cursor-pointer list-none px-3 py-2.5 hover:bg-surface-2 [&::-webkit-details-marker]:hidden">96                    <p className="eyebrow leading-tight">{t.label}</p>97                    <p className={cn('tnum mt-1 text-2xl font-semibold leading-none tracking-tight', t.tone === 'danger' && 'text-danger', t.tone === 'warn' && 'text-warning', t.tone === 'neutral' && 'text-ink')}>{t.count === null ? '—' : fmtInt(t.count)}</p>98                    <p className="mt-1 text-[11px] leading-snug text-ink-3">{t.hint}</p>99                  </summary>100                  <div className="border-t border-rule px-3 py-2">101                    {t.sample.length === 0 ? (102                      <p className="text-xs text-ink-3">No sample.</p>103                    ) : (104                      <ul className="space-y-1">105                        {t.sample.slice(0, 8).map((s, i) => (106                          <li key={i}>107                            <SampleRow s={s} />108                          </li>109                        ))}110                      </ul>111                    )}112                    {t.href && (113                      <Link href={t.href} className="link mt-2 inline-block text-xs">114                        Open review action →115                      </Link>116                    )}117                  </div>118                </details>119              </li>120            ))}121          </ul>122          {byCheck.length > 0 && (123            <p className="mt-3 flex flex-wrap gap-1.5 text-xs">124              {byCheck.map((c) => (125                <Link key={c.check_name} href={`/admin/anomalies?check=${encodeURIComponent(c.check_name)}`} className="inline-flex h-7 items-center gap-1.5 border border-rule px-2 text-ink-2 hover:border-rule-strong hover:text-ink">126                  <span className={c.severity === 'critical' ? 'text-danger' : c.severity === 'warning' ? 'text-warning' : 'text-ink-3'}>{c.severity}</span>127                  <span className="mono">{c.check_name}</span>128                  <span className="tnum text-ink-3">{fmtInt(c.n)}</span>129                </Link>130              ))}131            </p>132          )}133134          <h2 className="mt-8 text-base font-semibold tracking-tight">135            Prioritized review queue <span className="tnum text-sm font-normal text-ink-3">{fmtInt(queue.length)}</span>136          </h2>137          <Note className="mb-3 mt-1">Frontier models, benchmark leaders, the largest parameter / context claims, price anomalies, major organizations and duplicates of frontier models come first.</Note>138          <DataTable compact scroll caption="Prioritized review queue">139            <thead>140              <tr>141                <Th>Kind</Th>142                <Th>Item</Th>143                <Th>Reasons</Th>144                <Th>Detail</Th>145                <Th>Action</Th>146              </tr>147            </thead>148            <tbody>149              {queue.length === 0 && <EmptyRow cols={5}>Nothing prioritized.</EmptyRow>}150              {queue.map((it) => {151                const slug = typeof it.slug === 'string' ? it.slug : null;152                const type = typeof it.entity_type === 'string' ? it.entity_type : 'model';153                const href = it.kind === 'anomaly' ? `/admin/anomalies?check=${encodeURIComponent(String(it.check ?? ''))}` : it.kind === 'duplicate' || it.kind === 'merge_candidate' || it.kind === 'resolution' ? '/admin/entity-resolution' : it.kind === 'conflict' ? '/admin/review?kind=conflict' : '/admin/review';154                return (155                  <tr key={`${it.kind}-${it.id}`}>156                    <Td>157                      <KindChip value={it.kind} />158                      {typeof it.severity === 'string' && <span className={cn('ml-1 text-[11px]', it.severity === 'critical' ? 'text-danger' : 'text-warning')}>{it.severity}</span>}159                    </Td>160                    <Td primary>161                      {slug ? (162                        <Link href={routes.entity({ entity_type: type, slug })} className="text-ink hover:text-accent hover:underline">163                          {typeof it.name === 'string' ? it.name : slug}164                        </Link>165                      ) : (166                        <Mono>{it.id}</Mono>167                      )}168                      {typeof it.check === 'string' && <Mono className="block">{it.check}</Mono>}169                    </Td>170                    <Td className="text-xs text-ink-2">{it.reasons?.join(' · ') || '—'}</Td>171                    <Td className="max-w-[28rem] text-xs text-ink-2">{typeof it.message === 'string' ? it.message : <JsonPre value={Object.fromEntries(Object.entries(it).filter(([k]) => !['kind', 'id', 'reasons', 'slug', 'entity_id', 'check', 'severity', 'name', 'entity_type'].includes(k)))} maxHeight="6rem" />}</Td>172                    <Td>173                      <Link href={href} className="link text-xs">174                        Review →175                      </Link>176                    </Td>177                  </tr>178                );179              })}180            </tbody>181          </DataTable>182          {q?.note && <Note className="mt-3">{q.note}</Note>}183        </>184      )}185    </>186  );187}188