Skip to content

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_v string. /fly synthesises trajectories from transit_days alone; /missions shows 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:

  1. 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.

  2. 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?

  3. Surface. Where does this data show up? Three candidate surfaces:

    • /fly HUD — mission-specific readouts replacing the current generic transit_days synthesis.
    • /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.

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_quality flag.
  • /fly realism: each mission's outbound arc is parameterised by its C3 + V∞ + arrival declination, not synthesised from transit_days alone — 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 /missions that filters cards below.
  • No regression on the existing 28 mission cards or the existing /fly rendering.

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_v string ("~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

  1. OQ #1 — How precise must c3_km2_s2 be? 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.

  2. OQ #2 — Do events[] carry editorial notes in the base file or the i18n overlay? Per ADR-017, editorial = overlay. So events[].met_days + events[].type are base-file (numeric/enum). The human-readable note lives in data/i18n/[locale]/missions/[dest]/[id].json under events[]. Already partly the convention.

  3. OQ #3 — Backward compatibility for the existing delta_v string. Two paths: (A) keep delta_v as a presentation string; the new total_dv_km_s: number is what /fly consumes. (B) deprecate delta_v and 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.

  4. OQ #4 — Timeline navigator on /missions/:id deep-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.

  5. 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

Orrery — architecture documentation · MIT · No tracking