ADR 0011: Algebraic default, ephemeris opt-in¶
Status: Accepted (2026-04-30, v0.2.0)
Context¶
v0.1.0 shipped four bridge methods that needed a JPL DE-kernel via skyfield to answer:
get_solar_elongation(jd, planet)get_visibility_windows(jd_lo, jd_hi, planet)get_next_heliacal_rising(jd, planet)find_eclipses(jd_lo, jd_hi, kind)
Kiosk-style consumers — the primary motivating use case for the package — generally do not want a 16 MB to 1.5 GB ephemeris kernel as a runtime dependency. They want "is Mars currently visible?" to return without pip install antikythera-spectral[ephemeris] and a 1.5 GB BSP download.
Insight¶
The encoder is the device. Once anchored at design time (REFERENCE_JD = 1684595.0), every dial reading is (jd - REFERENCE_JD) / cycle_period_days % 1. Pure modular arithmetic on cyclic groups; no ephemeris needed. The ephemeris only enters when we want to grade the encoder's predictions against modern best-estimate sky truth.
The same logic applies to the four sky-truth methods above:
- Heliacal rising / visibility windows / solar elongation are all functions of synodic-cycle phase. Given one observed heliacal rising per planet (an anchor) plus the synodic period, every future event is
anchor + n · synodic. Closed-form, sub-millisecond, no ephemeris. - Eclipse search is what the Antikythera's Saros pointer does — the device's actual job. Saros-cycle propagation from a frozen anchor catalogue is the right model.
The only method that inherently needs an ephemeris is compare_ephemerides (it's literally a JPL-kernel diff tool); that one stays ephemeris-only.
Decision¶
Each of the four methods grows a precise keyword:
precise=False(default): self-contained algebraic mode. Uses per-planet anchors from_data/visibility_anchors.json+ the existing eclipse anchor catalogue in_data/anchors.json. Always succeeds (no kernel required).precise=True: opt-in skyfield mode. Sub-arcsec accuracy; requires[ephemeris]extras + the chosen kernel locally; returns{"ok": False, ...}if the kernel is missing.
The CLI mirrors this with a --precise flag on the four affected subcommands.
The package's dependencies list stays as ["numpy>=1.24"]. Skyfield + jplephem move to [ephemeris] extras only — they're now strictly optional.
compare_ephemerides is unchanged (ephemeris-bound by definition; [ephemeris] extras required).
Consequences¶
- Kiosk install:
pip install antikythera-spectralworks for every method exceptcompare_ephemerides. No extras needed. - Wheel size unchanged (frozen JSON anchors are tiny — <2 KB).
- Precision target:
precise=Falseanswers are within ~±1 day on heliacal events and ~±5° on elongation. At Hellenistic-era epochs the ΔT-uncertainty floor is 3 hours regardless (DELTA_T_MODEL.md), so the algebraic precision is honest for the device's natural use case. - Research-mode users who want to validate the encoder against modern best-estimate get sub-arcsec precision via
precise=True. Same surface, opt-in cost. bridge_api.mdupdated to document theprecisekeyword on the affected methods. Return shapes gain amode: "algebraic" | "ephemeris"field.
Anchor provenance¶
Per-planet anchors in _data/visibility_anchors.json were computed once at v0.2.0 design time using skyfield + DE421, searching forward from J2000 (JD 2451545.0) for the first heliacal rising of each planet. Documented inline in the JSON's anchor_provenance field. Re-running this computation with a different kernel or epoch is straightforward but should produce equivalent results to within ±1 day; the file is committed and frozen for v0.2.0.
Alternatives considered¶
- Drop the four methods entirely, force users into [ephemeris]. Rejected: the sky-truth queries are useful in their own right for kiosk display ("is Mars visible tonight?"), and the Antikythera's own job is exactly Saros-cycle eclipse prediction.
- Make skyfield a runtime dep, ship a small kernel. Rejected: smallest usable JPL kernel (DE421) is 16 MB and only covers 1899-2053. For Hellenistic-era queries you need DE441_part1 (1.5 GB). Neither is wheel-friendly.
- Single-mode algebraic only, drop the skyfield path. Rejected: research users genuinely need the validation surface; we shouldn't take it away from them just because kiosk users don't need it.