Shell script drives the Dockerfile builder stage across PG versions,
capturing pass/fail + timing per version. Makefile targets: test-matrix,
test-pg%, test-matrix-clean. Also runs standalone DE reader test in the
builder stage to catch compiler-version regressions.
Fix pork chop grid test: add ORDER BY to CROSS JOIN (optimizer chooses
different join nesting across PG versions, reordering rows).
An existing product called PG Orbit (a mobile PostgreSQL client)
creates a naming conflict. pg_orrery — a database orrery built from
Keplerian parameters and SQL instead of brass gears.
Build system: control file, Makefile, Dockerfile, docker init script.
C source: GUC prefix, PG_FUNCTION_INFO_V1 symbol, header guards,
ereport prefixes, comments across ~30 files including vendored SGP4.
SQL: all 5 install/migration scripts, function name pg_orrery_ephemeris_info.
Tests: 9 SQL suites, 8 expected outputs, standalone DE reader test.
Documentation: CLAUDE.md, README.md, DESIGN.md, Starlight site infra,
36 MDX pages, OG renderer, logo SVG, docker-compose, agent threads.
All 13 regression suites pass. Docs site builds (37 pages).
Replace the sat_code git submodule (lib/sat_code/) with vendored
sources in src/sgp4/. The upstream .cpp files are renamed to .c —
the code is valid C99 with zero C++ features. This eliminates the
g++ and -lstdc++ build dependencies.
Adds 518 Vallado test vectors (AIAA 2006-6753-Rev1) as a 13th
regression suite to verify byte-identical numerical output.
Updates all documentation (CLAUDE.md, DESIGN.md, 11 MDX pages,
Dockerfile) to reflect the new layout and pure-C compilation.
Replace generic blackAndWhite preset with custom renderer using
site colors (#0a0e17 dark background, #f59e0b amber accents),
decorative orbital rings watermark, branded footer with pg_orbit
name and site URL. Inter font in 400/700 weights.
Hero tagline: "It's not rocket science. (It's celestial mechanics.
But now it's just SQL.)" across README, index.mdx, and meta description.
Add astro-icon with Lucide icon set, astro-seo-meta, and
astro-opengraph-images (blackAndWhite preset, Inter font). Override
Starlight Head component to inject og:image and twitter card tags
with auto-generated 1200x630 PNG images for all 37 pages.
Standalone test (test/test_de_reader.c): generates a synthetic 12KB
DE binary with known Chebyshev coefficients, exercises header parsing,
polynomial evaluation at 5 domain points, Earth derivation via
center=99, Moon geocentric, layout validation, range/body error paths,
NAN sentinel, and garbage file rejection. 55 tests, no PG dependency.
Makefile: add `make test-de-reader` target; also includes the earlier
sat_code C++ -> pure C sgp4 migration that was missed from prior commits.
astro_math.h: document that ecliptic_to_equatorial/equatorial_to_ecliptic
are NOT safe for aliased (in-place) calls — equ[1] is written before
equ[2] reads ecl[1]. The vendored sgp4/sdp4.c has separate in-place
versions using a temp variable.
Three independent reviews (manual, failure-mode analysis, JPL spec
cross-reference) confirmed the mathematical core is correct. This
commit addresses defensive coding and operational behavior:
- Fix header byte-offset comments (12 groups = 144 bytes, not 156)
- Add layout validation before Chebyshev interpolation (prevent
buffer underread for bodies absent from a DE edition)
- Clamp Chebyshev argument to [-1,+1] with debug assertion for
values beyond 1e-10 tolerance (catches structural normalization
errors vs normal FP boundary rounding)
- Add O_CLOEXEC to prevent FD leaks to child processes
- Change GUC from PGC_SIGHUP to PGC_BACKEND to match actual
one-shot initialization behavior
- Fix provider consistency: planet_velocity_de() now accepts a
use_de flag to match the provider used for positions (rule 7)
- Optimize eph_de_moon() to use raw geocentric Moon (center=-1)
instead of computing Earth just to subtract it back out
- Pre-compute obliquity trig constants (verified to full precision)
- Tighten canary check from 0.9-1.1 AU to 0.97-1.04 AU
- Return NAN for missing constants (0.0 was ambiguous)
- Add _Static_assert for sizeof(double) == 8
- Remove unused HDR_* macros
- Zero Datum values before setting null flags in ephemeris_info
- Replace magic numbers with DE_MOON/DE_SUN constants
All 13 regression tests pass. Zero compiler warnings.
Clean-room DE binary reader (~400 lines C) with Chebyshev/Clenshaw
evaluation — no GPL dependency on jpl_eph. Per-backend lazy
initialization preserves PARALLEL SAFE. Existing VSOP87/ELP82B
functions stay IMMUTABLE; new _de() variants are STABLE with
automatic fallback to compiled-in ephemerides on any DE failure.
Implementation:
- de_reader.c: header parse, record seek, Clenshaw recurrence
- eph_provider.c: GUC (pg_orbit.ephemeris_path), lazy init,
ICRS-to-ecliptic frame rotation, on_proc_exit cleanup
- de_funcs.c: 11 new SQL functions (_de variants + diagnostics)
- Constant chain of custody rules 6-8 (frame rotation,
same-provider, AU consistency)
Extract observe_from_geocentric() to astro_math.h for shared use
by planet_funcs.c, moon_funcs.c, and de_funcs.c.
57 → 68 functions, 11 → 12 regression test suites, all passing.
README covers all 57 functions across 9 domains with quick-start
examples, capability matrix, body ID tables, and performance benchmarks.
Links to Starlight docs site for detailed reference.
Adds Docker Compose deployment for docs site behind caddy-docker-proxy
with dev/prod modes and Vite HMR support through reverse proxy.
Reflects the full solar system expansion: 57 functions, 7 types,
11 test suites, 36 source files, body ID tables, error handling
patterns, astronomical constants, and the Starlight docs site.
Add Universal Variable Lambert solver for computing transfer orbits
between any two planets. Enables pork chop plot generation as SQL:
SELECT dep_date, arr_date, lambert_c3(3, 4, dep_date, arr_date)
FROM generate_series(...) dep CROSS JOIN generate_series(...) arr;
New functions:
- lambert_transfer(dep_body, arr_body, dep_time, arr_time) → RECORD
Returns C3 departure/arrival (km^2/s^2), v_infinity (km/s),
time of flight (days), and transfer orbit SMA (AU).
- lambert_c3(dep_body, arr_body, dep_time, arr_time) → float8
Convenience: departure C3 only, NULL on solver failure.
The solver uses Stumpff functions for unified elliptic/parabolic/hyperbolic
handling, with Newton-Raphson iteration and bisection fallback.
Each solve is sub-millisecond; PARALLEL SAFE for batch computation.
All 11 regression tests pass.
Add observation functions for 19 planetary moons across four systems:
- Galilean moons (Io, Europa, Ganymede, Callisto) via clean-room L1.2 theory
- Saturn moons (Mimas through Hyperion) via TASS 1.7
- Uranus moons (Miranda through Oberon) via GUST86
- Mars moons (Phobos, Deimos) via MarsSat
Add Jupiter decametric radio burst prediction for Radio JOVE operators:
- io_phase_angle() — Io orbital phase from superior conjunction
- jupiter_cml() — System III Central Meridian Longitude with light-time correction
- jupiter_burst_probability() — Carr et al. (1983) source regions A, B, C, D
L1.2 Galilean theory is a clean-room MIT implementation from the published
IMCCE FORTRAN coefficients. All other ephemeris libraries are MIT-licensed
extractions from Stellarium with static caching removed for PARALLEL SAFE.
All 10 regression tests pass. Extension .so grows from 2.4MB to 2.5MB.
Phase 1 — Stars, comets, Keplerian propagation:
- star_observe() / star_observe_safe(): fixed star alt/az via IAU 1976
precession, equatorial-to-horizontal transform
- kepler_propagate(): two-body Keplerian orbit propagation for
elliptic, parabolic, and hyperbolic orbits
- comet_observe(): observe comets/asteroids from orbital elements
- heliocentric type: ecliptic J2000 position (x, y, z in AU)
Phase 2 — VSOP87 planets, ELP82B Moon, Sun:
- planet_heliocentric(): VSOP87 heliocentric ecliptic J2000 positions
for Mercury through Neptune (Bretagnon & Francou, MIT)
- planet_observe(): full observation pipeline for any planet
- sun_observe(): Sun position from negated Earth VSOP87
- moon_observe(): ELP2000-82B lunar position (Chapront-Touzé, MIT)
- Clean-room precession (IAU 2006) and sidereal time (IERS 2010)
- elliptic_to_rectangular utility (Stellarium, MIT)
All Stellarium extractions are MIT-licensed, thread-safe (static
caching removed for PARALLEL SAFE), zero external data files.
All 9 regression tests pass (90ms total).
Three-stage Dockerfile: Ubuntu 22.04 builder (glibc-matched to
TimescaleDB-HA), scratch artifact image (~748KB), and standalone
postgres:17 image. All 6 regression suites run during build.
Makefile gains docker-build, docker-push, and docker-test targets.
The 1-D altitude-band index only pruned ~25% of the 22k satellite
catalog (eliminates MEO/GEO/HEO but 75% is LEO). Adding inclination
as a second indexed dimension prunes an additional ~40% of remaining
candidates — objects in equatorial or low-inclination orbits that
geometrically cannot pass over the observer's latitude.
Key changes:
- tle_alt_range (16 bytes) → tle_orbital_key (32 bytes) with
inc_low/inc_high fields
- All 8 GiST support functions updated for 2-D bounding boxes
- Penalty uses margin (half-perimeter) not area to avoid degeneracy
when leaf entries have zero-width inclination ranges
- Picksplit selects split dimension by normalized spread
- && operator now checks altitude AND inclination overlap
- <-> operator remains altitude-only (conjunction screening is
altitude-dominant)
- SQL operator comments updated for 2-D semantics
- Test adds Equatorial-LEO satellite at ISS altitude but 5° inclination
to validate inclination-based pruning
Implements 5 new C functions requested by the Craft (Astrolock) API team:
- tle_from_lines(text, text): two-argument TLE constructor
- observer_from_geodetic(float8, float8, float8): numeric observer constructor
- observe(tle, observer, timestamptz): single-call propagate + topocentric
- sgp4_propagate_safe(tle, timestamptz): returns NULL on propagation error
- observe_safe(tle, observer, timestamptz): returns NULL on propagation error
Refactors do_propagate() into safe/unsafe variants to support NULL returns.
Adds regression test (convenience.sql) covering all new functions including
an equivalence test verifying observe() matches the manual two-step pipeline.
All 6 regression tests pass.
6 custom types (tle, eci_position, geodetic, topocentric, observer,
pass_event), 67 SQL functions, 2 operators (&&, <->), and a GiST
operator class for altitude-band indexing. Wraps Bill Gray's sat_code
for SGP4/SDP4 propagation with WGS-72 constants for propagation and
WGS-84 for coordinate output. All 5 regression tests pass on PG 18.