SPB Git forge
3commits 1branches 0releases
417.0 KBsize
maindefault branch
10 days agolast push
TypeScript 66.5% Python 30.9% JavaScript 1.4% CSS 0.7%
5.8 KB · 115 lines tsx
Raw Blame History
1import type { Metadata } from 'next';2import Link from 'next/link';3import { ATTRIBUTION, DISCLAIMER, FIELD_PRIORITY } from '@/components/meta/legal';4import { FreshnessSection, LimitationsSection, MissionLaunchSection, OrbitCalcSection, OrbitClassSection, PipelineSection, ResolutionSection, StatusSection } from '@/components/meta/methodology-sections';5import { ConstellationRulesSection, MetricsSection, OwnerCodesSection } from '@/components/meta/methodology-tables';6import { Callout, DocLayout, DocSection, Prose } from '@/components/meta/prose';7import { Container, PageHeader } from '@/components/ui/section';8import { api, safe } from '@/lib/api';9import { fmtDateTime } from '@/lib/format';10import { SITE_URL, routes } from '@/lib/site';1112export const metadata: Metadata = {13  title: 'Methodology — how SatelliteIndex builds and derives its data',14  description: 'Ingestion pipeline, source priorities, entity resolution, SGP4 orbit calculation, status and orbit-class rules, constellation membership, versioned derived metrics, freshness thresholds and known limitations.',15  alternates: { canonical: `${SITE_URL}/methodology` },16  openGraph: { title: 'Methodology | SatelliteIndex', description: 'How every value on SatelliteIndex is sourced, resolved, computed and labelled.', url: `${SITE_URL}/methodology` },17  twitter: { card: 'summary', title: 'Methodology | SatelliteIndex', description: 'How every value on SatelliteIndex is sourced, resolved, computed and labelled.' },18};1920const TOC = [21  { id: 'pipeline', label: 'Data pipeline' },22  { id: 'source-priority', label: 'Source priorities' },23  { id: 'entity-resolution', label: 'Entity resolution' },24  { id: 'orbit-calculation', label: 'Orbit calculation' },25  { id: 'status', label: 'Status classification' },26  { id: 'orbit-class', label: 'Orbit class' },27  { id: 'constellations', label: 'Constellation membership' },28  { id: 'mission-type', label: 'Mission type' },29  { id: 'launches', label: 'Launches' },30  { id: 'owner-codes', label: 'Owner codes' },31  { id: 'metrics', label: 'Derived metrics' },32  { id: 'freshness', label: 'Freshness' },33  { id: 'limitations', label: 'Limitations' },34  { id: 'disclaimer', label: 'Disclaimer' },35];3637export default async function MethodologyPage() {38  const res = await safe(api.methodology());39  const payload = res?.data ?? null;40  const metric = (key: string) => payload?.metrics.find((m) => m.key === key)?.methodology ?? null;41  return (42    <Container>43      <PageHeader eyebrow="Methodology" title="How the index is built" lede="Every value on SatelliteIndex is either a sourced fact with provenance or a derived label with a versioned rule. This page documents the rules — from the raw upstream payload to the position drawn on the globe — so you can decide how much to trust each number.">44        <p className="mt-4 text-sm text-ink-3">45          Sources and licenses: <Link href={routes.sources()} className="link">/sources</Link> · Live freshness: <Link href={routes.statusData()} className="link">/status/data</Link> · Machine-readable: <a href="/api/v1/methodology" className="link mono">/api/v1/methodology</a>46          {res && <span className="ml-2">· definitions fetched {fmtDateTime(res.meta.generated_at)}</span>}47        </p>48      </PageHeader>4950      <DocLayout toc={TOC}>51        <div>52          <PipelineSection />5354          <DocSection id="source-priority" eyebrow="02" title="Source priorities">55            <Prose>56              <p>57                Sources carry a numeric priority; when two sources describe the same field the higher-priority value is kept and the other is still recorded in provenance. In practice each field family has one primary source today:58              </p>59            </Prose>60            <div className="mt-4 overflow-x-auto">61              <table className="data-table stack md:min-w-[640px]">62                <thead>63                  <tr>64                    <th>Field</th>65                    <th>Primary source</th>66                    <th>Note</th>67                  </tr>68                </thead>69                <tbody>70                  {FIELD_PRIORITY.map((f) => (71                    <tr key={f.field}>72                      <td className="primary text-sm text-ink">{f.field}</td>73                      <td data-label="Primary source" className="text-sm">74                        <Link href={`${routes.sources()}#${f.sourceId}`} className="link">75                          {f.source}76                        </Link>77                      </td>78                      <td data-label="Note" className="text-sm text-ink-2">79                        {f.note}80                      </td>81                    </tr>82                  ))}83                </tbody>84              </table>85            </div>86          </DocSection>8788          <ResolutionSection />89          <OrbitCalcSection />90          <StatusSection methodologyText={metric('status')} />91          <OrbitClassSection methodologyText={metric('orbit_class')} />92          <ConstellationRulesSection rules={payload?.constellation_rules ?? null} />93          <MissionLaunchSection />94          <OwnerCodesSection owners={payload?.owner_codes ?? null} />95          <MetricsSection metrics={payload?.metrics ?? null} />96          <FreshnessSection methodologyText={metric('freshness')} />97          <LimitationsSection />9899          <DocSection id="disclaimer" eyebrow="14" title="Disclaimer">100            <Callout tone="warn" className="mt-0">101              {DISCLAIMER}102            </Callout>103            <Prose className="mt-4">104              <p>{ATTRIBUTION}</p>105              <p className="text-ink-3">106                See the <Link href={routes.terms()} className="link">terms of use</Link>. Corrections and questions: <Link href={routes.about()} className="link">about</Link>.107              </p>108            </Prose>109          </DocSection>110        </div>111      </DocLayout>112    </Container>113  );114}115