Listening for events…

Scope freeze — satcat CelestialObjectDex kind

Frozen 2026-06-26. The 2nd kind of the CelestialObjectDex family (docs/celestialdex-framework.md), after the neo pilot. One slot = one catalogued space object (a satellite, rocket body, or debris fragment) from the CelesTrak satellite catalog.

Mike's ruling

A satellite is a persistent object with an orbital history, so it belongs in the CelestialObjectDex (slot = the object), not as a one-off reentry Eventdex. The triage doc had filed celestrak_satcat as an Eventdex reentry; Mike moved it to CelestialObjectDex (2026-06-26). A reentry is one event in the object's lifecycle, not the object's identity.

The slot

  • One slot = one catalogued object. Slot id = the NORAD_CAT_ID (the catalog number, globally unique and stable).
  • Roster: 69,352 objects (every catalogued object, all distinct NORAD ids). Composition: 35,757 debris, 26,585 payloads, 6,853 rocket bodies, 157 unknown. 35,229 have decayed (reentered); 34,123 are still on orbit. Launch span 1957-10-04 (Sputnik) .. 2026-06-12.
  • No ground point: an orbiting object has no fixed terrestrial position, so geographic lat/lon are NULL (consistent with neo); the "position" is the orbital elements.

The array — the orbital lifecycle

For neo the array is the close-approach list; for satcat it is the object's lifecycle: launch, then (for the ~half that have come down) decay/reentry. v1 represents the lifecycle as launch_utc / decay_utc columns plus days_on_orbit and decayed, rather than a nested event list, because it is a two-point series. The richer orbital-element history array (period/altitude drift over time, from the live celestrak GP feed used in the Starlink thermosphere pilot) is deferred-v2.

Slot contents (spine columns)

  • Identity: norad_id, intl_designator (the international designator, e.g. 1998-067A), object_name.
  • Intrinsic / catalog: object_type (PAY/R/B/DEB/UNK) + name, ops_status + name, owner, launch_site, orbit_type, orbit_center, rcs_m2 (radar cross-section, a size proxy).
  • Measured orbital elements: period_min, inclination_deg, apogee_km, perigee_km (orbit determination from tracking). 67,320 / 69,352 carry them.
  • Lifecycle: launch_utc, decay_utc, decayed, days_on_orbit, plus the raw date strings.

Measured reality

Every field is a catalog fact or a tracking-derived quantity. The orbital elements come from orbit determination on real radar/optical observations, admissible under the bright line's celestial-mechanics refinement (feedback_measured_reality_only, Mike 2026-06-26): deterministic mechanics on measured tracks, not a chaotic forecast. Launch and decay dates are observed events — SATCAT populates DECAY_DATE only once an object has actually reentered, so all 35,229 decay dates are in the past; there are no predicted reentries in this kind. Clean.

Source and storage

  • Catalog: CelesTrak SATCAT (celestrak.org/pub/satcat.csv, keyless, ~6.6 MB, one row per object). Kept fresh by the existing celestrak_satcat fetcher; the kind also TTL-re-pulls it (7-day default) on the live edge.
  • Spine-parquet first (the severe-wx rule): one row per object in data/celestial_storehouse/satcat/satcat_spine.parquet. At ~69k objects, file-per-slot would bloat even the CelestialObjectDex's own index (neo is file-per-slot at 18.7k; satcat is the family's first spine-parquet kind, the same magnitude where nuforc crossed over for Eventdex). Per-slot JSON dossiers are deferred-v2 alongside the orbital-history array.

Live edge

satcat_celestialdex.refresh_and_store() (the family contract, adapted for a catalog-csv kind): TTL-re-pull satcat.csv, then rebuild the spine parquet, so new launches and freshly decayed objects flow in. Scheduler wiring (a weekly satcat_refresh job mirroring neo_refresh) is the finishing step, separate from this build so it lands with a single service restart.

Builder

src/terrapulse/monitor/satcat_celestialdex.py (importable parse_object / load_objects / build_spine / refresh_and_store; runnable as a module). Tests: tests/test_monitor/test_satcat_celestialdex.py (5).

Frozen vs deferred-v2

  • Frozen (this brick): the 69,352-object spine parquet (identity + intrinsic catalog fields + measured orbital elements + launch/decay lifecycle).
  • Deferred-v2: the orbital-element history array from the celestrak GP feed; per-slot JSON dossiers; a cross-match read-across (does a decayed object line up with a nuforc sighting, a cneos_fireballs entry, an entry reentry record).
Live Feed