RFC-009 — Mission flight params + timeline navigator
Status · Closed · closed by ADR-027 (2026-04-29) Date · 2026-04-29 TA anchor · §components/mission-data · §components/fly-screen · §components/missions-screen Related PRDs · PRD-003 (Mission Arc), PRD-004 (Mission Library) Related ADRs · ADR-006 (mission JSON), ADR-019 (ajv validation), ADR-020 (canonical mission schema), ADR-024 (mission URL sharing), ADR-026 (multi-destination) Why this is an RFC · The current mission JSON has language-neutral identity + dates + a single
delta_vstring./flysynthesises trajectories fromtransit_daysalone;/missionsshows agency + year + first-line. The mission record is identity, not flight. Real per-mission flight realism — characteristic energy, target b-plane, periapsis altitude, orbit-insertion ∆v, MET-stamped events — lives elsewhere or doesn't exist in our data. This RFC asks: how do we encode it, validate it, surface it, and gracefully handle the missions where the data is sparse or unavailable?
The question
Three coupled problems:
Data shape. What flight parameters get added to the mission record? A standardised schema that covers C3, V∞, declination, target-arrival geometry, key burns, and a structured event timeline — without ballooning a 30-line file into a 300-line one.
Sparse coverage. Curiosity (NASA, well-documented) has every parameter publicly released. Mars 3 (USSR, 1971) has fragmentary records. Mariner 4 has near-complete telemetry from JPL TR-32-740. Apollo 11 is the most-documented mission ever. How do we encode "known", "approximate", and "unknown" without rendering as nothing or as fake numbers?
Surface. Where does this data show up? Three candidate surfaces:
- /fly HUD — mission-specific readouts replacing the current generic
transit_dayssynthesis. - /missions detail panel — a new FLIGHT tab alongside GALLERY and LEARN.
- Timeline navigator at the top of /missions — a horizontal time scrubber spanning 1957–2030, missions plotted as dots, drag-to-scrub filters the cards below.
- /fly HUD — mission-specific readouts replacing the current generic
Use cases
- Curious learner clicks Curiosity → sees not just "254-day transit" but "C3 = 11.2 km²/s², launched 35° declination, arrived at 6.0 km/s, 4.1 km/s orbit insertion ∆v before atmospheric entry." The numbers are real and traceable.
- STEM student compares Mariner 4 vs Curiosity flight params side by side via the library and notices the C3 difference reflects launcher capability, not just timing.
- Teacher uses the timeline navigator to scrub from 1962 → 2024 and watches how the gap between launches collapsed from one-mission-per-decade to one-per-year. The collapse is felt visually, not read in text.
- Contributor adds a new mission and the schema tells them exactly which fields are required and which can be omitted with a
data_qualityflag. /flyrealism: each mission's outbound arc is parameterised by its C3 + V∞ + arrival declination, not synthesised fromtransit_daysalone — so two missions with the same start and end dates render visibly distinct trajectories when their target geometry differs.
Goals
- Encode flight params per mission in a way that ajv can validate at PR.
- Allow partial / unknown values without breaking the schema or showing fake data.
- Surface params in
/fly(HUD) and/missions(FLIGHT tab) — make them legible to non-experts. - Add a timeline navigator at the top of
/missionsthat filters cards below. - No regression on the existing 28 mission cards or the existing
/flyrendering.
Constraints
- ADR-020 locks the canonical mission schema. Extensions go through ADR-027 (this RFC's expected closure).
- ADR-019 locks ajv validation on PR. Every new field must validate.
- ADR-017 locks i18n architecture. Editorial content (event notes, anomaly descriptions) lives in locale overlays; flight params (numeric) live in the base file.
- CLAUDE.md locks no-localStorage, mobile-first, 44px touch targets. Timeline navigator must work on phones.
- Data-quality honesty (PA §promises). Unknown params must show as "—" or "unknown", never as plausible-sounding fake numbers.
- The current
delta_vstring ("~6.1 km/s") is loadbearing for/fly— must remain readable through a backward-compat shim or a dual-key migration.
Options
What flight params to encode
Option F-A — Minimum viable. Add only c3_km2_s2, v_infinity_arrival_km_s, orbit_insertion_dv_km_s, and a list of events[] with met_days + type. Keeps the schema small. Misses the geometry (declination, target periapsis) that distinguishes one Mars mission from another visually.
Option F-B — Full launch + arrival + cruise + events. Six sub-objects: launch (C3, declination, mass), cruise (TCM count, dust storm encounters if any), arrival (V∞, b-plane radius, periapsis km, inclination, insertion ∆v), events[] (MET-stamped milestones with type + optional editorial note via i18n overlay), descent for landers, return for sample-return / crewed. Each sub-object is optional — missing = unknown. Maximum realism. Largest schema; most fields to fill per mission.
Option F-C — Tiered: required, optional, advanced. Three tiers: (1) required for every mission (TLI/TMI ∆v, peak heliocentric speed, arrival geometry summary); (2) optional for well-documented missions (full F-B contents); (3) advanced for the STEM student (separate JSON file linked from the mission record). Keeps the base mission compact but lets a thorough mission carry full data.
How to handle sparse data
Option S-A — Optional fields throughout. Schema marks every flight-param field as optional. Missing = unknown; UI renders "—". Simplest. Risks ambiguity: is c3_km2_s2: undefined because we don't know, or because we forgot to fill it?
Option S-B — Explicit unknown tag. Each flight param has the form { value: number | null, source: string | null, confidence: 'measured' | 'reconstructed' | 'estimated' | 'unknown' }. Verbose but unambiguous. Doubles the size of every numeric field.
Option S-C — Top-level flight_data_quality flag + optional fields. One per-mission flag ('measured' | 'reconstructed' | 'sparse' | 'unknown') gates how we render missing fields. Optional fields elsewhere. UI can say "Mariner 4 reconstructed flight data — some values approximate" once at the top of the panel rather than per-field. Compact and honest.
Where to surface
Option U-A — /missions FLIGHT tab + /fly HUD only. Timeline navigator deferred. Smallest scope; ships flight realism without UI invention.
Option U-B — All three (FLIGHT tab + /fly HUD + timeline navigator). Complete experience. Timeline navigator is its own UX research surface.
Option U-C — FLIGHT tab + /fly HUD now, timeline navigator as a v0.1.8 follow-up. Stage the work. Timeline navigator gets its own UXS spec + dedicated implementation slice once the flight-data foundation is solid.
Timeline navigator visual approach
Option N-A — Horizontal strip with mission dots. 1957 → 2030 fixed range. Missions plotted as agency-coloured dots at their launch year. Drag a window-of-interest range; cards below filter to the windowed missions. Pinch-to-zoom on mobile. ~80 px tall.
Option N-B — Vertical timeline with annotated decades. Decade markers on the left, missions clustered by year. More space-consuming; reads like a textbook. Better on tablets, awkward on phones.
Option N-C — Hybrid: horizontal dot strip on phones, decade-annotated horizontal axis on desktop. Mobile-first per ADR-018. The desktop variant adds decade labels above the strip + agency legend in the right margin.
Open questions
OQ #1 — How precise must
c3_km2_s2be? Public records vary by source (NASA press kit vs JPL technical report vs reconstructed). Lock the policy: cite-the-most-authoritative-source-available; record the source string; round to one decimal place.OQ #2 — Do
events[]carry editorial notes in the base file or the i18n overlay? Per ADR-017, editorial = overlay. Soevents[].met_days+events[].typeare base-file (numeric/enum). The human-readable note lives indata/i18n/[locale]/missions/[dest]/[id].jsonunderevents[]. Already partly the convention.OQ #3 — Backward compatibility for the existing
delta_vstring. Two paths: (A) keepdelta_vas a presentation string; the newtotal_dv_km_s: numberis what/flyconsumes. (B) deprecatedelta_vand migrate. Path A wins on minimal disruption; Path B wins on no-two-sources-of-truth. Pick A for the slice; flag B for a follow-up.OQ #4 — Timeline navigator on
/missions/:iddeep-links? When a user shares/missions?mission=curiosity, does the timeline jump to 2011 and show Curiosity highlighted? Probably yes — coherent with ADR-024. Tracked here for closure.OQ #5 — Performance budget for timeline scrubbing. 28 missions today; 100+ in the long run. Re-rendering 100 cards on every scrub frame is too much. Need a debounce / virtualisation pattern. Defer the constraint to ADR-027's implementation notes.
Goals for the closure ADR (ADR-027)
The ADR locks:
- The schema additions to
mission.schema.json(and any new sub-schema files) - The data-quality / unknown-handling convention
- The list of params required vs optional
- The order of surface rollout (FLIGHT tab → /fly HUD → timeline navigator)
- The timeline navigator's mobile + desktop layout
- The migration plan for the existing 28 missions (which gets full flight params first; which stays partial)
- The i18n overlay convention for events[] notes