Skip to content

ephemerides-spectral roadmap

Status of advertised CLI / Bridge API methods. Mirrors the antikythera-spectral ROADMAP discipline: every entry the help text advertises is either ✅ wired (real implementation behind it) or ⏳ pending (planned for a specific version).

Released versions

Version Date Headline
v0.29.1 2026-05-16 Production cut — srmech dependency floor bump >=0.3.1,<0.4>=0.4.0. Version-only bump from 0.29.1rc10.29.1 after the single-rc TestPyPI verification cycle. Tracks the srmech v0.4.0 production cut so downstream consumers transitively pick up srmech's cumulative v0.4.x content: 14-class C-parity primitive vocabulary (Spike #24 Classes A–N in native C + Python), canonical QM/QFT/SM operations layer at srmech.qm.* (Schrödinger / Pauli + Cl(0,3) / Dirac γ-matrices + Weyl + Klein-Gordon / Feynman propagators / pseudo-Hermitian / SU(2)+SU(3) gauge / Higgs + W/Z + Yukawa + CKM Standard Model), and the ~87-entry srmech.amsc.tool_schema introspection surface. All 5 SSOT files (pyproject.toml, pyproject-pure.toml, version.py, srmech_profile.toml, c/include/ephemerides_spectral.h) bump in lockstep plus the manifest re-stamp. Pure dependency-floor bump; no code change; no ABI change (ES_ABI_VERSION = 10 unchanged from v0.29.0). Verified on TestPyPI as 0.29.1rc1 in a clean external venv before the cut.
v0.29.1rc1 2026-05-16 rc1 of v0.29.1 — srmech dependency floor bump >=0.3.1,<0.4>=0.4.0 (TestPyPI verification cycle). First rc; verified clean on TestPyPI in an external venv. No code change between rc1 and the v0.29.1 production cut.
v0.29.0 2026-05-15 Production cut — channel-basis dual-path spike (TURN_INTEGER, cyclic-group-native). Version-only bump from 0.29.0rc10.29.0 after the single-rc TestPyPI verification cycle. Cumulative content: opt-in es_channel_basis_method(..., ES_BASIS_METHOD_TURN_INTEGER) route that decomposes the splitmix64-derived phase residue by integer quadrant (phase = (uint32_t)(u >> 32) in Z_{2^32}, quadrant = phase >> 30, within = phase & 0x3FFFFFFF), dispatches bit-exact (±1, 0) / (0, ±1) when within == 0, else computes cos/sin on the small within-quadrant argument and applies i^quadrant rotation by sign/swap. Bit-exact quarter turns on every toolchain — no libm cospi/sinpi dependency, no platform feature gate. ABI v9 → v10 (additive; existing es_channel_basis preserved + still delegates to LEGACY → Tier 2a Python-vs-C byte-parity continues byte-for-byte). C/Python byte-parity preserved on both routes — _research/portable_prng.py gained splitmix64_turn_integer_basis_element + splitmix64_turn_integer_basis (Python mirror of the C TURN_INTEGER route). JPL Power-of-Ten clean (pins 49 funcs / 109 asserts / density 2.22). Encoder hot path unchanged. Verified on TestPyPI in a clean external venv before merge.
v0.29.0rc1 2026-05-15 Channel-basis dual-path spike (cyclic-group-native quarter-turn decomposition; ABI v9 → v10 additive). First rc of the v0.29.x cycle, with byte-for-byte C/Python parity preserved on both routes (LEGACY mirror via existing splitmix64_phases; TURN_INTEGER mirror via new splitmix64_turn_integer_basis — sibling Tier 2a discipline). The shipped LEGACY route does phi = (u >> 11) · (2π/2^53) in software then calls libm cos/sin on the radian result — composing two argument-reductions and leaving ~2 ULP of error at quarter-turn channels. New es_channel_basis_method(seed, out, D, method) adds an opt-in TURN_INTEGER route that honours the project's algebraic stance: keep the phase in turns (phase = (uint32_t)(u >> 32) lives in the cyclic group Z_{2^32}), decompose by integer quadrant (quadrant = phase >> 30, within = phase & 0x3FFFFFFF), dispatch bit-exact (±1, 0) / (0, ±1) when within == 0, else compute cos/sin on (double)within · (π/2 / 2^30) (small argument, no internal reduction needed) and apply i^quadrant rotation by pure sign/swap. Quarter-turn channels collapse to bit-exact (±1, ±i) on every toolchain — no libm cospi/sinpi dependency, no platform feature gate, no × π in the global argument. ABI v9 → v10 (additive: enum + method entry; the existing es_channel_basis is preserved as-is and still delegates to LEGACY → byte-parity with Python BIP / numpy.exp(1j·φ) continues to hold). JPL Power-of-Ten clean (pins: 49 funcs / 109 asserts / density 2.22). New scripts/bench_turn_integer_basis.py (NDJSON output) is the artifact of the bench-and-quantify step — its quantitative findings inform the yank-vs-keep decision before any TestPyPI publish. Default unchanged: LEGACY remains the byte-parity default until the bench supports flipping it. Earlier draft note: an initial cospi/sinpi route was committed in this branch (commit 1b860f8) but pivoted to TURN_INTEGER mid-rc after the design discussion concluded the phase is already a rational fraction; π should not appear in the global argument when integer quarter-turn arithmetic is exact.
v0.28.1 2026-05-15 Production cut — README hygiene patch on top of v0.28.0. Version-only bump from 0.28.1rc20.28.1 after the two-rc cycle (rc1 + rc2). Cumulative content: rc1 removed two stale "Unreleased" bullets (LLM tool-schema export + first cosmology pair, both shipped v0.26.1), fixed 3 stale 38-body references → 52, removed 2 shipped roadmap items, tightened the heteroclinic note; rc2 folded two proofread follow-ups (BIP-vs-HD-state clarification + DE441 sweep table body-id rename earth/moonterra/luna). Each rc verified on TestPyPI in a clean external venv before autonomous merge. Pure README hygiene; no code change; no ABI change (ES_ABI_VERSION = 9 unchanged).
v0.28.1rc2 2026-05-15 Folds rc1 proofread follow-ups: README BIP-vs-HD-state ambiguity (Option C — minimal table rename + clarifying paragraph) + DE441 sweep table body-identifier rename (Option B — earth/moonterra/luna). Pure README hygiene continuing the v0.28.1 docs-only patch story. No code change; no ABI change.
v0.28.1rc1 2026-05-15 Docs-only patch: stale "Unreleased" bullets removed from python/README.md. Two bullets at the top of the version-by-version list framed LLM tool-schema export + the first cosmology-instrument pair as future work; both had actually shipped in v0.26.1. The PyPI-rendered README on v0.28.0 still showed both as Unreleased. v0.28.1rc1 removes both bullets and leaves a brief HTML comment documenting the cross-package tool_schema architecture (srmech provides the framework; ephemerides-spectral's [profile.tool_schema].extension_file = "_srmech_tool_schema.toml" registers our 9 profile-tier surfaces with owner="ephemerides"; the local bridge.get_tool_schema introspects ~246 functions in 4 formats). No code change; no ABI change (ES_ABI_VERSION = 9 unchanged); no test ratchet changes. Pure docs hygiene.
v0.28.0 2026-05-14 Production cut after the v0.28.x rc stack — Task #212 closed (ADR-0001 §7 Step 2 done). Version-only bump from 0.28.0rc50.28.0. Cumulative content from the rc cycle: Phase 10a per-body equation-of-center catalog (rc1; 51 closed-form Newton-Kepler patches) + srmech [profile.native] plugin tier + ABI v6→v8 silent-rejection realignment + es_laplacian.c native-parity drift fix (rc3) + bridge call-site migration through srmech.profile.native with four-way native parity (rc4) + Phase 10a EOC C-side completion (rc5, ABI v8→v9 — closes the rc1 backend_caveat, EOC patches now byte-identical on both backend="bip" AND backend="c"; ES_MAX_PATCHES 32→64 to fit the 51-body catalog). Each rc verified on TestPyPI in a clean external venv before merge. ABI v8 → v9 wire-format change captured at load-time handshake (graceful degrade to pure-Python on mismatch).
v0.28.0rc5 2026-05-14 Phase 10a EOC C-side completion (ABI v8 → v9). Final rc in the v0.28.x stack. Closes the rc1 backend_caveat: per-body equation-of-center patches now produce byte-identical phase residues on both backend="bip" AND backend="c" across all 52 bodies at every Δt tested. C-side: new patch kind ES_PATCH_KIND_ECCENTRICITY_CORRECTION = 2; es_patch_t extended with 3 trailing double fields (eccentricity, mean_anomaly_at_j2000_rad, n_rad_per_day); Newton-Kepler evaluator es_eval_eoc_residue (bounded 30-iter, tol 1e-14 rad, warm-start E = M + e·sin M for e > 0.6, half-angle true-anomaly, floor-based principal-branch wrap); new es_clear_eoc_patches selective clear. JPL Power-of-Ten clean (no goto, no malloc, all loops bounded, ≥2 asserts/function, ≤60 lines/function). Python: EXPECTED_ABI_VERSION 8→9; EsPatch ctypes struct extended; native_apply_eoc_patch + native_clear_eoc_patches helpers; _mirror_patch_to_native gains EOC dispatch branch; bridge.apply_eoc_patches / clear_eoc_patches backend-aware with Python+C rollback parity. srmech [profile.native].expected_abi_version 8→9. New test_eoc_patch_byte_parity_across_backends ratchet pins byte-exact EOC parity at 4 Δt epochs (J2000, ±1 yr, +20 yr, -100 yr); rc1 python-only ratchet flipped positive. JPL audit pins updated (PIN_RULE_5_TOTAL_FUNCS 42→46; PIN_RULE_5_ASSERTIONS 88→102; density 2.22 ≥ 2.0). ABI wire-format: sizeof(es_patch_t) +24 bytes; ABI handshake catches v8/v9 mismatches and degrades to pure-Python rather than producing silent garbage. After rc5 verifies on TestPyPI + autonomous merges, the v0.28.0 production-cut PR opens for human-in-loop review.
v0.28.0rc4 2026-05-14 Task #212 PR-c — bridge call-site migration through srmech.profile("ephemerides").native. Final PR of Task #212 (ADR-0001 §7 Step 2 call-site-migration portion). New _load_via_srmech_profile() in _native_bip.py lazily imports srmech, calls srmech.profile("ephemerides"), and reuses the loaded CDLL handle when available; the existing direct ctypes.CDLL() path remains as the fallback for sdist / pure-Python / srmech-absent environments. _native_bip.LIB and srmech.profile("ephemerides").native are now the SAME Python object (Python is identity) — patch-registry runtime state stays consistent across both surfaces. New module global LOAD_SOURCE ∈ {"srmech_profile", "direct_ctypes", None}. 3 new ratchets in test_native_parity.py pin a four-way parity property: Python BIP / profile-loaded native / direct-ctypes native / bridge backend="c" all byte-identical at the same JD. Pure-Python additive; no ABI bump (path rearrangement; no C-side surface change).
v0.28.0rc3 2026-05-14 Task #212 PR-b — srmech [profile.native] plugin tier + ABI v6→v8 realignment + native-parity drift fix. ephemerides-spectral's srmech profile graduates from "simple" to "plugin" tier. New [profile.native] block: library = "ephemerides_spectral", install_path, abi_version_function = "es_abi_version", expected_abi_version = 8; 8 declared [profile.native.symbols.*] covering encoder hot path + introspection accessors. Closes the silent-rejection bug that had quietly forced pure-Python fallback for every v0.16.0+ install (_native_bip.EXPECTED_ABI_VERSION was left at 6 while the C library advanced to 8 in v0.16.0). es_laplacian.c regenerated against the same stub-fallback state _data/initial_phases.json uses; both sides now byte-agree on all 52 bodies. (rc2 was a failed-publish tombstone — the cibuildwheel Linux matrix surfaced the parity drift that rc3 fixed.) 13 new ratchets in test_srmech_profile.py. Pure-Python additive; no ABI bump (C-side ES_ABI_VERSION stays at v8; the Python-side realignment is a catch-up only).
v0.28.0rc1 2026-05-14 Phase 10a — Per-body equation-of-center catalog (PEP 440 alpha pre-release of v0.27.0). Closed-form Kepler series patches for every non-Sun body in the 52-body BIP roster (51 patches; Sun has e ≡ 0 → no EOC). New EccentricityCorrectionPatch kind in diagnosed_fibers.py — Newton-iteration on E − e·sin E = M (bounded 30-iter loop, tol 1e-14 rad) + half-angle true-anomaly formula; J2000-anchored by construction (patch evaluates to 0 at Δt=0 so BIP's L_true(J2000) calibration isn't double-counted); exact at any eccentricity from Triton's e ≈ 1.6e-5 through Nereid's e = 0.7507. New _research/secular_elements_data.py — 51-row J2000 Keplerian-elements catalog, frame partition 13 heliocentric + 38 parent-centric, 16 subsystem-authority SOURCES (Standish 1992 / Park 2021 DE441 / Chapront 1991 ELP2000 / Lainey 2007 MAR063 / Lieske 1998 E5 / Cooper 2006 / Jacobson 2000 / Vienne-Duriez 1995 TASS / Spitale 2006 / Jacobson 1998 Phoebe / Laskar-Jacobson 1987 GUST86 / Jacobson 2009 NEP078 / Brozovic 2015 Charon / JPL SBDB / Murray-Dermott 1999). New _research/eoc_catalog.py generator. New AMSC source secular_elements (literature_curated adapter); n_sources 19 → 20; adapter_class="curated" 16 → 17. Six new bridge surfaces (list_secular_elements, get_secular_elements, list_eoc_patches, get_eoc_patch, apply_eoc_patches, clear_eoc_patches) + six CLI subcommands; LLM tool-schema auto-discovers them (240 → 246). 39 new test ratchets in tests/test_eoc_catalog.py. Validation: 100-yr Earth-Mars syzygy sweep with Earth+Mars EOC active collapses Kepler-truth Δλ at BIP-opposition JDs from 9.26° RMS (15.75° peak) to 0.014° RMS (0.015° peak) — a 99.85% collapse to numerical precision. Anchor-date offsets vs textbook Mars-opposition dates drop from 19.79 d RMS (35.32 d max) to 1.12 d RMS (3.05 d max) — 94% collapse. Residual 1.12 d is the genuine Mars-Jupiter direct fiber, Phase 10b's target. Sun-from-SSB wobble hypothesis (bin-5 at 20.07 yr ≈ J-S synodic) tested closed-form and falsified at 0.7% collapse — note stashed at docs/srmech/notes/sun-wobble-falsification-2026-05-14.md as the first published-internal Phase-10b candidate falsification. Backend caveat: Python BIP backend only in this alpha; C-side support requires an ABI bump (new ES_PATCH_KIND_ECCENTRICITY_CORRECTION) queued for v0.27.0 or v0.28.0. Workflow tag-regex extended to accept PEP 440 aN/bN/.devN suffixes; auto-routing: rc/.dev → TestPyPI, clean / aN / bN → PyPI as pre-release. Pure-Python additive; no ABI bump (ES_ABI_VERSION = 8 unchanged). Verified on TestPyPI via 0.28.0rc1.dev1 cycle before the production PyPI alpha upload.
v0.26.1 2026-05-14 Production cut: Task #197 Phase 4 AMSC migration to srmech.amsc.* + LLM tool-schema export + first cosmology-instrument pair + v0.27.0-phase-A AMSC backfills. Verified on TestPyPI as 0.26.1rc1 (PR #396; tag ephemerides-spectral-v0.26.1rc1) against srmech==0.1.1rc9 ahead of the srmech v0.2.0 production cut; 15-cell cibuildwheel matrix + end-to-end venv install + srmech.__version__ == "0.1.1rc9" assertion all passed. Runtime dep bumped to srmech>=0.2.0 for the production cut. 12 AMSC framework modules (~2,931 LOC) removed from the ephemerides-spectral wheel — they now live in srmech.amsc.* on PyPI; no ephemerides_spectral.bridge public-API changes (delegation handled by _bootstrap_amsc() at import). LLM tool-schema export: self-describing bridge surface for ~240 public functions in four formats (Anthropic Claude tool-use / OpenAI function-calling / Anthropic MCP / plain JSON Schema). Three new bridge surfaces (get_tool_schema, list_tool_names, get_one_tool_schema) + three CLI subcommands (tool-schema, tool-names, tool-schema-one). Self-describing API — no hand-maintained tool list; ratchet test_every_tool_has_non_empty_description enforces docstring discipline. First cosmology-instrument pair: cmb_power_spectrum (Planck 2018 PR3 binned TT, 111 bands ℓ=2..2499, first acoustic peak at ℓ ≈ 225 with D_ℓ ≈ 5793 μK²) + cmb_anomalies (six canonical large-scale anomalies — Axis of Evil, Cold Spot, hemispherical power asymmetry, low quadrupole, parity asymmetry, missing C(θ)). Five new bridge functions + five CLI subcommands. n_sources 17 → 19; adapter_class="curated" 14 → 16. Catalog modules follow AMSC-first pattern — read directly from attested NDJSON via the universal accessor. Pure-Python additive; no ABI bump (ES_ABI_VERSION = 8 unchanged).
v0.26.0 2026-05-08 Schema-gap-driven trigger — closes the Mathematical Provenance Method loop. The system identifies what it doesn't know and points at attested sources that could populate the gap. New bridge.suggest_gap_collections(*, ood_threshold=0.85) reads the v0.24.10 OOS probe roster, runs each probe through the v0.24.9 dynamical-regime classifier, identifies regime gaps (OOD / spurious-match / surprise), matches each gap against descriptors via [gap_targeting].regime_labels declarations, and emits a deterministic suggestion list. Three real gaps surface immediately on the v0.25.x descriptor set: phobos (chaotic-Mars surprise; 0 candidates), ceres (OOD-flagged; 0 candidates), vesta (v0.24.12-introduced spurious landing; 0 candidates) — all three need new attested sources whose [gap_targeting] covers currently-untargeted regimes, exactly the scope a v0.26.x research thread will surface. New CLI subcommand suggest-gap-collections [--ood-threshold N]. CI auto-PR automation that consumes the suggestion surface lands in a future v0.26.x ship; v0.26.0 ships the analysis surface — the suggestion API is itself the deliverable. Pure-Python additive; no ABI bump (thirty-ninth consecutive ship since v0.13.x). 10 new tests. The eigenbasis points at its own next ground-proof row.
v0.25.2 2026-05-08 Attested collector — T3 live query. Completes the four-tier reproducibility model from notebook §18.1. New bridge.get_attested_dataset(source_key, *, live=True) invokes the descriptor's declared adapter against the upstream archive at call time; rows carry full per-row attestation + the response envelope adds tier="T3" + retrieved_at + upstream_response_sha256s for paper-appendix replay. Baseline tier (live=False, default) now also carries an explicit tier="T0+T1+T2" discriminator. CLI: attested-dataset --live flag. Adapter errors during live fetches surface as ok=False with diagnostic + retrieved_at. T3 is the weakest reproducibility tier: each row's response_sha256 documents the upstream content currently served; replay requires re-fetching against an unchanged upstream OR archiving response bytes alongside the recorded attestation. Pure-Python additive; no ABI bump (thirty-eighth consecutive ship since v0.13.x). 7 new tests. EarthRef SC descriptor's canonical_doi populated (10.1029/2009GL040749; empty string was rejecting MPR validation).
v0.25.1 2026-05-08 Attested collector — T2 user runtime kernel. Local NDJSON overlay layer atop the v0.25.0 T0+T1 baseline (notebook §18.1's four-tier reproducibility model). New bridge.use_local_kernel(path) registers an overlay directory shaped like <source_key>/<table>.ndjson; once registered, queries consult the overlay FIRST per source and REPLACE the baseline for any source whose table file exists in the overlay. bridge.clear_local_kernel and bridge.get_local_kernel_state round out the API; the state surface includes a cache hash (SHA-256 over canonical-serialised (source_key, ndjson_sha256) pairs) for paper-appendix replay. Three new CLI subcommands (local-kernel-use, local-kernel-clear, local-kernel-state). Reproducibility tier: T2. Default REPLACE policy; APPEND may land in a later v0.25.x. Pure-Python additive; no ABI bump (thirty-seventh consecutive ship since v0.13.x). 11 new tests. T3 live query ships v0.25.2.
v0.25.0 2026-05-08 Attested Multi-Source Collector framework v1 — three pilots end-to-end (EarthRef SC + GMRT + PetDB v4) + T1 collect CI workflow + MPR v1 normative format. Completes the v0.25.0a/b ship sequence (notebook §18). CONFIG-not-CODE escape from the v0.24.x hand-coding pattern: each new attested source is a TOML descriptor + JSON Schema, consumed by a generic 5-adapter shared core, producing canonical NDJSON ground-proof rows with mandatory attestation blocks. Adapter coverage: html_scraper, json_api, csv_bulk real impls (lazy requests + bs4); netcdf_grid + geotiff_bbox ship as fixture-only stubs gated behind collector-netcdf / collector-geotiff extras (rasterio/gdal stays out of v0.25.0 maintenance). T1 collect CI workflow ephemerides-spectral-collect.yml runs collectors against live archives on schedule (monthly) + manual dispatch; opens auto-PR with refreshed NDJSON; maintainer reviews per-row citation provenance before merging. New codegen/run_collectors.py is the only network-touching code path; regenerate.py does no network I/O (ratchet-pinned). MPR (Mathematical Provenance Record) v1 is normative — once shipped, future bumps require explicit migration. Format aligns with the discipline name from §0.0: The Mathematical Provenance Method. Pure-Python additive; no ABI bump (thirty-sixth consecutive ship since v0.13.x). 38 new tests.
v0.24.12 2026-05-07 Loki Patera Eruption Cycle (Io tidal-heating temporal-spectrum cousin to v0.24.8 Axial Seamount; Galilean Laplace 4:2:1 forcing) — eleventh ship in v0.24.x; second temporal-spectrum observable on a single sub-system. Same temporal_quasi_periodic_cycle regime label as v0.24.8 Axial — explicitly densifies the regime rather than opening a new one. Headline closure: Galilean Laplace commensurability 4·P_Io ≈ 2·P_Europa ≈ P_Ganymede verified to within ~1% by published periods (libration around exact resonance, not strict equality). Peale-Cassen-Reynolds 1979 used this near-commensurability to predict Io's tidal heating two weeks before Voyager 1 confirmed active volcanism. Loki Patera physics: ~200 km diameter lava lake at 12.7° N / 309.6° W; the largest persistent thermal anomaly in the Solar System; accounts for 5-15% of Io's globally-integrated ~10¹⁴ W tidal dissipation budget (~2-3 orders of magnitude larger than Earth's total volcanic output). Quasi-periodic ~540-day brightening / resurfacing cycle (Rathbun 2002 GRL canonical paper). 6-cycle-peak observation roster (1990-2017) + 6 action-angle modes + 8-entry SOURCES citation dict. Schema-gap surfacing: adding Loki at spatial_scale_log_km=2.30 made it a near-twin to Vesta (2.42), collapsing Vesta's calibration ratio from 0.98 (honest "I don't know") to 0.79 — Vesta now lands on rigid_body_chaotic_obliquity as a SPURIOUS classification. Pinned in tests as the next schema-gap to close (small-body-radiation row needed). Mathematical Provenance Method: the v0.24.x discipline is formally named — closed-form np.linalg.eigh on labelled ground-proof rows, no SGD, no random init. Pure-Python additive; no ABI bump (thirty-fifth consecutive ship since v0.13.x). New tests/test_loki_patera_eruption_cycle.py (41 tests).
v0.24.11 2026-05-07 Pluto-Charon Dynamical Spectrum (binary mutual tidal lock; Path-B closure of v0.24.10 OOS-probe-roster schema-gap) — fourth per-body action-angle ship in v0.24.x; first binary mutual-tidal-lock entry. Mutual orbital period = both spin periods = 6.387 d (the Solar System's only known double-synchronous binary planet; the END STATE of dyadic tidal evolution). Eccentricity 5e-5 (~1100x smaller than Luna's 0.0549) + mutual obliquity 0.0006° confirm the system has reached completion. Mass ratio Charon/Pluto = 0.122 (the largest binary mass ratio in the Solar System); barycenter sits ~940 km outside Pluto's surface. Cross-channel: 4 small moons at near-3:4:5:6 with the mutual orbital period (Hydra closest at 0.32% off; Showalter-Hamilton 2015 chaotic in libration). Path-B closure: rather than engineer a new feature to discriminate Pluto-Charon from Mercury (which would alter eigenbasis numerics), v0.24.11 populates the missing regime with a real ground-proof row + new label rigid_body_action_angle_mutual_lock. Pluto-Charon probe self-classifies cleanly; Enceladus + Io now land on mutual_lock (was Mercury-stable). Two new gaps surfaced as a result: asymmetric-satellite-with-partner-resonance (Enceladus, Io); rigid-stable-no-commensurability (Ceres, Vesta) — documented for future ships. Reframing: v0.24.x catalogs now consistently called ground-proof rows, not training data — the classifier's "training step" is np.linalg.eigh (closed-form, deterministic, byte-identical). Pure-Python additive; no ABI bump (thirty-fourth consecutive ship since v0.13.x). New tests/test_pluto_charon_dynamical_spectrum.py (33 tests). 1782 tests pass, 42 skipped.
v0.24.10 2026-05-07 OOS probe catalog + classifier calibration-ratio metric — closes a v0.24.9 loose end and surfaces a latent diagnostic. Two payloads: (1) curated 10-probe out-of-sample roster (Yellowstone, Reunion, Pluto-Charon, Enceladus, Io Galilean Laplace, Phobos, Ceres, Alpha Centauri B, Vesta, magnetar) that ratchet-pins the v0.24.9 classifier's behaviour on real bodies not in the v0.24.0–v0.24.8 training set; (2) the calibration_ratio = nearest_distance / 2nd_nearest_distance + out_of_distribution flag, surfaced as first-class fields on classify_dynamical_regime (the diagnostic was latent in distances_to_all from v0.24.9 but never summarised). Reframing: the catalog module docstring now explicitly notes the classifier is NOT machine learning in the SGD sense — its "training step" is a closed-form np.linalg.eigh call: no random init, no SGD, no hyperparameter search, no validation split, no pseudorandom anywhere. Probes are test vectors, never training data. Probe results: 8 match expected + 1 correctly OOD-flagged (Vesta, ratio 0.98) + 1 let-classifier-surprise-us (Phobos) = 0 unexpected classifications in the summary aggregate. The probe roster is honest about both the feature-schema gap (Pluto-Charon / Enceladus / Io with commensurabilities-but-no-Saros-track collapse onto Mercury-stable; documented as ratchet) and surprising classifications (magnetar's dimensionality dominates over size mismatch). Pure-Python additive; no ABI bump (thirty-third consecutive ship since v0.13.x). New tests/test_dynamical_regime_probes.py (33 tests).
v0.24.9 2026-05-07 Dynamical-Regime Classifier (eigenbasis-projection version of the v0.24.x if/else chain) — tenth and capstone ship in v0.24.x; the project's first explicit meta-consumer of the v0.24.x methodology arc. Replaces the aspirational hand-coded if/else chain ("if body has commensurability, dispatch to Mercury / Luna methodology; else if body is chaotic, dispatch to Mars methodology; …") with a learned eigenbasis projection over the v0.24.x catalogs themselves. 9 labelled training examples (one per v0.24.0–v0.24.8 ship), 7 features per example (time_scale_log_s, spatial_scale_log_km, stability_index, has_commensurability, prediction_track_signal, dimensionality, forcing_class_index), principal-component decomposition over the standardised feature matrix; nearest-neighbour classification in the top-k eigenbasis. Top 3 PCs explain ~83% of variance; top 4 explain ~94%. 9/9 self-classification accuracy. Out-of-sample probes do sensible things: Yellowstone hotspot → bounded_local_laplacian_trajectory (Hawaii-like); K-dwarf star → continuum_normal_modes (Sun-like); Enceladus → rigid_body_action_angle_stable (Mercury-like, Luna 2nd-nearest). Same Fiedler / eigenbasis machinery as v0.18.0 body_architecture, v0.24.5 Hawaii, v0.24.7 Mars Tharsis — applied to the v0.24.x ships themselves as data points. Pure-Python additive; no ABI bump (thirty-second consecutive ship since v0.13.x). New tests/test_dynamical_regime.py (48 tests).
v0.24.8 2026-05-07 Axial Seamount Eruption Chronology Catalog (temporal-spectrum eruption-cycle observable on a real-time-monitored submarine volcano) — ninth ship in v0.24.x; the project's first explicit prediction-reliability ship. Active submarine volcano on the Juan de Fuca Ridge (~480 km off Oregon). 3-eruption roster (1998 / 2011 / 2015) + 4 inflation-phase records (pre-1998, 1998-2011 ~15 cm/yr, 2011-2015 ~70 cm/yr, post-2015 ~20 cm/yr) + 2 Chadwick-Nooner forecasts (2015 HIT via OOI Cabled Array 6-month lead, 2024-2025 MISS as of catalog reference year 2026 due to post-2015 inflation slowing). THE HEADLINE PAYLOAD: published track record of one HIT and one MISS on the same body. Same Chadwick-Nooner methodology (constant inflation-rate-controlled trigger) succeeds for the 2015 cycle and fails for the 2024-2025 cycle because the post-2015 inflation rate slowed below the 2011-2015 reference, breaking the constant-rate extrapolation. Cross-channel: direct parallel to v0.24.2 Mars secular-resonance chaos at decade / cm-per-year scale instead of Gyr / arcsec-per-year. Same algebraic structure on two wildly different observational scales — the project's cleanest cross-system spectral-stability observation. Pure-Python additive; no ABI bump (thirty-first consecutive ship since v0.13.x). New tests/test_axial_seamount.py (40 tests). 1665 tests pass, 42 skipped.
v0.24.7 2026-05-07 Mars Tharsis Volcanic Chain Catalog (bounded-local Laplacian on a body WITHOUT plate tectonics) — eighth ship in v0.24.x; the no-plate-tectonics counterpart to v0.24.5 Hawaii. Same Gaussian-spatial-proximity Laplacian + Fiedler-eigenpair machinery as v0.24.5, applied to a 5-volcano roster on Mars (Olympus Mons + Arsia/Pavonis/Ascraeus Montes + Alba Mons). Olympus Mons (~22 km from base to summit, the largest volcano in the Solar System) is the direct consequence of the no-plate-tectonics regime: the same plume that produces a 6500-km hotspot chain on Earth instead builds one super-volcano on Mars because the lithosphere is unbroken. Two spectral observations: (1) bounded-local Fiedler partition isolates Alba Mons (the geographically distant N outlier) from the four young Tharsis-region volcanoes, with eigenvalue gap λ₃ − λ₂ ≈ 0.51·λ₂; (2) Tharsis Montes ridge alignment + outlier residuals — Olympus Mons sits ~1900 km off the ~040° NE-SW ridge axis, Alba Mons ~1200 km off; structural-not-temporal residuals. Cross-channel observation: there is no directional bend because there is no plate motion to record one. Hawaii (with plate tectonics) → trajectory; Mars (no plate tectonics) → cogenetic family. Pure-Python additive; no ABI bump (thirtieth consecutive ship since v0.13.x). New tests/test_mars_tharsis.py (35 tests). 1624 tests pass, 42 skipped.
v0.24.6 2026-05-07 Small-body Yarkovsky/YORP Catalog (thermal-radiation orbital + spin drift) — seventh ship in v0.24.x. Per-asteroid Yarkovsky semi-major-axis drift (anisotropic thermal re-emission produces a force; prograde rotators drift outward, retrograde inward) + YORP spin-state evolution (irregular-shape thermal torque drives spin rate + obliquity toward attractors at ~55° / ~125°). 10-asteroid roster: Bennu (OSIRIS-REx; first imaged Yarkovsky -19e-4 AU/Myr inward; Chesley 2014), 2000 PH5/YORP (first YORP detection 12-min rotation; Lowry 2007), Apophis (2068 close approach impact-prediction relevance; Vokrouhlický 2015), Ryugu, Itokawa (spin-DOWN), Apollo, Geographos, 1950 DA (at 2.121-h fission limit), Golevka (first-ever Yarkovsky detection; Chesley 2003), Eger. Threshold constants: rotational-fission ~2.2 h, observability ~30 km, YORP attractors 55°/125°. Cross-channel: spin-FREE counterpart to v0.23.0's spin-orbit-LOCKED roster; radiation-coupled analogue of v0.24.2 Mars's gravitational-secular-resonance chaos. Pure-Python additive; no ABI bump (twenty-ninth consecutive ship since v0.13.x). New tests/test_yarkovsky_yorp.py (34 tests). 1586 tests pass, 42 skipped.
v0.24.5 2026-05-07 Hawaiian-Emperor Chain Spectral Catalog (bounded-local graph Laplacian) — sixth ship in v0.24.x; the first time the project's graph-Laplacian eigenbasis is applied to physical features on a single body's surface rather than to orbital relationships between bodies. Demonstrates the bounded-local-Laplacian / chess-board insight as an explicit ship. 18-seamount roster spanning ~85 Myr (Meiji → Big Island Kilauea). Two complementary spectral observations: (1) bounded-local Fiedler partition with exactly one sign change along age-ordered chain (quasi-1D structural property; eigenvalue gap λ₃ − λ₂ ≈ 3× λ₂); (2) age-vs-arc-length linear-fit residuals giving Pacific Plate velocity ≈ 8.5 cm/yr (matches Sharp 2006 published 8-10) with bend at 47.5 Myr surfacing in slope residuals (Meiji largest residual ~1265 km). Same algebraic machinery as v0.18.0 body_architecture Fiedler partition; cross-strand observation with paleomagnetic Tarduno 2003 evidence. Pure-Python additive; no ABI bump (twenty-eighth consecutive ship since v0.13.x). New tests/test_hawaii_chain.py (28 tests). 1549 tests pass, 42 skipped.
v0.24.4 2026-05-07 Per-body Toroidal-Residual J₂ Catalog (Maclaurin/Jacobi/bar-ring sequence) — fifth ship in v0.24.x; the shape-side counterpart to v0.24.0–v0.24.3 dynamical-spectrum surfaces. Codifies the rotation-makes-the-toroidal / self-gravity-rounds-it insight as a per-body classification on the Chandrasekhar 1969 ellipsoidal-equilibrium sequence. Each body parameterised by q = ω²R³/(GM); thresholds at q = 0.187 (Maclaurin → Jacobi bifurcation), 0.27 (bar instability), 0.36 (Roche fission → ring/torus). 14-body roster: saturn closest to bifurcation (q ≈ 0.158; most oblate Solar-System body, 1/10 flattening), jupiter (q ≈ 0.089), uranus + neptune + mars + terra all maclaurin; luna + mercury fossil figures (J₂ exceeds current-rotation prediction by 25-50×; shapes frozen at earlier faster-rotation epochs); venus extreme-sphere (q ~ 6e-8). 14-entry SOURCES citation dict + 3 theory references (Chandrasekhar 1969, Lai 1994, Helled 2011). Pure-Python additive; no ABI bump (twenty-seventh consecutive ship since v0.13.x). New tests/test_toroidal_residual.py (34 tests). 1518 tests pass, 42 skipped.
v0.24.3 2026-05-07 Sun Dynamical Spectrum (helioseismic p-modes) — fourth per-body dynamical-spectrum surface; first stellar entry + methodology extension from rigid-body action-angle (Mercury / Luna / Mars) to stellar-oscillation continuum normal-mode spectrum. Headlines: Δν = 135.1 μHz (large frequency separation; sound-travel-time inverse), δν = 9.0 μHz (small separation; helium-core diagnostic), ν_max = 3090 μHz (peak amplitude; Brown 1991 g/√T_eff scaling). 20-mode sample p-mode catalog (n=18-25 at l=0-2; the high-SNR comb near ν_max). THE headline closure invariant: Tassoul 1980 asymptotic relation ν_{n,l} ≈ Δν · (n + l/2 + ε) - δν · l(l+1) / (n + l/2 + ε) predicts the entire mode comb from three constants. Cross-channel parallel: stellar-oscillation analogue of v0.24.1 Saros integer-commensurability. The Sun is the only star where individual modes resolve to high SNR (BiSON / SOI-MDI / SDO-HMI). Pure-Python additive; no ABI bump (twenty-sixth consecutive ship since v0.13.x). New tests/test_sun_dynamical_spectrum.py (30 tests). 1481 tests pass, 42 skipped.
v0.24.2 2026-05-07 Mars Dynamical Spectrum (chaotic obliquity / Laskar) — third per-body dynamical-spectrum surface; the contrast case to Mercury (clean Le Verrier closure) and Luna (clean Saros commensurability). Mars is the canonical observable signature of KAM-theory small-denominator failure in the Solar System: secular-resonance overlap between Mars's spin-axis precession (~7.58 arcsec/yr; Ward 1973) and the inner-system secular fundamentals s₃ (~−18.86 arcsec/yr) and s₄ (~−17.74 arcsec/yr) drives obliquity wandering across the 0°-60° range over Gyr (present 25.19°; mean 37.6° — Laskar et al. 2004). 8-mode action-angle catalog (orbital + spin + 3 precessions + e + i + obliquity); no spin-orbit lock (Mars is rotationally free); C/MR² = 0.3645 ± 0.0005 (Le Maistre 2023 InSight RISE; cross-references v0.21.4). THE chaos invariant is min_proximity_arcsec_yr < 12 arcsec/yr — the Laskar 1993 chaos-onset threshold — pinned in tests. Where Mercury's v0.24.0 closure was a successful sum and Luna's v0.24.1 closure was a successful integer commensurability, Mars's v0.24.2 "closure" is a failure mode: secular frequencies overlap so tightly that the action-angle quasi-periodic torus structure breaks down. Cross-channel observation: without Earth's stabilising Moon (v0.24.1 LLR-constrained), Earth would be subject to Mars-style obliquity chaos — v0.24.1 + v0.24.2 together ship the quantitative argument for why Earth has stable seasons. Pure-Python additive; no ABI bump (twenty-fifth consecutive ship since v0.13.x). New tests/test_mars_dynamical_spectrum.py (33 tests). 1448 tests pass, 42 skipped.
v0.24.1 2026-05-07 Luna Dynamical Spectrum — second per-body dynamical-spectrum surface; LLR-anchored complement to v0.24.0 Mercury. Same simple-target pattern (no atmosphere, no ocean) but the canonical Earth-tidal case; LLR is the most precise libration measurement programme in the Solar System (50+ years from McDonald, Apache Point, OCA, Matera). 11-mode action-angle catalog (8 angles: sidereal/synodic/anomalistic/draconitic mean motions + spin 1:1 locked + forced libration 7.9 arcsec + apsidal 8.85 yr + nodal 18.61 yr; 3 actions: e=0.0549, i=5.145°, obliquity-to-orbit 6.687° in Cassini state 2). THE headline closure invariant: the Saros integer commensurability — 223 synodic ≈ 239 anomalistic ≈ 242 draconitic months ≈ 19 eclipse years all agree within ~0.5 day at 18.03 yr. Textbook small-denominator phenomenon. Cross-strand observation: the Antikythera mechanism's Saros dial is literally a hardware implementation of this commensurability — direct cross-link between ephemerides-spectral and antikythera-spectral. Williams 2014 LLR cross-references v0.21.6 +3.83 cm/yr migration + v0.23.0 7.9 arcsec libration (test_forced_libration_matches_v0_23_0_value pins agreement). Bundled with RTD doc-maintenance fix (addressing-maths subsumption into chess + antikythera notebooks corrected on landing page). Pure-Python additive; no ABI bump (twenty-fourth consecutive ship since v0.13.x). New tests/test_luna_dynamical_spectrum.py (37 tests). 1412 tests pass, 42 skipped.
v0.24.0 2026-05-07 Mercury Dynamical Spectrum — first per-body dynamical-spectrum surface; discipline pivot from cross-channel-coupling (v0.21.x) to action-angle decomposition of a single body's full dynamical state. Mercury chosen as cleanest first target: no moon, no atmosphere, no ocean, in the historically richest dynamical-test position. 8-mode action-angle catalog (5 angles + 3 actions) covering orbital mean motion, spin frequency (3:2 lock), forced libration (35.8 arcsec at orbital frequency, Margot 2007), perihelion-longitude precession (574.10 arcsec/century), ascending-node precession (-446 arcsec/century retrograde), eccentricity (0.2056), inclination (7.005°), obliquity (2.04 arcmin Cassini state 1). THE headline: the Le Verrier / Einstein perihelion-precession contribution-by-perturber decomposition: total observed 574.10 ± 0.65 arcsec/century (Clemence 1947) decomposes as Newtonian planetary perturbations (Venus 277.42 + Jupiter 153.58 + Earth 90.04 + Saturn 7.30 + Mars/other 3.29 = 531.63) + general-relativistic Schwarzschild correction (42.98 — Einstein 1915 prediction; Park 2017 MESSENGER measurement confirms to 1 part in 10^4) + solar quadrupole J₂ (0.025 — Park 2017). Sum closes to 574.6 within Clemence's ±0.65 uncertainty — one of the most precise quantitative confirmations of GR. Le Verrier/Einstein closure invariant pinned. Cross-channel observation: every contribution is from a neighbouring field. Pure-Python additive; no ABI bump (twenty-third consecutive ship since v0.13.x). New tests/test_mercury_dynamical_spectrum.py (31 tests). 1372 tests pass, 42 skipped.
v0.23.1 2026-05-07 Packaging fix: pyproject.toml description trimmed from 593 → 473 chars to stay under PyPI's hard 512-character Summary limit. Both v0.22.0 and v0.23.0 PyPI publishes had silently failed at the upload step because of this (twine check --strict does NOT enforce the limit; the upload endpoint silently rejects oversized metadata). Description trimmed + ASCII-only + inline # IMPORTANT: comment + new CI guard step in publish workflow that hard-fails at 512 chars / soft-warns at 480. PyPI users: pip install -U jumps from 0.21.10 directly to 0.23.1, getting all v0.22.0 + v0.23.0 features. Pure-additive metadata + workflow fix; no ABI bump. 1338 tests pass, 42 skipped (unchanged).
v0.23.0 2026-05-07 Spin-orbit resonance ↔ rotation lock — eleventh cross-channel coupling surface (resumed after v0.22.0 trajectory pivot). Closes the tidal-physics triple with v0.21.4 (Q-factor) + v0.21.6 (orbital migration); end-state of long-term tidal evolution. 8-body roster: mercury (Margot 2007 — THE 3:2 spin-orbit resonance, the only non-1:1 case in the Solar System, ~36 arcsec libration; Pettengill 1965 radar + Goldreich-Peale 1966 stability), luna (Williams 2014 LLR — 1:1 canonical, ~7.9 arcsec; most precise libration in solar system), io/europa/ganymede (Lainey 2009/2020, Van Hoolst 2008 — Galilean 1:2:4 Laplace resonance members), titan (Iess 2012 — 1:1 with anomalously large ~52 arcsec libration → subsurface H₂O ocean diagnostic), triton (Jacobson 2009 — 1:1 retrograde from KBO capture), charon (McKinnon 2017 — Pluto-Charon DUAL-SYNCHRONOUS, the unique solar-system case where both bodies are tidally locked to each other). Period-consistency invariant pinned: T_rot/T_orb ≈ q/p within ±1%. Mercury-only-non-1:1 invariant pinned. Pure-Python additive; no ABI bump (twenty-first consecutive ship since v0.13.x). New tests/test_spin_orbit_resonance.py (30 tests). 1338 tests pass, 42 skipped.
v0.22.0 2026-05-07 Trajectory + Sensing Layer — discipline pivot out of v0.21.x cross-channel-coupling sequence into applied-physics propagators. Four-layer surface: Layer A per-body short-range ballistic propagator with optional exponential-atmosphere drag (BC = m/(C_d·A)), 7-body roster (terra/mars/venus/titan/luna/mercury/jupiter); vacuum closed form Vallado §8.6.2. Layer B Earth 3-regime ICBM (boost as boundary; midcourse Kepler BMW Ch. 6; re-entry Allen-Eggers NACA 1381 1958); 3 reference profiles (SRBM/MRBM/ICBM) from Wilkening 2000 + Sessler/UCS 2000. Layer C(a) sensor access: WGS-84 + ECEF/ENU + slant-range/elevation/azimuth + Earth-limb occlusion (Vallado Ch. 11); SGP4 via sgp4 package; 8 reference TLEs (ISS, Sentinel-1A, NOAA-20, IRIDIUM-NEXT, GOES-16, Molniya, Tundra, Landsat-9); IR transmission windows. Layer C(b) decoy discrimination: BC-differential velocity separation in 60-100 km drag tail (Allen-Eggers); 4 reference BC classes (heavy_rv/light_rv/replica_decoy/chaff_decoy). Trauma-informed defensive scope: textbook physics + public TLEs + textbook geometry only; specific RV signatures, sensor NEΔT, kill-vehicle parameters, threat-library specifics intentionally out of scope. Boost-phase trajectory deliberately not modelled (vehicle-specific Isp/thrust/gravity-turn). 14 new bridge surfaces; 14 new CLI subcommands; 23 citations. Pure-Python additive; no ABI bump (twentieth consecutive ship since v0.13.x). 4 new test files (29+24+24+26 = 103 tests). 1306 tests pass, 42 skipped.
v0.21.10 2026-05-07 Heliocentric flux ↔ surface temperature — tenth cross-channel coupling surface (post-trio). Stefan-Boltzmann radiative-equilibrium decomposition T_eq = ((1-A)·S/(4σ))^(1/4) of v0.20.2 observed temperatures into greenhouse + tidal + internal-heat contributions. 6-body roster: terra (Kiehl 1997 — +33.5 K canonical greenhouse), mars (Haberle 2013 — naked planet, ~5 K only), venus (Bullock 2001 — +505 K RUNAWAY greenhouse; surface hotter than Mercury despite being further from Sun; THE HEADLINE), mercury (Hapke 1981 — pure radiative balance, no atmosphere → all offsets zero), titan (Strobel 2009 — +9 K CH₄/N₂ greenhouse + 2 K Saturnian tidal), jupiter (Hubbard 1999 — +45 K internal-heat dominated; Jupiter radiates 1.7× what it absorbs, primordial cooling + helium-rain). Decomposition consistency invariant pinned: T_obs - T_eq ≈ greenhouse + tidal + internal (±5 K). Pure-Python additive; no ABI bump (nineteenth consecutive ship since v0.13.x). New tests/test_thermal_balance.py (28 tests). 1190 tests pass, 41 skipped.
v0.21.9 2026-05-07 Volcanic outgassing ↔ atmospheric composition — ninth cross-channel coupling surface (post-trio); CLOSES the six-ship Io→Jupiter mass-transfer pipeline. Forms the supply-side of atmospheric mass balance with v0.21.7 escape as demand-side. 6-body roster: terra (Burton 2013 — 3 kg/s CO₂; balanced by silicate weathering NOT escape; classic carbon cycle); mars (Halevy 2014 — dormant; ~0 outgassing while v0.21.7 escapes 2 kg/s → "dead planet"); venus (Bullock 2001 — 0.5 kg/s SO₂ active hotspots); io (Lellouch 2007 — 1 ton/s SO₂ tidal volcanism; THE HEADLINE, cross-references v0.21.8 100 TW heating); enceladus (Hansen 2011 INMS — 200 kg/s H₂O plume venting → Saturn E-ring supply); jupiter (Bagenal 2007 — 1000 kg/s Io plasma torus injection; matches v0.21.7 escape rate). 6-mechanism enumerated vocabulary. Six-ship closure — v0.19.0 + v0.20.1 + v0.21.5 + v0.21.7 + v0.21.8 + v0.21.9 form a coherent observational picture of the Io→Jupiter mass-transfer pipeline. Pure-Python additive; no ABI bump (eighteenth consecutive ship since v0.13.x). New tests/test_volcanic_outgassing.py (24 tests). 1163 tests pass, 41 skipped.
v0.21.8 2026-05-07 Heat flow ↔ tidal heating — eighth cross-channel coupling surface (post-trio); CLOSES the tidal-energy-budget loop with v0.21.4 + v0.21.6. For a body with measured total surface heat flow + measured tidal-Q (v0.21.4), the heat flow constrains the energy-budget decomposition into tidal / radiogenic / primordial-cooling contributions. Cross-channel reach: v0.21.4 + v0.21.6 + v0.21.8 close the tidal-energy-budget loop — for Io, Q≈80 + +3.6 cm/yr migration imply tidal dissipation power matching observed ~100 TW surface heat flow. 6-body roster: terra (Davies 2010 — 47 TW radiogenic-dominated, tidal negligible); mars (Khan 2023 InSight — 0.1 TW radiogenic; cooled faster than Earth); io (Veeder 2012 Galileo PPR — 100 TW = 99% tidal; THE HEADLINE; most volcanically active body in solar system, 2× Earth despite 4× smaller radius); europa (Vance 2018 — 0.5 TW tidal-dominated; maintains subsurface ocean); enceladus (Howett 2011 Cassini CIRS — 10 GW SP plume-driving tidal dissipation); titan (Tobie 2008 — 2 TW with substantial tidal heating in icy outer mantle from Saturn). 3-fraction decomposition (tidal/radiogenic/primordial) summing to ~1 pinned as invariant. Pure-Python additive; no ABI bump (seventeenth consecutive ship since v0.13.x). New tests/test_heat_flow.py (27 tests). 1136 tests pass, 41 skipped.
v0.21.7 2026-05-07 Atmospheric escape ↔ magnetic-field shielding — seventh cross-channel coupling surface (post-trio). Atmospheric escape rates depend critically on magnetic-field shielding: planets with intrinsic dipoles deflect solar wind at the magnetopause, retaining atmospheres against pickup-ion erosion. The cross-channel observation: the v0.20.2 atmospheric inventory diverges by Gyr from the v0.20.1 magnetic-multipole inventory — Mars + Venus diverge from terrestrial because they lack shielding. 6-body roster: terra (Lammer 2018 — 3 kg/s thermal Jeans, IGRF-shielded; integrated 4-Gyr loss negligible); mars (Jakosky 2018 MAVEN — 2 kg/s present-day pickup-ion; 4-Gyr loss ~10¹⁸ kg = ~50% of primordial CO₂ atmosphere; THE HEADLINE: famous "Mars lost atmosphere because it lost dynamo"); venus (Persson 2020 / Lundin 2008 ASPERA-4 — 0.4 kg/s pickup-ion despite no dipole; thick atmosphere retained by stronger gravity + induced magnetosphere); mercury (Killen 2007 — 0.01 kg/s sputtering Na/K exosphere); titan (Strobel 2008 — 30 kg/s hydrodynamic, highest absolute rate among classic atmospheric bodies; Saturn-magnetosphere shielded); jupiter (Bagenal 2007 — 1000 kg/s dominated by Io plasma torus injection of S+/O+, cross-references v0.19.0 + v0.20.1 + v0.21.5). 5-mechanism enumerated vocabulary (thermal_jeans / hydrodynamic / pickup_ion / photochemical / sputtering). Pure-Python additive; no ABI bump (sixteenth consecutive ship since v0.13.x). New tests/test_atmospheric_escape.py (23 tests). 1107 tests pass, 41 skipped.
v0.21.6 2026-05-07 Tidal-resonance ↔ orbital migration — sixth cross-channel coupling surface (post-trio). A satellite's tidal interaction with its parent body dissipates mechanical energy and transfers angular momentum; the secular semi-major-axis drift is the observable signature. 6-pair roster: terra-luna (Williams 2014 LLR — 3.83 cm/yr outward, the canonical case + most precise rate in solar system); mars-phobos (Lainey 2007 — −1.9 cm/yr inward, ~50 Myr Roche deadline); jupiter-io (Lainey 2009 — +3.6 cm/yr outward; Galilean Laplace 1:2:4 currently EXPANDING); saturn-titan (Lainey 2020 — +11 cm/yr, 100× older estimates, the headline; implies Saturn-interior resonance locking, cross-references v0.21.4 Mankovich-Fuller 2021 ring seismology); neptune-triton (Jacobson 2009 — −0.5 cm/yr retrograde inward); pluto-charon (McKinnon 2017 — 0 cm/yr dual-synchronous tidal lock; unique solar-system case). Direction-sign convention: outward positive, inward negative, locked zero. Two new bridge surfaces, two new CLI subcommands. Pure-Python additive; no ABI bump (fifteenth consecutive ship since v0.13.x). New tests/test_tidal_migration.py (24 tests). 1082 tests pass, 41 skipped.
v0.21.5 2026-05-07 Magnetic ↔ atmosphere coupling via aurorae — fifth cross-channel coupling surface (post-trio). Aurorae are the visible signature of magnetic-field-line topology mapping into the upper atmosphere; oval morphology traces internal-field geometry. 6-body roster: terra (Bonfond 2017 — solar-wind reconnection, 10¹¹ W); jupiter (Connerney 2017 Juno UVS — circular oval traces JRM33 + Io footprint; 10¹⁴ W = 1000× Earth; corotation-driven, NOT solar-wind); saturn (Hunt 2014 + Stallard 2008 — annular oval directly traces Cao 2020 axisymmetry < 0.007°); uranus (Lamy 2017 — partial oval / extreme tilt); neptune (Pryor 2007 — patchy time-variable; weakest 10⁸ W); ganymede (Saur 2015 — only intrinsic-moon-dynamo aurora; auroral-position rocking diagnoses subsurface saline ocean's induction response, a true cross-channel observation tying v0.20.0 interior + v0.20.1 magnetic catalogs through observed coupling). 6-entry SOURCES; ratchet pinned. Two new bridge surfaces, two new CLI subcommands. Pure-Python additive; no ABI bump (fourteenth consecutive ship since v0.13.x). New tests/test_auroral_coupling.py (24 tests). 1056 tests pass, 41 skipped.
v0.21.4 2026-05-07 Interior-derived rotational constraints — fourth cross-channel coupling surface, opening the post-trio sequence after v0.21.1-v0.21.3 shipped the trio explicitly named in §17.4.2. Connects v0.20.0 INTERIOR_MODELS to observed rotational behaviour through 5 distinct physics regimes. 7-body roster: terra (Mathews 2002 — FCN 430.21 d / core-mantle friction); mars (Le Maistre 2023 InSight — core radius 1830 km); jupiter (Kaspi 2018 from Juno — zonal-wind base 3000 km / 4% of radius); saturn (Mankovich-Fuller 2021 — ring-seismology revises rotation period from Voyager 10:39 → 10:33 = 0.43539 days; the headline, resolving decades-long debate); io (Lainey 2009 — Q ~80, vigorous tidal dissipation driving volcanism); europa + ganymede (Lainey 2020 shared citation — Q ~500/300 from Cassini-era astrometric fits). 6 sources for 7 bodies (Lainey 2020 covers two moons in one paper). Two new bridge surfaces: get_rotational_constraint(body=None), list_rotational_constraints(). Two new CLI subcommands. Pure-Python additive; no ABI bump (thirteenth consecutive ship since v0.13.x). New tests/test_rotational_constraint.py (26 tests). 1029 tests pass, 41 skipped.
v0.21.3 2026-05-07 Orographic forcing of atmospheric standing waves — third cross-channel coupling surface in the §17.4.2 v0.21.x sequence; completes the trio explicitly named in §17.4.2. For a body with both topography (v0.20.0) and atmosphere (v0.20.2), surface topography acts as a lower-boundary forcing on the global circulation, generating downstream stationary Rossby waves. 4-body roster: terra (Held 2002 — Tibetan Plateau k=2 forcer at 300-500 mbar mid-troposphere; canonical NH winter pattern); mars (Hollingsworth 1997 — Tharsis Bulge ~10 km, ~10000 km wide; wavenumber-2 stationary mode survives to ~50 km altitude / mesopause; the headline planetary case in the catalog); venus (Lebonnois 2010 — super-rotation regime suppresses classic stationary-wave physics; LOW precision; observed=False); titan (Charnay & Lebonnois 2012 — analogous super-rotation; LOW precision). The terra + mars entries have observationally-confirmed standing waves; venus + titan are GCM-only because super-rotation breaks the Hoskins-Karoly classic regime. Two new bridge surfaces: get_orographic_forcing(body=None), list_orographic_forcings(). Two new CLI subcommands. 4-entry SOURCES; ratchet tests pin both directions. Pure-Python additive; no ABI bump (twelfth consecutive ship since v0.13.x). With v0.21.3 the trio of cross-channel coupling surfaces explicitly named in §17.4.2 is complete. New tests/test_orographic_forcing.py (24 tests). 1001 tests pass, 41 skipped.
v0.21.2 2026-05-07 Magnetic-multipole-derived dynamo-region constraints — second cross-channel coupling surface in the §17.4.2 v0.21.x sequence. For a body with a published spherical-harmonic magnetic-field expansion (v0.20.1), the Lowes-Mauersberger spectrum R(n) ∝ (R_dynamo/R_surface)^(2n+4) inverts directly for the dynamo radius. 5-body roster: terra (Lowes 1974 — canonical CMB at 3486 km / 0.547 R_E in molten Fe-Ni; matches seismology to <1%, the validation case); mercury (Christensen 2006 weak-field anomaly with stable-strat upper-core; depth 0.83 R_Me); jupiter (Connerney 2022 from JRM33 — 0.85 R_J in metallic H); saturn (Cao 2020 — 0.55 R_S in metallic H; the famous axisymmetry < 0.007° is itself a constraint via the Stevenson 1980 stable-strat-layer mechanism that filters non-axisymmetric modes); ganymede (Schubert 1996 — only intrinsic-moon dynamo in solar system; small Fe-FeS core at 0.27 R_G). Not a re-derivation — values shipped are the published inversions from cited papers. Two new bridge surfaces: get_dynamo_region(body=None), list_dynamo_regions(). Two new CLI subcommands. 5-entry SOURCES citation dict; ratchet tests pin both directions. Pure-Python additive; no ABI bump (eleventh consecutive ship since v0.13.x). New tests/test_dynamo_catalog.py (24 tests). 975 tests pass, 41 skipped.
v0.21.1 2026-05-07 Topography ↔ gravity admittance — first cross-channel coupling surface in the §17.4.2 v0.21.x sequence. For a body with both a published gravity multipole expansion (v0.20.0) and a topography model, the spectral admittance Z(n) at each spherical-harmonic degree constrains crustal density and thickness via isostatic compensation theory. 5-body roster: terra (Wieczorek 2007 ~50 mGal/km, ρ=2670, depth=35 km, Airy); luna (Wieczorek 2013 GRAIL+LOLA — the famous 2550 kg/m³ lunar crust + Z ~95 mGal/km); mars (Genova 2016 ~110 mGal/km, bimodal crust 30-70 km; Tharsis dominates n<10); mercury (James 2015 MESSENGER, ρ ~3200 kg/m³ consistent with high planetary density); venus (Anderson 2002 Magellan — highest Z ~200 mGal/km, weak Airy; lithospheric-flexure/mantle-plume support). Not a re-derivation — values shipped are the integrated Z summary published in the cited papers; per-degree Z(n) tables remain in the papers' supplementary materials. Two new bridge surfaces: get_topography_gravity_admittance(body=None), list_admittance_spectra(). Two new CLI subcommands: admittance, admittance-spectra. 5-entry SOURCES citation dict; ratchet tests pin both directions. Pure-Python additive; no ABI bump (tenth consecutive ship since v0.13.x). New tests/test_admittance_catalog.py (25 tests). 949 tests pass, 41 skipped.
v0.21.0 2026-05-07 Sol Spherical Harmonic Catalog — unification refactor across the v0.20.0 gravity sector (4π-normalised Stokes coefficients) and the v0.20.1 magnetic sector (Schmidt-quasi-normalised g_n^m / h_n^m). This is a unification refactor, NOT a new data store — the underlying records still live in geodetic_catalog_data and magnetic_multipole_catalog_data; v0.20.0/v0.20.1 surfaces continue to work unchanged. The "unification" is a NEW query surface that lets consumers ask "what spherical-harmonic representations does the catalog have for body X across all channels?" in one call. Each returned record carries an explicit normalisation_convention field ("4pi-Stokes" or "Schmidt-quasi-norm") so consumers know which conversion factors to apply when crossing channels. Roster reach: 56 gravity + 7 magnetic = 56 unified bodies; 7 both-channels intersection (terra/mercury/jupiter/saturn/uranus/neptune/ganymede). Two new query surfaces + one math helper: get_spherical_harmonics(body, channel="both") (single-body unified query); list_spherical_harmonic_models() (full enumeration + 76-entry merged citation dict spanning both sectors); convert_spherical_harmonic_normalisation(coefficient_value, n, m, from_convention, to_convention) (Winch et al. 2005 closed-form C̄_nm = g_n^m / sqrt((2 - δ_0m) * (2n + 1)); round-trip identity to float-machine precision). Three new CLI subcommands. Back-compat preserved — explicit regression tests pin v0.20.0/v0.20.1 surfaces continue to return their original shapes. Pure-Python additive; no ABI bump (ninth consecutive ship since v0.13.x). New tests/test_spherical_harmonic_catalog.py (30 tests). 922 tests pass, 41 skipped.
v0.20.2 2026-05-07 Sol Fluid Instrument — climatology + archive index + state-at-epoch query surface for the solar-system fluid envelope (atmospheres, oceans, cryospheres, exospheres). Promotes notebook §17.3 + §17.4.2 to a stable ship surface, mirroring the v0.19.0/v0.20.0/v0.20.1 patterns. Ships all three Option-D layers together per the §17.4.2 full-coverage commitment: Layer 1 — climatological summary (21 bodies: 17 atmospheric + 4 airless small bodies; per-body T_K, P_Pa, top-3 gas mole fractions, obliquity, eccentricity, Bond albedo). Layer 2 — archive-pointer index (10 entries: ERA5, MCD v6.1, MAVEN, VIRA + Akatsuki, Cassini, Juno, Voyager 2 Uranus/Neptune, New Horizons Pluto). Layer 3 — state-at-epoch coverage flags (21 entries; only terra ERA5 + mars MCD have True; all others fall back to climatology). Three new bridge surfaces: get_fluid_state(body=None, jd_tdb=None, lat=None, lon=None) (with coverage_status triage), list_fluid_archives(), fluid_architecture(target=None). Three new CLI subcommands: fluid-state, fluid-archives, fluid-architecture. No outbound network calls — package ships pointers + climatology fallback; consumers fetch actual reanalysis fields via CDS-API / MCD wrapper. HIGH/MEDIUM/LOW/NONE data-quality partition is the fluid-channel sibling of v0.20.0/v0.20.1 ({HIGH:13, MEDIUM:8, LOW:0, NONE:1}). Headline numerics: titan 94 K + 1.45 bar (denser than Earth's despite the cold!); triton 38 K + 1.4 Pa (one of coldest known surfaces); venus 737 K + 92 bar; uranus 97.77° obliquity. 24-entry SOURCES citation dict; ratchet tests pin both directions. Pure-Python additive; no ABI bump (eighth consecutive ship since v0.13.x). New tests/test_fluid_instrument.py (50 tests). 889 tests pass, 41 skipped.
v0.20.1 2026-05-07 Sol Magnetic Multipole Catalog — state-lookup query surface for the published-internal-field roster. Promotes notebook §17.2 + §17.4.2 to a stable ship surface, mirroring the v0.19.0 EM Instrument and v0.20.0 Sol Geodetic Catalog patterns. Not a BIP encoder — per §17.4.1 the rhythm-mismatch finding generalises across magnetic multipoles by epoch-static-ness: internal-field Schmidt coefficients are static at their epoch. 7-body main-field roster with full coverage commitment: terra (IGRF-13 deg 13), jupiter (JRM33 deg 18, Great Blue Spot resolved), saturn (Cao 2020 deg 14, axisymmetric tilt < 0.007°), mercury (Thébault 2018 deg 5, ~484 km offset dipole), uranus (AH5 deg 3, Voyager-only), neptune (O8 deg 3, Voyager-only), ganymede (Kivelson 2002 dipole-only — only intrinsic-moon-dipole). Plus 1 crustal field model (Earth EMM2017 deg 720, ~30 MB lazy-load) + 1 solar synoptic reference (Stanford HMI Carrington-cadence pointer). Five new bridge surfaces: get_magnetic_multipoles / evaluate_magnetic_field (closed-form Schmidt dipole synthesis) / get_solar_synoptic_state / list_magnetic_multipoles / magnetic_architecture. Five new CLI subcommands. HIGH/MEDIUM/LOW/NONE data-quality partition (current-best=HIGH; single-mission=MEDIUM; Voyager-only=LOW; synoptic-only=NONE). 9-entry SOURCES citation dict; ratchet tests pin every numeric value's source_key. Package metadata refresh: pyproject.toml description was advertising the obsolete v0.5-era 38-body roster and omitting all v0.16-v0.20.x catalog work — refreshed to list the 52-body roster + the three per-body catalogs + ITN-chain + body-architecture surfaces. Pure-Python additive; no ABI bump (seventh consecutive ship since v0.13.x). New tests/test_magnetic_multipole_catalog.py (59 tests). 834 tests pass, 41 skipped.
v0.20.0 2026-05-07 Sol Geodetic Catalog — state-lookup query surface for the solid-body geodetic stack (gravity multipoles + topography + interior structure). Promotes notebook §17.1 + §17.4.2 to a stable ship surface, mirroring the v0.19.0 Sol EM Instrument pattern. Not a BIP encoder running on geodetic rhythms — per §17.4.1 the rhythm-mismatch finding generalises across solid-body geodesy alongside magnetic multipoles and fluid-envelope channels: Stokes coefficients, DEM spectra, and layered density profiles are static parameters with no native rhythm, so the cyclic-group encoder discipline does not transplant. Three internal channels per body — gravity (full Stokes for terrestrial bodies + the Moon; zonal-only J_n for the gas + ice giants; point-mass GM for trojans + irregulars), topography (DEMs / SARTopo / polyhedral shape models), interior (radial density profiles + layered models + moment-of-inertia constraints). 56 gravity + 32 topography + 26 interior entries; 22 fully-characterised triple-channel bodies (terra / luna / mars / mercury / venus / io / europa / ganymede / callisto / mimas / enceladus / dione / rhea / iapetus / titan / triton / pluto / charon / ceres / vesta / bennu / ryugu) — full §17.4.2 coverage, no "minimum-viable" subset deferred. Three new bridge surfaces: get_geodetic_state(body=None) / list_geodetic_models() / geodetic_architecture(target=None). Three new CLI subcommands: geodetic-state / geodetic-models / geodetic-architecture. HIGH/MEDIUM/LOW/NONE data-quality partition (median per §17.1.6 ship-readiness convention) is a third orthogonal classification axis alongside v0.18.0's inner/outer Fiedler partition and v0.19.0's magnetised/induced/unmagnetised split. 67-entry SOURCES citation dict (DOIs / mission archives / journal refs); ratchet tests pin every numeric value's source_key. Forward sequence committed in §17.4.2: v0.20.1 MagneticMultipoleCatalog; v0.20.2 SolFluidInstrument; v0.21.0 SphericalHarmonicCatalog unification refactor; v0.21.1+ cross-channel coupling surfaces (one per minor version). Pure-Python additive; no ABI bump (sixth consecutive ship since v0.13.x with no ABI movement). New tests/test_geodetic_catalog.py (35 tests). 769 tests pass, 41 skipped.
v0.19.0 2026-05-06 Sol Electromagnetic Instrument — state-at-epoch query surface for the solar-system EM sector. Promotes notebook §16.9 to a stable ship surface. Not a BIP encoder — per §16.3 / §16.9.1, EM clocks (rotational, Carrington, solar cycle, plume duty cycle) don't form a low-order rational lattice with orbital periods, so the cyclic-group encoder discipline doesn't transplant. 16-body roster (1 star + 7 magnetised + 4 induced + 4 unmagnetised; strict subset of the v0.16.0 52-body celestial roster). 7 pairwise EM couplings (Jupiter-Io flux tube ~10¹² W headliner; Saturn-Enceladus, Saturn-Titan, Sun-Earth IMF, Jupiter-Europa, Jupiter-Ganymede, Sun-asteroid radiation pressure). Three new bridge surfaces: get_em_state(jd_tdb) / list_em_couplings() / em_architecture(target=None). Three new CLI subcommands. Notable data: Jupiter dipole 1.52×10²⁰ T·m³ (JRM33 Connerney 2022); IGRF-13 Earth dipole; Ganymede only-moon-with-intrinsic-dipole; Saturn rotation period uncertainty ±1 % flagged per §16.3 disclaimer. 19-entry SOURCES citation dict; ratchet tests pin every numeric value's source_key. User course-correction during §16 writing widened scope from "magnetic-only" → "electromagnetic" (Io flux tube is a current loop; solar wind is plasma-mediated; radiation pressure is photon momentum). Pure-Python additive; no ABI bump (fifth consecutive ship since v0.13.x with no ABI movement). New tests/test_em_instrument.py (46 tests). 730 tests pass, 41 skipped.
v0.18.2 2026-05-06 2-D (f₂, f₃) Fiedler-embedding upgrade for bridge.predict_itn_accessibility. Closes the §13.6 refinement #1 (two-eigenvector embedding) on top of the v0.18.1 hybrid weighting. Spearman ρ ~unchanged (1-D: +0.857 / 2-D: +0.849; rank ordering already strong) but R² lifts 0.51 → 0.64 and in-sample MAE drops 4.11 → 3.00 km/s (−27 %) + LOOCV MAE drops 4.24 → 3.12 km/s (−26 %) + new LOOCV median |err| = 2.20 km/s. Bridge response shape is purely additive: embedding_distance_2d + calibration.embedding_dim + calibration.lambda_3 + calibration.loocv_median_abs_error_kms are new; the v0.18.1 1-D fiedler_distance field is preserved for back-compat. Calibration constants change (intercept 8.68 → 4.90, slope 15.62 → 17.32); the v0.18.1 numbers are exposed under *_1D_HISTORICAL constants. New research/two_eigenvector_fiedler_embedding.py runs all three weightings × both embeddings for the comparison table. Notebook §13.10 documents the result. Pure-Python additive improvement; no ABI bump (fourth consecutive ship since v0.13.x with no ABI movement; ES_ABI_VERSION = 8 unchanged from v0.17.0/v0.18.0/v0.18.1). 685 tests pass, 41 skipped (was 681 + 41 in v0.18.1; +4 net new).
v0.18.1 2026-05-06 bridge.predict_itn_accessibility: closed-form spectral Δv estimate from the §13.9 hybrid Fiedler-distance regression. Promotes the v0.17.x research output (notebook §13.9.4) to a stable ship surface. The hybrid inv_dv × resonance gateway-graph Laplacian's Fiedler distance is calibrated by OLS regression against ground truth from a 50-yr find_itn_chains sweep at J2000: slope ≈ 15.62 km/s per Fiedler-unit, intercept ≈ 8.68 km/s, Spearman ρ = +0.857, in-sample R² ≈ 0.51, LOOCV MAE ≈ 4.24 km/s. Use case: fast first-pass triage (microseconds vs ~1.5 s for the full Dijkstra) — not trajectory design (MAE is ~4 km/s on a 2–28 km/s domain, useful for ranking pairs but too coarse for mission-budget purposes). New bridge.predict_itn_accessibility(departure, target) Python entry + new predict-itn-accessibility CLI subcommand. Calibration provenance returned in every response. New offline calibration script research/calibrate_predict_itn_accessibility.py. Notebook §14 added in this ship — re-reads §13.9 / v0.18.1 as the bulk-boundary correspondence's "real" empirical payload (the holographic-principle macro-scale framing). Pure-Python addition; no ABI bump (third consecutive ship since v0.13.x with no ABI movement; ES_ABI_VERSION = 8 unchanged from v0.17.0/v0.18.0). New tests/test_predict_itn_accessibility.py (22 tests). 681 tests pass, 41 skipped (was 658 + 41 in v0.18.0; +23 new).
v0.18.0 2026-05-06 Body Architecture: inner/outer system classification of heliocentric bodies via the resonance-weighted gateway-graph Laplacian Fiedler partition. First spectral-architecture surface in the bridge — the v0.17.x research output (notebook §13.8) promoted to a stable ship API. The cyclic-group encoder discovers the canonical asteroid-belt boundary without being told it exists: outer 5 (jupiter / saturn / uranus / neptune / pluto) all negative; inner 8 (mercury / venus / terra / mars / vesta / ceres / pallas / hygiea) all positive. Pluto and Neptune share the deepest negative Fiedler entry (≈ −0.585) via their 2:3 mean-motion lock. New bridge.body_architecture(target=None) Python entry + new body-architecture CLI subcommand. Fiedler-vector sign anchored to the shortest-period body (mercury) being positive — class labels reproducible across platforms regardless of LAPACK pivoting. Pure-Python addition; no ABI bump (second consecutive ship since v0.13.x with no ABI movement; ES_ABI_VERSION = 8 unchanged from v0.17.0). Notebook §13.9 also lands the hybrid inv_dv × resonance Laplacian research follow-up: Spearman ρ = +0.857 (clears the §13.7 0.85 ship bar), Matthews φ = +0.298 (below the 0.6 partition bar). Vindicates the multiplicative-hybrid hypothesis for a continuous Fiedler-distance Δv predictor; bridge.predict_itn_accessibility queued for v0.18.x or v0.19.0. New tests/test_body_architecture.py (34 tests). 658 tests pass, 41 skipped (was 622 + 41 in v0.17.0; +36 new).
v0.17.0 2026-05-06 Resonance-graph multi-leg find_itn_chains (advanced Lagrange-highway search). Generalises the v0.8.1 closed-form Hohmann-window enumeration (find_itn_pathways) to multi-leg pathways via Dijkstra-style graph search over the (body, epoch) state space. Each leg is a closed-form Hohmann window from find_itn_pathways; legs stitch end-to-end at intermediate bodies; cumulative Δv and time-of-flight are budget-bounded. Each leg carries a small-integer (p, q) gear-ratio "resonance signature" (period_dep / period_tgt reduced to lowest terms via _best_rational_approx) — the natural cross-pollination point between the closed-form transfer-window machinery and the BIP cyclic-group encoder. Canonical witnesses verified in tests: Earth/Mars 8:15 synodic-resonance anchor, Earth/Jupiter 1:12 Jupiter-orbit anchor, Jupiter/Saturn 2:5 great-inequality. Dijkstra invariant on cumulative Δv guarantees the first chain emitted is the optimal-Δv path; subsequent chains emitted in monotonically non-decreasing total-Δv order. New bridge.find_itn_chains Python entry + new find-chains CLI subcommand (intermediates / max-legs / Δv budget / TOF budget / threshold / max-chains flags). Pure-Python addition; no ABI bump — first ephemerides ship since v0.13.x to leave the C wire-format alone (every ship from v0.14.0 through v0.16.0 either added bodies or expanded BODIES, each of which moved the ABI). Sets up the v0.17.x research thesis (notebook §12.2 → task `#118`): Gateway-graph Laplacian + Fiedler-partition empirical-low-Δv-accessibility correspondence. New test_find_itn_chains.py (21 tests). 622 tests pass, 41 skipped (was 601 + 41 in v0.16.0; +21 new).
v0.16.0 2026-05-06 BODIES Tier-1 expansion (43 → 52): Lagrange trojans + retrograde irregulars + Neptune sub-graph completion. Themed per the post-v0.15.0 audit (notebook §11). Adds 9 new bodies + 9 forward + 9 inverse bridge wrappers + 9 CLI subcommands. First L4/L5 entries in BODIES: 4 Saturnian Lagrange trojans (Telesto + Calypso at Tethys L4/L5; Helene + Polydeuces at Dione L4/L5) — period IDENTICAL to host moon's, body-graph Laplacian acquires multiplicity-2 eigenvalue at host frequency. 3 Jovian irregulars (Himalia largest prograde; Pasiphae + Sinope retrograde — second retrograde marker beyond Triton; Pasiphae/Sinope near-resonant with period ratio ~1.02). Neptune sub-graph completion (Proteus second-largest at 1.122 d; Nereid most eccentric major-moon orbit at e=0.749, 360-d period). First invocation of v0.14.1-reserved suffix-disambiguation policy: Telesto's SSaTeT2 distinguishes from Tethys's SSaTeT. C-side wire-format change: ES_N_BODIES 43 → 52; ABI v7 → v8; native binary rebuilt + parity-smoke ratchet ratcheted. The Saturnian trojans are the spectral headliner — their period equals their host moon's, the natural intersection point with v0.16.x's resonance-graph multi-leg find_itn_chains. 601 tests pass, 41 skipped (was 514 + 41 in v0.15.0; +87 new — parametrize amplification across 4 trojans + 3 irregulars + 3 Neptunians).
v0.15.0 2026-05-06 Sol Moon Times: classical-roster completion (Pluto-Charon + remaining major Uranian moons) — BODIES roster expanded 38 → 43. Closes task `#86` for the IAU-major moon roster. Adds 5 new bodies (Miranda, Ariel, Umbriel, Oberon, Charon) + 5 forward + 5 inverse bridge wrappers + 5 CLI subcommands. Charon is the binary-planet case: mutually tidally locked with Pluto (only such 1:1:1 spin-orbit lock in the solar system), Charon:Pluto mass ratio ≈ 0.12 puts the system barycentre outside Pluto. SUrMiT vs SSaMiT is the v0.15.0 second-instance disambiguation case — same shared-moon-prefix pattern as the v0.14.2 SUrTiT/SSaTiT pair. C-side wire-format change: ES_N_BODIES 38 → 43; ABI v6 → v7; native binary rebuilt + parity-smoke ratchet ratcheted. 512 tests pass, 41 skipped (was 497 + 4 in v0.14.2; +56 new). With v0.15.0 every classical IAU-named moon in the BODIES roster has a Sol Time wrapper.
v0.14.2 2026-05-06 Sol Moon Times: remaining 8 moons across 4 parent families (Mars, Jovian inner regulars, Uranus, Neptune). Closes task `#86` for the current 38-body roster. Adds 8 Sol Moon Times — Phobos SMaPhT + Deimos SMaDeT (Mars: both likely captured asteroids, Phobos's 0.319 d sidereal period is shorter than Mars's solar day so Phobos rises in the west); Metis SJuMeT + Adrastea SJuAdT + Amalthea SJuAmT + Thebe SJuThT (Jupiter inner regulars: Metis + Adrastea are ring-shepherds, Amalthea was the last solar-system moon discovered by direct visual observation in 1892); Titania SUrTiT (Uranus's largest moon, only Uranian moon currently in BODIES — Oberon, Umbriel, Ariel, Miranda queued for a future ship); Triton SNeTrT (Neptune's largest moon, captured Kuiper Belt object, only large retrograde moon in the solar system). All 8 follow the v0.14.1 6-letter S<Planet2><Moon2>T convention; SUrTiT vs SSaTiT is exactly the disambiguation the policy was designed to provide. Encoder convention documented for Triton: period_days is positive (we encode omega = +2π/P for ALL bodies regardless of prograde/retrograde direction; retrograde-ness is metadata, not a sign flip — same convention as v0.5.4 Sol Uranian Time). Generic _add_moon_subparser CLI helper supersedes the v0.14.0/v0.14.1 family-specific helpers. Built via 4 parallel subagent worktrees (one per family) integrated by the parent agent into a single bridge.py / cli.py / parity-smoke ship — first multi-agent ship in this repo. Pure-additive; no API / encoder / ABI / encoder-test changes. 497 tests pass, 4 skipped (was 399 + 4; +98 new).
v0.14.1 2026-05-06 Sol Moon Times: Saturnians (11 moons) + abbreviation policy switch (4-letter → 6-letter). Second slice of `#86`. The contingency from v0.14.0's ROADMAP fired exactly as predicted: Saturnians introduced two collisions under the v0.14.0 4-letter S<Planet><Moon>T pattern (Tethys + Titan both 'T' → both SSTT; Enceladus + Epimetheus both 'E' → both SSET). Per the policy, the switch applies uniformly across all Sol Moon Times — Galileans retroactively renamed (SJIT → SJuIoT, SJET → SJuEuT, SJGT → SJuGaT, SJCT → SJuCaT); Saturnians ship with 6-letter abbreviations (Mimas SSaMiT, Enceladus SSaEnT, Tethys SSaTeT, Dione SSaDiT, Rhea SSaRhT, Titan SSaTiT, Hyperion SSaHyT, Iapetus SSaIaT, Phoebe SSaPhT, Janus SSaJaT, Epimetheus SSaEpT). Python function names + CLI subcommand names + return-shape unchanged; only the epoch.abbreviation string changes (callers parsing the field for display need to update). Resonance witnesses verified in tests (Mimas-Tethys 4:2 = Cassini Division; Enceladus-Dione 2:1 = tidal heating; Titan-Hyperion 4:3 = chaotic rotation; Janus-Epimetheus co-orbital). Hyperion's chaotic rotation noted in the bridge docstring + test module — sidereal_period_days references orbital period; rotation phase decoupled. 399 tests pass, 4 skipped (was 294 + 4; +105 new).
v0.14.0 2026-05-05 Sol Moon Times: Galileans (Io / Europa / Ganymede / Callisto). First slice of task `#86`. New generic MoonTime primitive in _research/time_scales.py + four per-Galilean bridge wrappers + four CLI subcommands (time-jupiter-{io,europa,ganymede,callisto}) with abbreviations SJIT / SJET / SJGT / SJCT. Default epoch is J2000.0 (STLT's Greek-historical anchors don't generalise to non-Luna moons). Galilean Laplace-resonance witness verified in tests (canonical n_Io − 3·n_Europa + 2·n_Ganymede ≈ 0; Callisto correctly outside the resonance). New ## Naming convention contingencies section in ROADMAP documents the fallback policy if moon-letter collisions arise (uniform switch to 6-letter S<Planet2><Moon2>T). Pure-additive; no API/encoder/ABI changes. 294 tests pass, 4 skipped (was 251 + 4; +43 new).
v0.13.10 2026-05-05 Drop edited from docs-check workflow trigger types — fixes post-merge double-fire. User-flagged on PR `#214` (v0.13.9 ship): docs-check was deterministically double-firing at every merge. Root cause: GitHub web UI's "Squash and merge" fires pull_request: edited (merge-commit dialog) near-simultaneously with pull_request: synchronize (refs/pull/N/merge recomputed). Fix: drop edited from trigger types; now [opened, synchronize, reopened, labeled], matching ephemerides-spectral-ci.yml's narrower list. Trade-off: [skip-docs-check] opt-out can no longer be added retroactively; must be set up-front. CI-only change; no code / API / encoder / ABI / test changes. 251 tests pass, 4 skipped.
v0.13.9 2026-05-05 JPL Power-of-Ten Rules 6 + 7 manual audits — closes the v0.13.4-v0.13.9 rule-fix sequence; ALL TEN RULES NOW SATISFIED. Audit-only release; no code changes; 0 violations found for both Rule 6 (smallest possible scope) and Rule 7 (check return values + validate parameters). The v0.11.2 spot-check estimates of "5-10 + 5-15" violations didn't survive the incremental tightening in v0.13.4-v0.13.6 (long-function splits, assertion-density work, cleanup-on-error refactor all happened to also tighten scope and unify the rc-check pattern). Audit walked every variable declaration and every es_status_t assignment site by hand. All ten JPL Power-of-Ten rules satisfied: Rules 1+3 (v0.13.4), Rule 4 (v0.13.5), Rule 5 (v0.13.6), Rule 10 (v0.13.7), Rules 6+7 (v0.13.9); Rules 2, 8, 9 already-passing at v0.11.2. 251 tests pass, 4 skipped.
v0.13.8 2026-05-05 README accuracy patch — two-stage architecture clarification. User-flagged misunderstanding about "pure ALU": the previous README listed three backends (bip / c / complex128) as parallel alternatives, with complex128 annotated as "Used for the algebraic identities (Syzygy operator, observer binding) and as a regression baseline" — but since v0.7.0 (Tier 2b) the production HD path is C-side complex64; complex128 is the regression baseline only (backend="fpu-ref"). README now splits into two-stage architecture: (1) phase-residue stage with three integer-ALU encoders (bip / c / complex128 reference) producing uint32[38] residues, and (2) HD-pipeline stage (FPU complex64 production / complex128 regression) for syzygy / observer-bind / eclipse-probability. Adds a "TL;DR on pure ALU" callout: phase residues are integer ALU end-to-end; HD operations can't be (channel bases are unit-magnitude complex). Roadmap renumber: Rules 6+7 manual audits move v0.13.8 → v0.13.9 (last item in the JPL rule-fix sequence). Docs-only; no API / encoder / ABI / test changes. 251 tests pass, 4 skipped.
v0.13.7 2026-05-05 JPL Power-of-Ten Rule 10 fixes — cross-platform pedantic-build CI matrix. Fourth code-quality patch in the v0.13.4-v0.13.8 rule-fix sequence. New ES_PEDANTIC=ON CMake option elevates -Wall -Wextra -Wpedantic (gcc/clang) and /W4 (MSVC) warnings to errors via -Werror//WX. New pedantic-build CI job runs a 3-cell matrix (Linux gcc, macOS clang, Windows MSVC); always-on (not gated by wheel-check) — Rule 10 is a permanent invariant. Local MSVC /W4 /WX build verified clean. All five mechanically-enforceable JPL rules now satisfied (Rules 1, 3, 4, 5, 10). Remaining: Rules 6+7 manual audits (v0.13.8). CI-only addition; no public API/ABI/encoder change. 251 tests pass, 4 skipped.
v0.13.6 2026-05-05 JPL Power-of-Ten Rule 5 fixes — assertion density at 2/function average. Third code-quality patch in the v0.13.4-v0.13.8 rule-fix sequence. 88 assertions added across 42 functions = 2.10/function (target ≥2.0). All gated behind standard <assert.h> NDEBUG semantics — production builds (-DNDEBUG) strip them entirely; zero runtime cost. Coverage: pre-conditions (post-validation assert(ptr != NULL), assert(idx < N_BODIES), assert(isfinite(input))); post-conditions (assert(magnitude >= 0), assert(phase < 2π)); invariants (assert(D > 0), assert(n_patches <= ES_MAX_PATCHES)). The test_rule_5_density_meets_2_per_function ratchet test flips from SKIP to PASS. PIN_RULE_5_ASSERTIONS ratcheted UP 0 → 88. Total mechanically-detectable violations: 102 → 0 — every Rule 1-5 violation in the v0.11.2 audit baseline now cleared. Remaining: Rule 10 (v0.13.7), Rules 6+7 (v0.13.8). Pure additive instrumentation; no public API/ABI change. 250 tests pass, 4 skipped (was 5; Rule 5 density skip is gone).
v0.13.5 2026-05-05 JPL Power-of-Ten Rule 4 fixes — long-function splits. Second code-quality patch in the v0.13.4-v0.13.8 rule-fix sequence. Pure refactor: no public API / ABI / test-surface change. The 4 audit-baseline offenders (es_encode_state 109, es_find_syzygies 99, es_bind_observer 78, es_get_eclipse_probability 65) split into JPL-compliant ≤60-line drivers via 10 new private static helpers along natural algorithm seams: apply_one_chunk + apply_subchunk_remainder (encoder); select_syzygy_targets + score_syzygy_event + validate_syzygy_args + emit_syzygy_event (parity); observer_coord_shift + apply_observer_bind + build_syzygy_operator + complex64_vdot_magnitude (HD pipeline). PIN_RULE_4_LONG_FUNCTIONS 4 → 0; PIN_RULE_5_TOTAL_FUNCS ratcheted 32 → 42 (Rule 5 work in v0.13.6 needs the larger inventory). Encoder math byte-identical — parity smoke green. Total mechanically-detectable violations: 102 → 64 (37% of audit baseline cleared across v0.13.4 + v0.13.5). 250 tests pass, 5 skipped.
v0.13.4 2026-05-05 JPL Power-of-Ten Rule 1 + Rule 3 fixes (combined refactor in es_hd_state.c). First code-quality patch in the v0.13.4-v0.13.8 rule-fix sequence. Caller-supplied-scratch refactor: HD-pipeline entries (es_encode_state_hd, es_bind_observer, es_get_eclipse_probability) take scratch buffers as additional pointer parameters; the Python ctypes shim allocates them alongside the existing out_state. goto count 5 → 0 (Rule 1); malloc/free count 29 → 0 (Rule 3); <stdlib.h> no longer included. ABI v5 → v6 — mechanical wire-format change; encoder math byte-identical (parity smoke pins both backends to within float-ULP). Total mechanically-detectable violations: 102 → 68 (33% of audit baseline cleared). Remaining: Rule 4 (v0.13.5), Rule 5 (v0.13.6), Rule 10 (v0.13.7), Rules 6+7 (v0.13.8). User-facing Python bridge surface unchanged. 250 tests pass, 5 skipped.
v0.13.3 2026-05-05 Pre-merge docs+parity hygiene check (soft-warning workflow). Closes `#98` (consolidated; absorbs `#87` + `#88`). New .github/workflows/ephemerides-spectral-docs-check.yml cross-checks code-side touches (version bumps; bridge.py; cli.py; _research/*.py; c/src/*.c / c/include/*.h) against the five PyPI-facing docs files (python/README.md, python/CHANGELOG.md, CHANGELOG.md, ROADMAP.md, ephemerides_spectral_research_notebook.md). Posts (or updates in place) one PR comment summarising drift; never fails the build. The pytest freshness ratchet (test_native_version_string_matches, test_parity_smoke::PARITY_TARGETS, test_readme_freshness, test_jpl_audit) still hard-fails on the highest-value drift modes; this surfaces the next tier — prose-and-narrative drift a regex can't authoritatively adjudicate. Opt-out: [skip-docs-check] in PR body. Comment idempotence via peter-evans/find-comment + peter-evans/create-or-update-comment. Concurrency cancel-in-progress: true keyed by workflow + ref absorbs the opened+labeled double-fire pattern. 250 tests pass, 5 skipped.
v0.13.2 2026-05-05 Quick-win housekeeping: gitignore _native/; renumber JPL rule-fix roadmap. Patch-level repo-config + docs only; no API / encoder / ABI / test changes. Adds python/ephemerides_spectral/_native/ to the top-level .gitignore (`#85`); _native/ holds compiled DLL/SO files that rebuild on every cmake --build and shouldn't be source-controlled. Patches c/JPL_AUDIT.md's roadmap section: original v0.11.3-v0.11.7 numbering is obsolete; rule-fix patches renumbered to v0.13.4-v0.13.8 (Rule 1+3 / Rule 4 / Rule 5 / Rule 10 / Rules 6+7). v0.13.3 reserved for `#98` (consolidated docs+parity hygiene check; absorbs `#87` + `#88`). 248 tests pass, 5 skipped.
v0.13.1 2026-05-05 SPICE feature-gap audit + STLT-naming hygiene. Docs-only; no API / encoder / ABI changes. New figures/spice_feature_audit.md answers "what does SPICE do that we don't, and is a compat bridge worth shipping?" — three-column comparison; recommendation: skip the compat-bridge. Spawns a v0.14.x backlog (light-time + stellar-aberration; frame transforms; full Kepler elements; per-body pole orientation). STLT naming hygiene: the README abbreviation table promotes Luna's primary Sol Time from SLT to STLT per the moons-stuck-to-parent Sol <Parent>-<Body> Time convention; SLT preserved as secondary alternative for the surface-clock case. Drops "system clock for the Terra-Luna pair" framing from active code (CHANGELOG history entries preserved as artefacts). User-flagged framing fix. Tests unchanged at 248 + 5 skipped.
v0.13.0 2026-05-05 Sol Dynamics — completes the Kinematics + Dynamics split. Counterpart to v0.12.0's Sol Kinematics; mirrors chess-spectral's qm_*_dynamics.py dynamics layer (Hamiltonian + force / energy queries). New bridge.get_dynamics() (system aggregate), bridge.get_force_between(a, b) (Newtonian pair force, validated against the textbook 3.54×10²² N Earth-Sun figure to 0.01 %), bridge.get_body_energies(body) (per-body KE + PE + total). New standalone dynamics CLI subcommand with three modes: system aggregate (default), per-body (--body X), pair-force (--body X --from Y). New --dynamics flag uniform across every time-* subcommand. Total system energy −1.98×10³⁵ J (bound; virial theorem holds to 0.5 %). All three augmenting flags --proper + --state + --dynamics compose without conflict. Phase A audit (committed during v0.12.0 ship) covers both halves; v0.13.0 ships the second canonical primitive without needing new Phase A research. New _research/dynamics.py codegened alongside kinematics.py. 248 tests pass.
v0.12.0 2026-05-05 Sol Kinematics — per-body orbital state, augmented onto every time-* subcommand via --state. First half of the Kinematics + Dynamics split modelled on chess-spectral's qm_*.py + qm_*_dynamics.py pattern. New bridge.get_kinematic_state(body, ...) + bridge.get_full_system_state(...) + bridge.apply_state_correction(...) primitives + standalone kinematics --body X / kinematics --all CLI subcommand. Validated against NASA fact-sheet orbital velocities for Mercury / Terra / Mars / Jupiter / Pluto to within 0.02-1.1 %. Jupiter holds 61.5 % of total system angular momentum (matches the published ~61 % figure); outer planets hold 99.84 % of planet total L (matches ~99 %). User pointed at the chess-spectral pattern: "we can check our chess spectral where we have done this." Translation 1:1; same Phase A independent script + Phase B canonical primitive discipline as STLT and SPrT. New _research/kinematics.py codegened alongside proper_time.py. v0.13.0 Sol Dynamics ships the time-evolution + forces + energies counterpart. 212 tests pass.
v0.11.2 2026-05-05 JPL Power-of-Ten audit baseline for the C library. Audit-only release; no API / encoder / ABI changes. Documents 102 mechanically-detectable violations rule-by-rule in c/JPL_AUDIT.md: 5 goto (Rule 1, all in es_hd_state.c cleanup pattern), 29 malloc/free (Rule 3, all in HD pipeline), 4 functions over 60 lines (Rule 4: es_encode_state 109, es_find_syzygies 99, es_bind_observer 86, es_get_eclipse_probability 71), 64-assertion shortfall (Rule 5, 0/32 functions). Rules 2 (fixed loop bounds), 8 (limited preprocessor), 9 (no function pointers) already pass clean. Pins counts in tests/test_jpl_audit.py as a one-way ratchet — counts can only go DOWN; new violations fail loudly. Same modular discipline as test_native_version_string_matches_package_version and test_readme_freshness.py. Reference: Holzmann 2006, IEEE Computer. Rule-by-rule fixes staged as v0.11.3 (Rule 1+3 combined), v0.11.4 (Rule 4), v0.11.5 (Rule 5), v0.11.6 (Rule 10), v0.11.7 (Rules 6+7). 182 tests pass.
v0.11.1 2026-05-05 Research notebook hygiene — backfill §7.4 (STLT) and §7.5 (SPrT) sections + refresh Status banner. Documentation-only release. v0.10.0 (STLT) and v0.11.0 (SPrT) shipped with full bridge / CLI / test surfaces but neither updated the research notebook; the freshness invariants from v0.9.3 cover the PyPI README but don't audit the notebook. Triggered by the user noticing the gap during the v0.11.0 close. Adds 1,500+ lines of notebook prose covering STLT's Meton-anchor rationale + the Hipparchus-Babylonian-midpoint convergence story, and SPrT's diagonal-fiber framing + the validation table. Refreshes the Status banner (was stale at v0.7.0). Backfills §4 Release History through v0.11.1 (was ending at v0.9.1). Task #98 captured: soft-warning "docs probably need updating" check on PRs that touch code without touching docs — would have caught these gaps automatically. No API / encoder / ABI changes; 171 tests pass identical to v0.11.0.
v0.11.0 2026-05-05 Sol Proper Time (SPrT) — gravitational + orbital-kinematic time dilation, applied transparently via --proper on every time-* subcommand. New bridge.get_proper_time_rate(body, ...) + bridge.compare_proper_times(a, b, ...) primitives + standalone time-proper CLI subcommand. Same physics as Mercury's existing 43″/century PN diagonal correction, applied per-body to all 38 bodies. The user's framing: "gravitational time dilation fiber so users don't even need to know anything extra had to happen in the back end." Six published values (Earth GR, Sun GR, Mars GR, Pluto GR, Earth orbital kinematic, Mars-vs-Earth GR difference) reproduced to within 0.30 %. The 0.0175 s/Earth-year Curiosity-rover figure verified inline; combined-effect (GR + kinematic) Mars-Terra clock-rate difference is 0.0710 s/yr. New surface_radius_km per body in bodies.py. Phase A research script + markdown report committed first; Phase B canonical primitive ships with two independent implementations agreeing on the same six numbers (so either drifting catches the other). 169 tests pass.
v0.10.0 2026-05-05 Sol Terra-Luna Time (STLT) — system clock for the Terra-Luna pair, Meton's 432 BCE summer solstice as the default epoch. First Sol Time member with a non-J2000 default anchor. New bridge.jd_to_sol_terra_luna_time(jd_tdb, *, epoch="meton") + inverse; new CLI time-terra-luna with --epoch {meton, antikythera, hipparchus, mardokempad, j2000}. The "combo" candidate test from research/lunar_epoch_candidates.py independently confirms the choice: the Hipparchus-Babylonian eclipse-archive midpoint (Mardokempad 721 BCE + Hipparchus 141 BCE) lands within +240 days of Meton's solstice — same year. Greek mathematical astronomy's eclipse archive is centred on Meton's lifetime. Synodic month is the natural unit; Saros (18.03 yr) and Metonic (19.00 yr) cycle counts come along for free. Phase A research script + markdown report at figures/lunar_epoch_candidates.md. Latent bug fixed in passing: find_syzygies(backend="auto") was rejected by _validate_backend (same class as v0.9.2's get_breathing_modulation fix). House-epoch design choice; not a claim to be NASA's eventual LCT. 127 tests pass, 4 skipped.
v0.9.3 2026-05-05 PyPI-facing README staleness sweep + CI freshness check (docs-only). Status section refreshed (8 versions of accumulated drift — block ended at v0.6.1, now runs through v0.9.3). Roadmap section pruned of items that have shipped (Tier 2b, Sol Venusian/Mercurian Time, ITN pathway / find-tubes); reorganised to lead with genuinely-still-ahead work (first-principles per-resonance α, Hyperion follow-up, remaining 4 broken moons, Sol Moon Times, DE441 vs DE442 experiment, heteroclinic-tube extension to find-tubes, LTC, Phase 10 resonance coverage). Leftover earth-body CLI examples corrected to terra; "Phase 9 'Breathing' Couplings" heading inverted to "Phase 9 Adaptive Couplings (a.k.a. 'breathing')". Drift-prevention: new tests/test_readme_freshness.py enforces three invariants — every CHANGELOG version must appear in the README Status section; the Status: vX.Y.Z banner under the H1 must equal __version__; every CLI body-name flag in an example must reference a name in SUPPORTED_BODIES. Same modular discipline as test_native_version_string_matches_package_version and test_parity_smoke.py::PARITY_TARGETS — enumerate the truth, fail on drift. Docs-only release; no API or encoder changes; no ABI bump.
v0.9.2 2026-05-05 CLI: adaptive is the primary subcommand for state-dependent coupling modulation; breathing is preserved as a hidden synonym (help=argparse.SUPPRESS). No bridge-API changes, no encoder hot-path changes — purely a CLI surface adjustment plus help-text cleanup. The framing: what we call "breathing couplings" in the visual / informal register is, in mainstream network-science vocabulary, an adaptive coupling — a state-dependent (non-autonomous) graph Laplacian whose edge weights co-evolve with the system's own resonant phases (Gross & Blasius 2008, "Adaptive coevolutionary networks"; the adaptive Kuramoto family). Both names work; new users discover adaptive via --help, visual-metaphor users keep typing breathing. Latent bug fixed in passing: bridge.get_breathing_modulation(backend="auto") was rejected by _validate_backend (the sentinel isn't in SUPPORTED_BACKENDS); resolved before validation now, matching the docstring contract. Help-text cleanup: leftover --body earth / --departure earth examples corrected to terra after v0.9.0/v0.9.1. 118 tests pass, 7 new (tests/test_cli_adaptive_alias.py).
v0.9.1 2026-05-05 Sol Time naming convention overhaul + Sol Terra Time + Sol Luna Time. Direct Latin proper noun (Mercury, Venus, Pluto, Terra, Luna, Sol) for rocky bodies + Sun + Luna; established adjective form (Jovian, Saturnian, Uranian, Neptunian) for gas/ice giants. Renames (BREAKING): jd_to_sol_mercurian_timejd_to_sol_mercury_time; same for venusian → venus, plutonian → pluto; same for the dataclasses. New (additive): Sol Terra Time (STT, Terra's surface clock; sidereal 23h 56m 4s, solar 24h) and Sol Luna Time (SLT, Luna's tidally-locked surface clock; sidereal=orbital=27.32 d, solar=synodic=29.53 d). SLT is distinct from Sol Lunar Time (get_lunar_phase), which gives Luna's phase as observed from Terra — same body, different observer frame. Each bridge return's epoch: block carries an abbreviation field per the user's indexing table. The naming framing: "Returning to the giants whose shoulders we stand on. We've always had a lunar orbit and a lunar eclipse. We've all had terrain and terrestrial animals. We're just putting the books back in their dewey decimal spot." 111 active tests pass.
v0.9.0 2026-05-05 Body identity rename: moonluna, earthterra. BREAKING CHANGE. Latin proper nouns for the body identity strings; the generic English words (moon = category for any natural satellite, earth = soil/ground) are no longer privileged as proper-noun strings. BODIES["luna"] / BODIES["terra"] replace the old keys. _data/initial_phases.json re-keyed (encoded phase residues unchanged at any JD). C-side es_bodies table re-emitted via codegen. JPL/skyfield kernel boundary: EphemerisBundle.lookup() translates internal terra/luna → JPL EARTH/MOON via a small alias map. Category strings, adjective forms, and external JPL identifiers are unchanged. Encoder hot path byte-identical to v0.8.1. Migration: any code with body="earth" / body="moon" updates to body="terra" / body="luna". v0.9.1 ships the matching Sol Time naming-convention overhaul (Sol Mercurian → Sol Mercury, etc.; new Sol Terra Time + Sol Luna Time).
v0.8.1 2026-05-05 ITN pathway / Lagrange-tube query — find-tubes first cut. "Surfing the perturbations": closed-form Hohmann transfer-window enumeration mirroring v0.3.1's find-syzygies discipline. New bridge.find_itn_pathways(jd_lo, jd_hi, departure, target, ...) + CLI find-tubes. Pure-Python; C twin queued (parity smoke marks find_itn_pathways as tier1_skip). Earth → Mars sanity: 23 windows over J2000 + 50 yr at threshold 0.02; 258.87-d transfer time and 5.594 km/s Δv match textbook Hohmann to 0.01% / 0.1%. The gateway_lp field is a placeholder for future CR3BP L1/L2 gateway designation. References: Koon/Lo/Marsden/Ross 2011; Lo's Genesis trajectory work; Conley 1968.
v0.8.0 2026-05-05 Sol Symphony Times: 7 new planetary/stellar time systems. Venus, Mercury, Pluto, Sol (the Sun!), Jupiter, Saturn, Neptune join Mars / Lunar / Uranian as Sol Time members. Each ships with sidereal + (where applicable) solar day phase + orbital phase + epoch metadata. Special quirks honored: Mercury 3:2 spin-orbit resonance (solar day = 2 Mercury-years exactly); Venus retrograde with sidereal day longer than year (243 vs 224.7 d); Sol differential rotation (Carrington Rotation Number; 25.38 d at ~16° latitude); Saturn Cassini-revised rotation (Mankovich 2019, supersedes Voyager). 12 new bridge methods, 6 new CLI subcommands, naming hierarchy convention for future moon ports (Sol <Parent>-<Body> Time). ABI unchanged — pure-Python time-scale formulas. 102 active tests pass. Subagent confirmed gas giant rotation periods (Jupiter System III magnetic-field; Saturn Cassini ring-seismology) are derived independently of moon orbital data, so Sol Jovian and Sol Saturnian Time ship without needing the gas-giant moons.
v0.7.0 2026-05-05 C/Python parity Tier 2b — full HD pipeline in C (ABI v5). Three new C entry points: es_encode_state_hd (BIP-encode then lift to D-dim hypervector via channel bases), es_bind_observer (topocentric HDC algebra; no SPICE), es_get_eclipse_probability (syzygy projection). Bridge dispatches get_local_view and get_eclipse_probability on backend={"auto","bip","c","fpu-ref"}. The parity smoke test's two tier2_skip entries flip to parity — every encoder-touching bridge method now has a paired C path; the v0.6.0 discipline ("if we always smoke all python things, we know to always smoke the same C things") is fully realised. New _research/bip_hd_lift.py Python helpers + tests/test_hd_parity.py byte-parity tests. Behaviour change: default get_local_view / get_eclipse_probability output switches from FPU matrix-expm to BIP-and-lift; pass backend="fpu-ref" to opt back into pre-v0.7.0 behaviour. 84 active tests pass; 4 skipped (cibuildwheel-only).
v0.6.1 2026-05-05 C/Python parity Tier 2a foundation (ABI v4). Channel-basis emission in C with byte-identical agreement to the Python side. New portable splitmix64 PRNG (replaces numpy's PCG64-seeded basis init for reproducibility); new es_channel_basis(seed, out, D) entry point + es_complex64_t typedef. The _research/portable_prng.py module mirrors the C-side splitmix64 byte-for-byte. New tests/test_channel_basis_parity.py pins byte-identical complex64[D] output between Py + C across all 38 body seeds and D ∈ {1024, 65536}. No bridge surface change; no encoder behaviour change. Foundation for v0.7.0's HD encode + observer-bind + eclipse projection. See TIER2_DESIGN.md for the three-phase plan.
v0.6.0 2026-05-05 C/Python parity Tier 1 + always-on parity smoke test (ABI v3). Two encoder-touching bridge methods that were previously Python-only now have C twins: get_breathing_modulation (resonant-pair phase + integer-LUT modulation factor at one JD) and find_syzygies (synodic + draconic month enumeration). New bridge.<method>(backend={"auto","bip","c"}) dispatch on both. Encoder hot path unchanged — net-new ABI v3 entry points only (es_breathing_modulation, es_find_syzygies with es_syzygy_t struct, three new es_status_t codes). The durable parity discipline: new tests/test_parity_smoke.py enumerates every public bridge.* function in a PARITY_TARGETS table classified as parity / python_only / tier1_skip / tier2_skip. Two drift-detection sub-tests force the table to stay current: adding a new bridge method without a parity classification fails CI; deleting a function without removing its entry fails CI. Tier 2 still pending (get_local_view, get_eclipse_probability need hyperdimensional state in C — v0.7.0). 64 active tests pass; 6 skipped (4 cibuildwheel-only + 2 Tier 2 stubs).
v0.5.5 2026-05-05 Moon catalog patches — Phase C of the v0.5.x moon programme. Five LS-fit-vindicated moon patches join CATALOG_V2: dione-1.06yr-diagonal-v2 (98.2%), tethys-0.38yr-diagonal-v2 (93.8%), enceladus-0.39yr-diagonal-v2 (98.9%), titan-0.69yr-diagonal-v2 (95.5%), iapetus-0.22yr-diagonal-v2 (98.6%) — measured shrinkage% pinned per entry. The v0.5.2 LS-fit methodology is now vindicated twice on independent body sets: planets at 96-99%, moons at 93-99%. Same bin-leakage signature both times (LS-fit amps 2-3× the FFT-bin baselines), both for bodies orbiting the Sun and bodies orbiting Saturn. Hyperion's 0.20yr-diagonal patch lands at 75.2% (single sinusoid vs Hyperion's chaotic-rotator multi-peak quasiperiodic spectrum) — queued as a multi-component or coupled Titan-Hyperion 4:3 follow-up. New scripts: author_moon_patches.py + verify_moon_patches.py; de441_moon_spectrum.gather_moon_residuals factored out for reuse.
v0.5.4 2026-05-05 Sol Uranian Time (SUT) — third planetary time system alongside Mars Sol Date / Mars Coordinated Time and lunar synodic + sidereal phase. New bridge.jd_to_sol_uranian_time(jd_tdb) returns USD (Uranian Sol Date, sidereal-day count since the 2007 northern equinox), SUT (time-of-day in Uranian hours), orbital phase + season (4 ~21-yr seasons partitioning Uranus's 84.02-yr orbit). Carries retrograde=True because Uranus rotates backwards relative to its orbital motion (the encoder doesn't yet sign-aware omega; surfacing the flag makes the asymmetry visible). New CLI time-uranus --jd ... (or --usd ... to invert). Plus a CLI --help audit across all subcommands — every command now has concrete --help examples; the v0.4.0 patches group's stale "C backend doesn't yet implement" notice corrected to reflect v0.4.1 + v0.5.2 reality.
v0.5.3 2026-05-05 Moon residuals: 13 of 17 fixed via high-precision sidereal periods. v0.5.2 sweep flagged ~100° RMS residuals on most moons; root cause turned out to be period-truncation in the BODIES table (10⁻⁴-relative omega error accumulating over 41,000+ orbits across the 200-yr sweep). The hypothesised ecliptic-projection frame mismatch was ruled out by per-orbital-period diagnostic (within one orbit the broken moons show <1° RMS). Fix: full-precision (9+ decimals) sidereal periods from JPL HORIZONS / NASA fact sheets. Result: io 106°→0.34°, europa 116°→0.76°, ganymede 117°→0.14°, adrastea 104°→0.07°, amalthea 102°→0.27°, enceladus 103°→2.57°, tethys 101°→2.94°, dione 117°→2.54° — 30-1450× improvements. 13 of 17 moons now clean (was 4). Four still broken (metis, thebe, rhea, phoebe) — physics-specific investigation queued (Phoebe is retrograde and needs a sign-aware encoder; metis needs an authoritative period; thebe + rhea likely perturbation-driven).
v0.5.2 2026-05-05 Patch-shrinks-residual benchmark FULLY VINDICATED on planets. Least-squares fitting at the exact target period (replaces FFT-bin extraction); bypasses bin leakage entirely. New CATALOG_V2 ships 3 patches with measured shrinkage pinned in each entry's notes: Mars 99.2% / Mercury 99.9% / Jupiter 97.6% / Saturn 96.0%. Empirical findings: J–S correlation = +1 (in-phase, not anti-correlated as v0.4.0 assumed); LS-fit periods drift ~0.16% from bin-rounded; LS-fit amplitudes 25–55% larger than FFT-bin extraction (the leaked energy v0.5.1 couldn't see). Moon-kernel infrastructure ships alongside (mar099s + jup365 + sat441 via auxiliary_kernels parameter; new bundle.lookup(target_key) searches main + aux in order; new de441_moon_spectrum.py runs a moon-friendly sweep). Moon residual finding: 4 of 17 moons (Callisto / Titan / Iapetus / Hyperion) work cleanly; the rest show ~100° RMS dominated by near-DC content — root cause queued for v0.5.x.
v0.5.1 2026-05-05 Patch-shrinks-residual benchmark — earn the right to predict missing data. Verdict: PARTIAL vindication. The v0.4.0 catalog had two diagnosable bugs: amplitude was off by 2× (used FFT magnitude rather than real-sinusoid amplitude 2|X[k]|/N), and phase was wrongly assumed 0 (with the Mercury patch reinforcing its target residual to −49.9% before the fix). v0.5.1 ships three research scripts: patch_shrinks_residual.py (the benchmark), author_phase_recovered_patches.py (re-author from the complex FFT spectrum, fixing both bugs), verify_recovered_patches.py (re-run with recovered catalog). Recovered results: J–S coupled patch shrinks both Jupiter (77.1%) and Saturn (76.4%); Mercury 39.6%; Mars stuck at 2.7% due to FFT bin leakage. Empirical finding worth documenting: J–S correlation = +1 (in-phase) at 9.56 yr — the v0.4.0 anti-correlated-libration assumption was wrong. v0.5.2 will add windowed FFT + multi-bin patches to unblock Mars and ship a CATALOG_V2 that meets the ≥80% bar across every body. v0.4.0 catalog unchanged in the wheel — v0.5.1 is audit + diagnostic, not a behavior break.
v0.5.0 2026-05-05 All major Jovian + Saturnian moons join the encoder; SPICE-free runtime. Body roster grows 26 → 38: Jovian inner regulars (Metis, Adrastea, Amalthea, Thebe), classical Saturnian moons (Mimas, Tethys, Dione, Hyperion, Iapetus, Phoebe), Saturn co-orbitals (Janus, Epimetheus). Three new famous resonances wired: Mimas–Tethys 4:2 (Cassini Division), Enceladus–Dione 2:1 (Enceladus tidal heating), Titan–Hyperion 4:3 (Hyperion chaotic rotation). Natural-resonance gear group expands Z_30 → Z_60 (Z_4 × Z_3 × Z_5). New codegen step emits _data/initial_phases.jsonpip install ephemerides-spectral works out of the box, no SPICE staging required for either backend. Pre-ship FFT sweep confirms zero regressions on the 10 DE441-coverable bodies (every peak amplitude byte-identical to v0.3.1) and 21× faster sweep thanks to the v0.4.1 C native + v0.5.0 SPICE-free init phases. Validation of the new moons' encoded longitudes against ephemeris truth pending v0.5.x supplementary-kernel work (mar097 / jup340 / sat441).
v0.4.1 2026-05-05 C-side runtime kernel patching (ABI v2). Native backend now applies the diagnosed-fiber overlay — backend="c" produces byte-identical phases to backend="bip" even with patches active. New c/src/es_patches.c carries the registry; encoder hook in es_encode_state runs after the sub-day remainder, before the final cyclic-group reduction. Banker's rounding shared between encode + overlay paths so the integer deltas match numpy.round half-to-even semantics byte-for-byte. Python ctypes shim mirrors the registry into C on every apply_patch / clear_patches; rejections on either side roll back the other. 237× speedup on patched encodes (10.8 ms → 0.046 ms); patch overhead +19 μs C vs +418 μs BIP. ABI v1 → v2 (v0.3.1 binaries with v0.4.1 wheel will refuse to load native; falls back to pure-Python BIP cleanly).
v0.4.0 2026-05-05 Runtime kernel patching — diagnosed-fiber overlay (Python side). Patches sit beside the published spectral kernel as DATA (not code edits) and contribute per-body residue deltas at encode time; the kernel's published bytes never change. Inspired by Linux ksplice / kpatch. Three patches in the bundled CATALOG, each authored directly from a v0.3.1 FFT residual peak: mars-7.96yr-diagonal (3.45° amplitude), mercury-10.69yr-diagonal (9.19°), jupiter-saturn-9.56yr-coupled (45° anti-correlated, the J–S 5:2 libration smoking-gun). Two patch kinds: SinusoidPatch (diagonal, single body) and CoupledSinusoidPatch (off-diagonal pair with correlation ∈ {-1, +1}). New bridge.apply_patch / apply_custom_patch / list_catalog_patches / list_active_patches / clear_patches; CLI patches catalog/apply/active/clear. With no patches active the encoder is byte-identical to v0.3.1 (regression test pinned). v0.4.0 gated backend="c" to fall back to BIP when patches active — superseded by v0.4.1's C-side overlay.
v0.3.1 2026-05-04 C-in-wheel + spectral syzygy window search + DE441 error-spectrum FFT. Native C backend (backend="c") bundled in platform wheels via cibuildwheel; ~1000× speedup on the encode hot loop; byte-exact parity with the Python BIP encoder. Spectral syzygy window search (find-syzygies) replaces v0.3.0's point-evaluation eclipse --jd for window queries — O(n_syzygies × confirmation) instead of O(window_days × encode), ~1000× faster for multi-decade windows. New de441_error_spectrum.py FFTs the per-body residual; headline finding: Jupiter–Saturn show identical 9.56-yr peaks at ±45° amplitude — the smoking-gun missing-coupling signal motivating v0.4+'s first-principles α derivation. Pure-Python py3-none-any wheel preserved for Pyodide / WASM.
v0.3.0 2026-05-04 Time scales + DE441 sweep + natural-resonance group. New bridge surface for Mars Sol Date / Mars Coordinated Time (Allison & McEwen 2000) and mean lunar synodic + sidereal phase primitives. LTE440 (Lin et al. 2025) registered as a known lunar-time ephemeris (metadata only; no auto-download). New CLI subcommands time-mars, time-lunar, lunar-kernels, natural-group. New research/de441_sweep.py runs the BIP encoder across J2000 ± 14,000 yr against DE441 ground truth — see figures/de441_full_sweep.md for the table (Earth/Venus/Uranus < 10° at multi-millennium horizons; Mars 14°; Mercury 84°; Jupiter/Saturn/Neptune/Pluto/Moon hit >150° — the structural-limit signature of phenomenological α). New bridge.get_natural_resonance_group() returns the resonance-derived cyclic group (Z_30 = Z_2 × Z_3 × Z_5 for the v0.2.0 four-resonance set), distinct from the encoder's architectural Z_{2^32}. LTC deferred to v0.4+.
v0.2.0 2026-05-04 Phase 9 coverage extension. The hardcoded Jupiter–Saturn 5:2 entry is promoted to a structured RESONANCES SSOT table; three new resonances are wired alongside it: Neptune–Pluto 3:2 (orbital), Io–Europa 2:1 + Europa–Ganymede 2:1 (the two legs of the Jovian Laplace resonance). The reference encoder, the BIP encoder, and the C codegen all walk the same table — single source of truth in research/laplacian.py. Encoded phase residues for Io / Europa / Ganymede / Neptune / Pluto shift relative to v0.1.0 (their breathing modulation is now active); Earth's phase is unchanged; the 0.0002 rad Earth phase floor at +20 yr against DE421 is preserved. C port: es_n_couplings grows from 1 to 4; byte-for-byte parity with Python verified across all 26 bodies.
v0.1.0 2026-05-04 First public release on PyPI. 26-body Sol Star System Laplacian (diagonal mean motions + Mercury PN correction + static gravitational fiber couplings); Phase 9 state-dependent (non-autonomous) breathing couplings — Jupiter–Saturn 5:2 resonance modulated via 1024-entry int32 cosine LUT (Q1.14, 4 KB), end-to-end on the integer ALU; ALU-native BIP encoder over Z_{2^32} (uint32 cyclic-group binding via free overflow) with 305× speedup vs the FPU reference and 256 KB state at D=65536; FPU complex128 reference encoder preserved for the algebraic identities (Syzygy operator, observer binding, regression baseline); pre-flight bounds check + scoped np.errstate(over='raise') on signed-int64 multiplies; lenient errstate(over='ignore') + warning filter on the uint64 accumulator; rich CLI (9 subcommands: version, bodies, kernel list, resolution, encode, local-view, eclipse, couplings, breathing); Pyodide-friendly bridge with input validation and {ok: True/False} JSON contract; codegen-stamped frozen-data manifest.

Next planned

Version Theme
v0.24.10 Out-of-sample probe catalog + classifier calibration metric. Shipped in v0.24.10. See released versions table above.
v0.25.0a Attested Multi-Source Collector framework — checkpoint commit (in flight). Shipped as part of v0.25.0.
v0.25.0a-original (original entry retained for git history) Attested Multi-Source Collector framework — checkpoint commit (in flight). Implements notebook §18 normative spec: MPR (Mathematical Provenance Record) v1 NDJSON format with mandatory attestation block, descriptor TOML schema with [rendering] (self-describing verbiage) + [gap_targeting] (designed-for-but-not-consumed for v0.26.x schema-gap-driven trigger), 5-adapter shared core via typing.Protocol (html_scraper real impl; json_api/csv_bulk parse-real-fetch-stub for v0.25.0b; netcdf_grid/geotiff_bbox fixture-only stubs gated behind collector-netcdf / collector-geotiff extras), universal catalog wrapper, 4 new bridge surfaces + 4 new CLI subcommands, EarthRef SC pilot descriptor (NDJSON commits in v0.25.0b T1 first run). Codegen: byte-exact recursive mirror via emit_attested_collections.py; manifest walks _research/ recursively; regenerate.py does no network I/O. Code-only checkpoint — no PyPI release; v0.25.0 stable publishes when v0.25.0b lands (GMRT + PetDB pilots + T1 collect CI workflow). 37 new tests. Pure-Python additive; no ABI bump.
v0.25.0b GMRT + PetDB pilots + T1 collect CI workflow. Shipped as part of v0.25.0.
v0.25.1 T2 user runtime kernel — local NDJSON overlay. Shipped in v0.25.1.
v0.25.2 T3 live query. Shipped in v0.25.2.
v0.27.0 phase A literature_curated AMSC backfill of every v0.24.x _data.py catalogue. Shipped via PRs #303 (Mercury), #306 (Luna), #308 (Mars), #309 (Sun), #311 (Toroidal-Residual), #312 (Hawaii), #313 (Yarkovsky/YORP), #314 (Mars Tharsis), #315 (Axial Seamount), #316 (Dynamical-Regime + OOS probes, paired-as-two-sources), #317 (Pluto-Charon), #319 (Loki Patera). All 12 v0.24.x catalogues now have descriptor + JSON Schema + NDJSON + dual-author byte-stable diff tests. Pattern established: _round_sig(x, 12) rounding for libm-computed fields; nodoi: / historical: / isbn: source-DOI prefixes for non-Crossref references; per-catalogue physics ratchets pinning load-bearing claims. The v0.27.0 banner remains open; phases B (binary_archive adapter), C part 2 (orbital-mechanics surface plumbing), and D (use_local_kernel extension) still pending.
v0.27.0 Three-layer mechanism architecture — JPL kernel set + AMSC backfill + body→kernel registry. Status (2026-05-10): phase A complete (PRs #303–#319, 12 v0.24.x catalogues); phase C part 1 complete (PR #299 body→kernel registry abstraction); phases B + C part 2 + D remain. Banner flips when all four pieces ship. Codifies the architecture named in notebook §22 (PR #296): layer 1 (AMSC attestation envelope) covers every piece of data the project consumes; layer 2 (heavy store) is the JPL kernel set + the v0.24.x _data.py modules for bodies no JPL kernel covers; layer 3 (spectral scaffold) is everything that's a function of system structure rather than (body, time). Full-coverage scope on the user-controlled-data axis. Four mutually-reinforcing pieces under one banner: (A) literature_curated AMSC backfill of every v0.24.x _data.py catalogue — descriptor + schema + NDJSON + dual-author byte-stable diff inheriting the Saturn-rings pattern (PR #291); (B) new binary_archive adapter + descriptors for the JPL kernel set (DE441 part 1/part 2, sat441, ura111, nep097, jup365, plu060, plus a published-asteroid pilot) — lazy-fetch, content-addressed cache, SHA-verified; (C) body→kernel registry + plumbing through predict_itn_accessibility, find_itn_chains, find_itn_pathways, find_syzygies, get_breathing_modulation, get_eclipse_probability, body_architecture and the action-angle / coupling / regime surfaces — eigenbasis cached by roster+kernel hash; fallback to BODIES-distilled values when no kernel registered; (D) extends bridge.use_local_kernel() (v0.25.1 T2) to accept the registry. Each piece is a separate PR; the v0.27.0 banner flips when all four are merged. The empirical claim is the 52-body JPL-quality result (§22.7): every body in the roster is served at the highest-precision available kernel, with the spectral scaffold binding them into a unified system. Resolves the AMSC-backfill question of the "pre-v1.0 architectural review" row below for the v0.24.x catalogues (the four MPM screens are met for every catalogue that has cited literature; fallback documented honestly for the rest). Companion artifact: the stored-relationship mechanism research spike (PR #294) — cross-domain framing for the eight-notebook collection.
v0.25.x or later Saturn ring system temporal-spectrum catalog. Multi-regime body — combines rigid-body action-angle (Mimas-Cassini-division 2:1 lock; classical Saturnian resonance ladder), temporal cycles (F-ring shepherds Pandora / Prometheus quasi-periodic boundary modulations), and shape-residual context (Saturn the closest-to-Maclaurin-Jacobi-bifurcation Solar-System body, q ≈ 0.158 vs threshold 0.187 from v0.24.4). Would be the project's first multi-regime body ship and a strong test of the v0.24.9 dynamical-regime classifier's discriminative power — a body that should sit ambiguously between several training regimes simultaneously, exercising the calibration-ratio metric. Sources: Murray-Dermott 1999 Solar System Dynamics §10 (ring dynamics); Tiscareno 2018 ring-edge resonance review; Spitale-Porco 2009 F-ring shepherd modulation; v0.24.4 + v0.21.4 already cite the Mankovich-Fuller 2021 Saturn rotation. New physics ship; not derivable from existing v0.24.x catalogs.
v0.25.x or later Loki Patera (Io) tidal-heating temporal-spectrum catalog. Shipped in v0.24.12. See released versions table above.
v0.4.x phase F C-side overlay (ABI v2 bump). Shipped in v0.4.1. See released versions table above.
v0.5.2 Windowed FFT + multi-bin patches → CATALOG_V2. Superseded. v0.5.2 took a different route — LS-fit at the exact target period (closed-form + scipy refinement) bypasses FFT bin leakage entirely and hit 96-99% shrinkage on planets with single-sinusoid patches. Multi-bin became unnecessary on the planet set. Now revived as a different motivation: Hyperion's chaotic-rotation residual (v0.5.5) shows multi-peak quasiperiodic structure that single-sinusoid LS-fit can't capture (75.2% vs the 80% gate). A multi-component patch — one entry expressed as a list of (period, amplitude, phase) sinusoids — is the right shape for that. Targeted at v0.5.x or v0.6.x.
v0.5.x Remaining 4 broken moons (metis, thebe, rhea, phoebe). Period truncation fix (v0.5.3) cleaned 13 of 17 moons; these 4 resisted. Each needs physics-specific investigation: Phoebe retrograde sign fix; Metis authoritative period; Thebe + Rhea likely perturbation-driven.
v0.5.x Moon catalog patches: re-run patch-shrinks-residual on the v0.5.3 moon residuals; author CATALOG_V2 entries for measurement-validated coefficients on the Saturnian resonances. Shipped in v0.5.5 — see released versions table above. 5 of 6 targets vindicated at 93-99%; Hyperion at 75% queued for the multi-component or coupled-T-H follow-up.
v0.6.x Hyperion multi-component or Titan-Hyperion 4:3 coupled patch. Hyperion's chaotic rotation produces quasiperiodic-not-sinusoidal residual with multiple peaks near 72d (rank 1 5.44°, rank 3 1.39°, rank 5 1.30°). Two candidate paths: (1) multi-component sinusoid at the 4:3 beat — single catalog entry, list of (period, amp, phase) covering the Hyperion sub-peaks; (2) coupled titan-hyperion-4to3-coupled-v2 patch — v0.5.0 wired the resonance into RESONANCES but couldn't calibrate. Either approach should beat the 80% gate that single-sinusoid LS-fit can't.
v0.5.x Moon residual root-cause investigation. v0.5.2's moon FFT sweep shows 13 of 17 moons have ~100° RMS residuals dominated by near-DC content (FFT peak at sweep-span = 336 yr). Callisto / Titan / Iapetus / Hyperion are clean (~0.6–11° RMS); the rest aren't. Likely cause: _calibrate_initial_phases's skyfield astrometric.ecliptic_latlon lookup recovers the wrong reference frame for moons whose barycenter chain crosses an auxiliary SPK kernel. Once fixed, the LS-fit catalog methodology (vindicated on planets at ≥96%) should apply directly to author moon patches.
v0.5.x Supplementary moon-kernel codegen (mar097, jup340, sat441). v0.5.0's 12 new moons get their initial phases from a period-based fallback because DE441 only ships planet barycenters + Sun + Earth + Moon. With the satellite SPK kernels staged at codegen time, the moons get real ephemeris truth at REFERENCE_JD. Then the FFT sweep can compare encoded moon longitudes against truth — likely surfacing new Saturnian / Jovian moon residual peaks worth authoring catalog patches against. Runtime stays SPICE-free; the kernels are codegen-time inputs only. See figures/de441_error_spectrum_v0.5.0.md for the motivation.
v0.4.x First-principles per-resonance α. Replace the phenomenological α = 0.1 modulation depth with values derived from a Hamilton/Delaunay-variable Lagrangian (Lie-series perturbation theory around each resonance). Empirically motivated by the v0.3.0 DE441 sweep, which shows Jupiter/Saturn/Neptune/Pluto/Moon phase-scrambling at multi-millennium horizons under uniform α. The v0.4.0 catalog patches are the application-side analog: empirical sinusoidal corrections that v0.4.x's first-principles α should ultimately make redundant for the bodies inside the resonance set.
v0.4.x Patch-shrinks-residual benchmark. Shipped in v0.5.1 (PARTIAL) → v0.5.2 (VINDICATED on planets, ≥96%) → v0.5.5 (VINDICATED on moons, ≥93%). See released versions table above. The methodology is now vindicated twice on independent body sets.
v0.4.x (research) DE441 vs DE442 spectral error signature (experiment). Build two BIP instruments from scratch — one calibrated only from DE441, one only from DE442. For a sample of JDs across both kernels' overlap, encode the system on both and compute per-body residue deltas: Δφ_b = (A.phases[b] − B.phases[b]) mod 2^32. Project the deltas onto the encoder's eigenbasis (Laplacian eigenmodes). Hypothesis: DE442's corrections to DE441 live in a coherent eigenmode subspace — the spectral signature of the kernel-update. If true, the signature lets us predict where ephemeris error correction is structurally needed without needing the corrected kernel. New research/de441_vs_de442_signature.py; figures/ entry with the eigenmode decomposition.
v0.4.x Spectral kernel + diagnosed-fiber patches. Shipped in v0.4.0 (Python overlay) → v0.4.1 (C-side ABI v2 + native overlay). The full diagonal/coupled patch typology landed; v0.5.2 + v0.5.5 then ship the CATALOG_V2 LS-fit-vindicated entries on top. See released versions table above.
v0.5.x Runtime kernel patching (overlay, not bones-mutation). Shipped in v0.4.0 — see released versions table above. The Python-side overlay is live; C-side ABI v2 surface is v0.4.x phase F (see preceding row).
v0.4.x Spectral syzygy window search. Shipped in v0.3.1 (Python BIP path) → v0.6.0 (C twin via backend="c" Tier 1 parity port). See released versions table above.
v0.7.0 C/Python parity Tier 2b — HD encode + observer-bind + eclipse projection. Shipped in v0.7.0 — see released versions table above. Parity smoke now has zero tier_skip entries.
v0.8.x or later Sol Moon Times — Sol <Parent>-<Body> Time hierarchy. v0.8.0 ships Sol Times for the Sun + 5 planets + Pluto. Future ports under the naming convention: Sol Earth-Moon (replacement for the convention-name "Sol Lunar"), Sol Mars-Phobos, Sol Mars-Deimos, Sol Pluto-Charon, the 4 Galileans (Sol Jupiter-Io / -Europa / -Ganymede / -Callisto), the 9 classical Saturnians, etc. Each requires sidereal day, orbital period, parent-body anchor, retrograde flag, IAU-defined prime meridian. Many of these have IAU 2015/2018 cartographic-coordinates working group data. Targeted opportunistically — moons whose users care can ship first.
v0.7.x Phase 2c — FPU matrix-expm path decision. TIER2_DESIGN.md deferred this: keep the matrix-expm propagation as backend="fpu-ref" for backwards compat (current v0.7.0 choice), or retire it once we measure the path-divergence on the DE441 sweep. The matrix-expm path captures second-order Laplacian effects that the BIP integer encoder approximates phenomenologically; whether that matters for any consumer is empirically open. Decision rests on the divergence measurement.
v0.6.x CORDIC topocentric rendering. The cosine LUT is half a CORDIC kernel; the rotation half can subsume the topocentric lat/lon observer-bind, taking that path off the FPU. (Now subsumed by v0.7.0 Tier 2 work — observer-bind in C is the deliverable.)
v0.6.x or later ITN pathway / Lagrange-tube query First cut shipped in v0.8.1 — see released versions table above. Hohmann transfer-window enumeration via the find-syzygies closed-form pattern. C twin + CR3BP gateway / Jacobi-constant / heteroclinic-chain / energy-budget extensions queued under "Next planned" rows below.
v0.8.x or later find_itn_pathways C twin (parity flip). Mirror the v0.3.1 → v0.6.0 find-syzygies trajectory: ship the Python implementation first (v0.8.1), add the C twin in a follow-up minor with ABI bump v5 → v6. Math is the same (Kepler + synodic anchor); the C side reads body initial phases from es_initial_phases and mean motions from es_omega_diag (both already exported). The parity smoke entry flips from tier1_skip to parity when this lands.
v0.8.x or later CR3BP gateway designation + Jacobi constant. Layer the L1/L2/L3 designation onto each candidate. Each gateway has a specific Jacobi constant (energy); emit it as a candidate field. Per-gateway invariant manifold pre-computation at codegen time (or runtime via fixed-point iteration on the linearised CR3BP). The gateway_lp field graduates from "transfer-ellipse" placeholder to a real Lagrange-point label.
v0.8.x or later Multi-leg heteroclinic chains. Sun-Earth L2 → Sun-Mars L1 → Mars surface, etc. Combinatorial enumeration over the gateway graph; each leg an ITNCandidate linked to the next. First cut shipped in v0.17.0 as find_itn_chains — Dijkstra-style graph search over the (body, epoch) state space; each leg a closed-form Hohmann window from find_itn_pathways; cumulative Δv + TOF budget-bounded; per-leg gear-ratio resonance signature (p, q). The CR3BP-gateway-aware version (full Sun-Earth L2 → Sun-Mars L1 chains with explicit Lagrange-point labels) still requires the gateway designation + Jacobi-constant row above; v0.17.0 is the first layer of that arc. References: Koon-Lo-Marsden-Ross 2011 §6 (the "Interplanetary Superhighway").
v0.8.x or later Energy-budget filtering + ballistic-capture windows. --energy-budget X flag emits only candidates whose cumulative Δv fits the budget. Ballistic-capture windows at planetary L1 (Belbruno-style low-energy capture, generalised) become a transfer_kind = "ballistic-capture" candidate.
v0.6.x or later LTC (Lunar Coordinated Time). Pending NASA + international space-agency standardisation (target 2026–2028 per April 2024 White House directive). LTE440 (Lin et al. 2025) ships the underlying SPICE-format conversion ephemeris with 0.15 ns accuracy through 2050; ephemerides-spectral gains an LTC namespace in the bridge mirroring MarsTime once the LTC epoch + day-length convention are formalised.
later Multi-millennium sweep against DE441. Re-derive Metonic + Saros anchors against the full 3.3 GB DE441 with breathing couplings active. Propagator drift floor (~0.0002 rad at +20 yr in v0.1.0 against DE421) re-measured at +200 yr / +2000 yr horizons.
later Sdist standalone build (cmake.source-dir = "."). v0.3.1's published sdist contains the C tree + CMakeLists at the parent of python/ (sdist.include = ["../CMakeLists.txt", "../c/**", ...]), but cmake.source-dir = ".." resolves outside the unpacked tarball root, breaking pip install ephemerides-spectral from sdist on platforms without a wheel. Fix: co-locate the C tree under python/ so cmake.source-dir = "." works for both wheel-from-source and wheel-from-sdist. Currently a non-issue because the 15 platform wheels cover essentially all consumers.
pre-v1.0 architectural review AMSC backfill — migrate v0.24.x hand-coded _research/<topic>_data.py modules to AMSC-backed research/attested/<source>/<table>.ndjson + descriptor + JSON schema. Reviewed before declaring v1.0 stable; the wheel becomes mostly framework + adapters with data living entirely in committed NDJSON, future catalog additions are pure descriptor authorship (no Python data modules at all), and existing v0.24.x ships become eligible for T1 auto-PR data refreshes. MPM-screened, not architect-preference-driven. Apply the four MPM screens to the migration decision itself: (1) reproducibility — does the migrated path regenerate byte-identical to the hand-coded path? (2) provenance — do [gap_targeting] regime labels + per-row attestation survive the migration without losing fidelity vs the hand-coded SOURCES dicts? (3) regenerability — does T1 CI refresh become feasible for v0.24.x ships against their original sources, or are some v0.24.x catalogs unrefreshable in principle (textbook constants, settled-physics anchors, etc.)? (4) Gemini-failure-mode — is the proposed migration vocabulary-match (looks-clean-because-it's-config) or actually-grounded (the descriptor schema demonstrably expresses what the hand-coded modules express)? Validation evidence: the Saturn ring system catalog (task `#153`) is the natural dual-author exercise — author once via the v0.24.x hand-coded path (canonical), once via the AMSC path (validation), diff -q the resulting NDJSON; the agreement (or specific divergences) is the empirical evidence about whether the descriptor schema is rich enough for per-body catalog density. Outcomes (both correct): if all four screens pass, a v0.27.x-or-later migration sequence (~5-10 ships) executes the backfill before v1.0 ships. If any screen fails, v1.0 ships with the dual-path architecture as a deliberate choice, with the failure documented as the reason. Either way the screening is itself the deliverable; the migration is not pre-decided. Cross-references: ephemerides notebook §0.0 (the four MPM screens), §18.1 (the four-tier reproducibility model the migration would extend to v0.24.x), §18.4 (the descriptor schema being evaluated).

Naming convention contingencies

Sol Time abbreviation collision plan — triggered in v0.14.1. The v0.14.0 Sol Moon Times shipped with the 4-letter S<Planet-initial><Moon-initial>T pattern. The v0.14.1 Saturnians introduced two collisions: Tethys + Titan (both T under Saturn → both SSTT) and Enceladus + Epimetheus (both E → both SSET). The fallback policy fired:

v0.14.0 (deprecated):  S<Planet><Moon>T            e.g.  SJGT
v0.14.1+ (active):     S<Planet2><Moon2>T          e.g.  SJuGaT
Multi-star fallback:   S<Star1><Planet2><Moon2>T   e.g.  S?JuGaT  (reserved for Stellar Forge — task #102)

Galilean abbreviations were retroactively renamed in v0.14.1:

Body v0.14.0 v0.14.1+
Io SJIT SJuIoT
Europa SJET SJuEuT
Ganymede SJGT SJuGaT
Callisto SJCT SJuCaT

The 11 Saturnians shipped with the new 6-letter form directly (no v0.14.0 to migrate from): SSaMiT / SSaEnT / SSaTeT / SSaDiT / SSaRhT / SSaTiT / SSaHyT / SSaIaT / SSaPhT / SSaJaT / SSaEpT — all distinct.

Subsequent moon-family ships use the 6-letter form by default. Python function names (jd_to_sol_<parent>_<moon>_time), CLI subcommand names (time-<parent>-<moon>), and bridge return-shape are NOT affected by the policy — only the epoch.abbreviation STRING. Callers reading the abbreviation as a display label / comparison key need to update; callers using the function names directly are unaffected.

The uniform-across-all-moons discipline is load-bearing: mixed conventions (some 4-letter, some 6-letter) would be worse than either pure convention because readers would have to remember which family uses which length. As soon as the first collision triggers, all moons switch.

The same letter-budget logic extends to multi-star systems if ephemerides-spectral ever covers anything beyond Sol — e.g., the Stellar Forge feasibility task `#102`. A star-initial prefix becomes required in that scenario; the existing 6-letter S<Planet2><Moon2>T would become 7-letter S<Star?><Planet2><Moon2>T (or maybe a longer combinator).


Phase status (carried over from v0.1.0 plan)

Phase Status Description
0 — Project framing & sibling-folder discipline ✅ shipped Sits beside antikythera-spectral; cross-references in both notebooks.
5 — Historical resonance (Metonic / Saros) ✅ shipped (v0.1.0) Lunar projection round-trip at +19 yr against DE421.
6 — Interaction fibers (off-diagonal Laplacian) ✅ shipped (v0.1.0) Sun-planet / moon-planet / J-S resonance / asteroid-Jupiter coupling table.
7 — Bit-serialised prototype ✅ shipped (v0.1.0) 305× speedup vs FPU reference at +20 yr, 0.0002 rad Earth phase floor.
8 — Dimensional expansion ✅ shipped (v0.1.0) D = 2^16 .. 2^20 sweep; SNR scales linearly with D.
9 — Breathing Laplacian ✅ shipped (v0.1.0) State-dependent off-diagonal weights; integer cosine LUT; PN correction.
10 — Phase 9 coverage extension ✅ shipped (v0.2.0) RESONANCES SSOT table; J–S 5:2 + N–P 3:2 + Io–Europa 2:1 + Europa–Ganymede 2:1.
11 — Time scales + DE441 sweep ✅ shipped (v0.3.0) MSD/MTC + lunar phase + LTE440 awareness + natural-resonance group + DE441 ±14,000 yr sweep.
12 — C-in-wheel + syzygy window + FFT ✅ shipped (v0.3.1) scikit-build-core platform wheels via cibuildwheel; backend="c" ~1000× speedup; spectral find-syzygies window search; DE441 error-spectrum FFT identifying the J–S 9.56-yr ±45° missing-coupling peak.
11 — First-principles modulation depths ⏳ v0.3.x Replace phenomenological α with Lagrangian-derived values.
12 — CORDIC topocentric ⏳ v0.7.0 Observer-bind off the FPU. Subsumed by Tier 2b (HD state in C → es_bind_observer).
13 — DE441 multi-millennium sweep ⏳ later Re-anchor Metonic + Saros against full 3.3 GB kernel.
14 — C BIP source port ✅ shipped (alongside v0.1.0) Embedded-friendly integer-only kernel; byte-exact parity with the Python reference at +20 yr; codegen reads from the same Python research SSOT. Lives at c/.

Bridge ↔ CLI parity

Every CLI subcommand maps 1:1 to a bridge method; every bridge method has CLI access. Pinned by inspection at v0.1.0:

CLI subcommand Bridge method Status
version bridge.get_version()
bodies bridge.list_bodies()
kernel list bridge.list_kernels()
resolution bridge.get_resolution(body, D)
encode bridge.get_system_state(jd, backend, kernel, force_high_res, D)
local-view bridge.get_local_view(jd, body, lat, lon, kernel)
eclipse bridge.get_eclipse_probability(jd, kernel)
couplings bridge.list_couplings()
breathing bridge.get_breathing_modulation(jd, pair, n_lobes, kernel)
time-mars bridge.jd_to_mars_time(jd_utc) / bridge.mars_time_to_jd(msd) ✅ (v0.3.0)
time-lunar bridge.get_lunar_phase(jd_tdb) ✅ (v0.3.0)
lunar-kernels bridge.list_lunar_kernels() ✅ (v0.3.0)
natural-group bridge.get_natural_resonance_group() ✅ (v0.3.0)
find-syzygies bridge.find_syzygies(jd_lo, jd_hi, kind, threshold) ✅ (v0.3.1)

Future CLI / bridge surface lands here as the corresponding ROADMAP rows ship.

References