Metadata-Version: 2.4
Name: lxephemeris
Version: 1.0.0
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Rust
Classifier: Topic :: Scientific/Engineering :: Astronomy
Summary: Clean-room high-precision astrological and astronomical ephemeris engine (DE440s + IAU 2006/2000A)
Keywords: ephemeris,astrology,astronomy,swisseph,pyswisseph,kerykeion,pyephem,de440,jyotish,human-design
Home-Page: https://procoders.tech/
Author-email: ProCoders <lxephemeris@procoders.tech>
License: PolyForm-Noncommercial-1.0.0 OR LicenseRef-Commercial
Requires-Python: >=3.9
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Commercial License, https://procoders.tech/contacts/
Project-URL: Homepage, https://procoders.tech/
Project-URL: Issues, https://github.com/procoders/lxephemeris/issues
Project-URL: Repository, https://github.com/procoders/lxephemeris

# lxephemeris

**The modern astronomical & astrological computation engine for Python, Node.js, and Rust.**  
*100% memory-safe Rust core. Lock-free multi-threading. Zero external files required to start — with native NASA JPL DE440s support for sub-milliarcsecond precision.*

[![CI](https://github.com/procoders/lxephemeris/actions/workflows/ci.yml/badge.svg)](https://github.com/procoders/lxephemeris/actions/workflows/ci.yml)
[![Rust](https://img.shields.io/badge/Rust-1.80%2B%20%7C%20forbid(unsafe__code)-orange.svg)](#why-we-built-lxephemeris)
[![SDKs](https://img.shields.io/badge/SDKs-Python%20%7C%20Node.js%20%7C%20Rust%20%7C%20CLI-blue.svg)](#quickstart)
[![Golden Suite](https://img.shields.io/badge/Verified-37%2C416_Golden_Vectors-brightgreen.svg)](#verification--benchmarks)
[![License](https://img.shields.io/badge/License-PolyForm_Noncommercial_%7C_Commercial-purple.svg)](#licensing--commercial-use)

---

```python
import lxephemeris

# Works out of the box with zero external files (or loads NASA JPL DE440s if present)
engine = lxephemeris.Engine()

jd_utc = lxephemeris.utc_from_local(2026, 10, 27, 14, 30, 0.0, tz_name="America/New_York")
obs = lxephemeris.Observer(latitude_deg=40.7128, longitude_deg=-74.0060, altitude_m=10.0)

# Full natal snapshot: planets, 23 house systems, aspects, Hermetic lots, lunar phase & sect in ~150 µs
chart = engine.chart_snapshot(jd_utc, obs)
```

---

## Why We Built `lxephemeris`

If you have ever built a production astrology, horary, Vedic, Human Design, or astronomical API in Python or Node.js, you know the pain of the existing ecosystem.

For nearly three decades, almost every backend in the industry has been forced to glue together **Swiss Ephemeris (`libswe` / `pyswisseph`)** — a C library designed in the 1990s for single-threaded desktop apps — alongside **`PyEphem`** and **`Kerykeion`**.

When we ran that legacy stack under high concurrency in production, we kept hitting the same architectural walls:

1. **Global Mutable C State & Thread-Safety Bugs**: `libswe` stores ephemeris paths (`swe_set_ephe_path`), sidereal modes (`swe_set_sid_mode`), and topocentric observers (`swe_set_topo`) in process-global `static` C variables. If Thread A computes a Vedic (Lahiri) chart while Thread B computes a Western (Tropical) chart, **they silently corrupt each other's math**. Fixing this in Python required ratusan lines of global `RLock` wrappers that killed multi-core throughput.
2. **A Mountain of Monkey-Patches**: High-level wrappers had to be patched just to return accurate charts:
   - `Kerykeion` silently clamps latitudes above `±66°`, causing a **7.85° Ascendant error** in Northern Europe, Alaska, and Svalbard, and truncates birth-time seconds (`second=0`), shifting the Ascendant by up to **15 arcminutes**.
   - Rounding planet longitudes (`round(lon, 4)`) before house assignment routinely drops cusp planets into the wrong house.
   - `PyEphem`'s `Sun().hlong` returns Earth's heliocentric longitude shifted by `180°` (breaking Chinese *Jieqi* solar terms), and `ephem.Ecliptic(ephem.Moon(obs))` rotates topocentric coordinates using static J2000 obliquity (**23 arcminutes of error**).
3. **22 Upstream Calculation & C Buffer Bugs**:
   - Missing `.se1` ephemeris files cause `libswe` to **silently downgrade** to a lower-precision fallback without raising an error.
   - `swe_house_pos` returns an invalid `0.0` at high latitudes or circumpolar declinations.
   - `swe_fixstar2_ut("Mira")` matches `Mirach` (**>17° error**) due to naive prefix matching in C.
   - Star-anchored sidereal modes (`True Citra`, `Revati`, `Pushya`) wobble by **±20.5 arcseconds** every year because annual stellar aberration is mixed into the anchor star.
4. **Slow FFI Loops for Transits, Returns & Timelines**: Finding a year of exact transit windows, retrograde stations, Void-of-Course Moon intervals, or a 3-pass Saturn Return meant running tens of thousands of Python/JS bisection calls across the C FFI boundary — taking hundreds of milliseconds per request.
5. **Dependency Sprawl**: Teams had to maintain 5–6 different libraries — one for planetary positions, one for lunar phases, one for natal wheels, another for Vedic Panchanga/Dasha, another for Hellenistic Lots, and custom scripts for Human Design gates or Chinese calendars.

**So we built `lxephemeris` from scratch in 100% safe Rust (`#![forbid(unsafe_code)]`).**

No C pointers. No global state. No monkey-patches. Just one ultra-fast, mathematically rigorous engine with first-class native SDKs for **Python (`PyO3`)**, **Node.js / TypeScript (`napi-rs`)**, and **Rust**.

---

## What Makes `lxephemeris` Better

### 1. One Engine Replaces 6+ Libraries (Batteries Included)
Instead of stitching together `pyswisseph` + `ephem` + `kerykeion` + custom scripts, `lxephemeris` ships every major astronomical and astrological subsystem natively in Rust:

- **Solar System & 68 Minor Bodies**: `Sun..Pluto`, 7 Lunar points (`Mean_Node`, `True_Node`, `Mean_South_Node`, `True_South_Node`, `Mean_Lilith`, `True_Lilith`, and smooth $C^2$ `Interpolated_Lilith`), 9 Uranian hypotheticals (`Cupido..Poseidon`, `Isis`), and **68 JPL `SB441-N16` asteroids, centaurs, and dwarf planets** (`Chiron`, `Ceres`, `Pallas`, `Juno`, `Vesta`, `Pholus`, `Nessus`, `Eris`, `Sedna`, `Haumea`, `Makemake`, `Lilith (1181)`, `Proserpina (26)`, etc.).
- **23 House Systems + Polar Safety**: Placidus, Koch, Porphyry, Regiomontanus, Campanus, Equal, Whole Sign, Alcabitius, Morinus, Topocentric (Polich-Page), Krusinski, APC, Carter, Sunshine, Gauquelin (36 sectors), and more — with explicit `PolarPolicy` (`Strict`, `FallbackToWholeSign`, `FallbackToPorphyry`) so Arctic/Antarctic charts never crash or flip 180°.
- **Native Event & Timing Solvers**:
  - **Aspects & Transits**: Static natal & synastry aspects (`calc_chart_aspects`, `calc_synastry_aspects`), declination parallels/contraparallels, exact sky-to-sky aspect windows (`mutual_aspects_in_range`), natal transit timelines (`natal_transits_in_range`), and **Void-of-Course Moon** intervals (`void_of_course_moon_in_range`).
  - **Planetary Returns & Stations**: Exact Solar, Lunar, Saturn, and Chiron returns (`planetary_return`, `planetary_returns_in_range`) that automatically detect all **3 passes** of a retrograde return loop, plus exact retrograde/direct stations (`search_stations_in_range`).
- **Vedic / Jyotish Suite**:
  - **43+1 Sidereal Ayanamsas**: All 43 standard models (`Lahiri`, `True Citra`, `Krishnamurti (KP)`, `Raman`, `Fagan-Bradley`, `Suryasiddhanta`, `Yukteshwar`, etc.) plus custom user-defined ayanamsas — free of annual aberration wobble.
  - **Panchanga, Muhurta & Vargas**: Full 5-limb `panchanga` (`Tithi`, `Nakshatra + Pada`, `Yoga`, `Karana`, `Vara`, plus `Rahukalam`, `Yamagandam`, `Gulika Kalam`, `Abhijit Muhurta`), all **16 Parashara Shodashavarga (`D1..D60`)**, and **120-year Vimshottari Dasha** (`Maha`, `Antar`, `Pratyantar`).
- **Traditional & Hellenistic Suite**: Day/Night chart sect (`chart_sect`), **24 Chaldean Planetary Hours** (`planetary_hours`), and **7 Hermetic Lots** (`Fortune`, `Spirit`, `Eros`, `Necessity`, `Courage`, `Victory`, `Nemesis` with diurnal/nocturnal reversal).
- **Human Design & Chinese Solar Calendar**:
  - **Human Design**: Exact `-88°` prenatal Design solar arc solver (`human_design_epoch`) and 64 I-Ching Mandala Gates × 6 Lines × Color × Tone × Base (`map_zodiac_placement`).
  - **Chinese Almanac**: All 24 Solar Terms (*Jieqi* / *Zhongqi*, `solar_terms_in_range`), 4 cardinal seasons (`seasons_in_year`), and lunar phase solvers (`lunar_phases_in_range`, 8-phase & 28-phase `lunar_phase_summary`).
- **Fixed Stars, Brady Parans, Eclipses & Occultations**:
  - **52 Embedded Fixed Stars** (VizieR Hipparcos-2 `I/311` + XHIP `V/137D` with full 3D space motion) + custom `sefstars.txt` / JSON catalog loader.
  - **Bernadette Brady Parans** (`find_parans`) & **Schaefer Heliacal Risings/Settings**.
  - **Solar & Lunar Eclipses** (global & local Besselian solvers with Saros series/member and path width) & **Lunar Occultations** of stars, planets, and asteroids.

### 2. Zero External Files Required — Or Sub-Milliarcsecond JPL `DE440s`
- **Instant Zero-File Start (`Engine()`)**: Works the second you install it. When no external `.bsp` files are configured, `lxephemeris` uses its built-in `DE440s`-calibrated analytical engine covering **`-3000 CE .. +3000 CE`** with zero disk I/O.
- **Observatory-Grade SPK Mode (`Engine.from_data_dir("./data")`)**: Point the engine at NASA JPL **`DE440s`** (`1849–2150`), **`DE440`** (`1550–2650`), **`DE441`** (`-13200..+17191`), or **`INPOP21a`** plus `asteroids_68_1850_2100.bsp` for **`< 0.003 arcsecond`** agreement with NASA JPL Horizons.

### 3. 5–15× Faster (Single-Pass Analytical Velocities)
Legacy ephemeris libraries compute planet speed (`°/day`) by evaluating the ephemeris 3 separate times ($t - \Delta t, t, t + \Delta t$) and taking a finite difference — which is both 3× slower and prone to $0^\circ / 360^\circ$ wrap-around glitches.
- `lxephemeris` differentiates Chebyshev polynomials, relativistic light-time, aberration, and the IAU 2006/2000A frame rotation matrix **analytically in a single pass**:
  - **`12.8 µs`** per planetary position + instantaneous velocity.
  - **`~150–240 µs`** for a complete natal chart (`chart_snapshot`).
  - Releases the **Python GIL** and runs multi-core **Rayon** batch queries (`calc_batch`, `calc_batch_flat_f64`, `houses_batch`) across all CPU cores.

### 4. Drop-In Migration for Existing `pyswisseph` Codebases
Don't want to rewrite your whole app at once? `lxephemeris` includes a thread-safe **`SweAdapter`** that mirrors the `swisseph` API (`calc_ut`, `houses_ex2`, `fixstar2_ut`, `get_ayanamsa_ex_ut`, `sol_eclipse_when_glob`, `lun_eclipse_when`, `nod_aps_ut`, `pheno_ut`, `rise_trans`, `azalt`, `julday`, `revjul`, and `SE_*` constants) — scoped safely to an engine instance instead of global C state.

---

## How `lxephemeris` Compares

| Feature | **`lxephemeris`** | **Swiss Ephemeris (`pyswisseph`)** | **Kerykeion** | **PyEphem (`ephem`)** | **Skyfield** |
| :--- | :--- | :--- | :--- | :--- | :--- |
| **Core Architecture** | **100% Safe Rust (`#![forbid(unsafe_code)]`)** | Legacy C (`libswe`, 1990s) | Python wrapper over `pyswisseph` | Legacy C (`libastro`) | Pure Python / NumPy |
| **Thread Safety** | **Lock-free `Send + Sync` (0 state bleed)** | ❌ Global mutable C `static` state | ❌ Inherits `pyswisseph` globals | ⚠️ Mutable `Body` objects | ✅ Thread-safe |
| **Works with 0 External Files** | **✅ Built-in analytical engine (`-3000..+3000`)** | ⚠️ Silent fallback if `.se1` missing | ✅ Bundles `.se1` files | ✅ Analytical only | ❌ Requires downloading `.bsp` |
| **JPL `DE440s` / `DE441` Precision** | **✅ Native DAF/SPK (`< 0.003"`)** | Compressed `.se1` re-fits | Via `pyswisseph` | ❌ Truncated VSOP87 (multi-arcsec drift) | ✅ Native SPK |
| **Single Body + Speed Latency** | **`12.8 µs` (analytical Jacobian)** | `~45–90 µs` (3-pt finite diff) | `~25–80 ms` per subject | `~80–150 µs` | `~600–2,000 µs` |
| **23 Houses & Arctic/Polar Safety** | **✅ All 23 + explicit `PolarPolicy`** | ⚠️ Silent polar fallback & `house_pos=0.0` bug | ❌ Clamps `\|lat\| > 66°` (**7.85° ASC error**) | ❌ No astrological houses | ❌ No astrological houses |
| **68 Astrological Minor Bodies** | **✅ Single verified `.bsp` + Keplerian fallback** | Manage 68 separate `.se1` files | Partial | ❌ Manual orbital elements | Manual SPK segments |
| **43+1 Sidereal Ayanamsas** | **✅ Aberration-free star anchors** | ⚠️ `±20.5"` annual aberration wobble on star anchors | ⚠️ Leaves secondary points tropical | ❌ None | ❌ None |
| **Transit, Return & VoC Moon Solvers** | **✅ Native Rust Newton-Illinois solvers** | ❌ Write your own FFI loops | ❌ Static charts only | ❌ Basic rising/phase only | Discrete `almanac` only |
| **Vedic (Panchanga, Dasha, D1–D60)** | **✅ Built-in** | ❌ None | ❌ None | ❌ None | ❌ None |
| **Traditional (Sect, Hours, 7 Lots)** | **✅ Built-in** | ❌ None | ❌ None | ❌ None | ❌ None |
| **Human Design (64 Gates & `-88°` Arc)** | **✅ Built-in** | ❌ None | ❌ None | ❌ None | ❌ None |
| **SDKs with Identical Math** | **Python, Node.js/TS, Rust, CLI** | C + separate 3rd-party bindings | Python only | Python only | Python only |

---

## Quickstart

### Python (`lxephemeris`)

```python
import lxephemeris

# 1. Start immediately (zero external files needed) or load NASA JPL DE440s from ./data
engine = lxephemeris.Engine()
# engine = lxephemeris.Engine.from_data_dir("./data", verify_manifest_sha256=True)

# 2. Local wall-clock time -> UTC Julian Date (preserves fractional seconds & PEP 495 DST fold)
jd_utc = lxephemeris.utc_from_local(2026, 10, 24, 14, 0, 32.5, tz_name="Europe/Berlin", fold=0)
obs = lxephemeris.Observer(51.5074, -0.1278, 35.0)

# 3. Single body position + analytical speed + visual magnitude
sun = engine.calc("Sun", jd_utc, scale="UTC")
chiron = engine.calc("Chiron", jd_utc, scale="UTC")
print(f"Sun: {sun.lon_deg:.6f}° (speed={sun.lon_speed_deg_day:.6f}°/d, Vmag={sun.magnitude_v:.2f})")

# 4. Polar-safe houses & cusp boundary guard (eps = 1e-9°)
houses = engine.houses(
    jd_utc,
    latitude_deg=51.5074,
    longitude_deg=-0.1278,
    system="P",
    scale="UTC",
    polar_policy="fallback_to_whole_sign",
)
sun_house = lxephemeris.house_of_lon(sun.lon_deg, houses.cusps_deg, eps_deg=1e-9)

# 5. All-in-one Natal Snapshot, Solar Return, Vedic Panchanga, & Human Design Gate
snapshot = engine.chart_snapshot(jd_utc, obs)
solar_return = engine.planetary_return("Sun", jd_utc, jd_utc + 350.0)
panchanga = engine.panchanga(jd_utc, obs, ayanamsa="lahiri")
hd = lxephemeris.map_zodiac_placement(sun.lon_deg)
print(f"ASC: {houses.asc_deg:.4f}° | Sun in House {sun_house} | HD Gate {hd.hd_gate}.{hd.hd_line}")
```

### Node.js / TypeScript (`lxephemeris`)

```typescript
import { Engine, utcFromLocal, houseOfLon, mapZodiacPlacement } from "lxephemeris";

// 1. Start immediately (zero external files needed) or load NASA JPL DE440s from ./data
const engine = new Engine();
// const engine = Engine.fromDataDir("./data", 4, null, true);

const jdUtc = utcFromLocal(2026, 10, 24, 14, 0, 32.5, "Europe/Berlin");
const jdSplit = { jd1: jdUtc, jd2: 0.0 };
const obs = { latitudeDeg: 51.5074, longitudeDeg: -0.1278, altitudeM: 35 };

const sun = engine.calc("Sun", jdSplit, "UTC");
const houses = engine.houses(jdSplit, obs, "P", "UTC", "fallback_to_whole_sign");
const sunHouse = houseOfLon(sun.lonDeg, houses.cuspsDeg, 1e-9);
const snapshot = engine.chartSnapshot(jdUtc, obs);
const hd = mapZodiacPlacement(sun.lonDeg);

console.log(
  `Sun: ${sun.lonDeg.toFixed(6)}° in House ${sunHouse} | HD Gate ${hd.hdGate}.${hd.hdLine} | Lots: ${snapshot.lots.length}`
);
```

### Rust (`lxephemeris-core`)

```rust
use lxephemeris_core::{
    AspectPreset, BodyId, CalcOptions, Engine, HouseOptions, HouseSystem, Observer,
    PlanetId, PolarPolicy, TimeInput, JD_J2000,
};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. Zero-file analytical start (or Engine::from_data_dir("./data", EngineConfig::default())?)
    let engine = Engine::default();

    // 2. Single-pass position + analytical velocity (12.8 µs)
    let t = TimeInput::from_tt_jd(JD_J2000);
    let sun = engine.calc(BodyId::Planet(PlanetId::Sun), t, CalcOptions::default())?;
    println!("Sun: lon={:.6}°, speed={:.6} °/day", sun.lon_deg, sun.lon_speed_deg_day);

    // 3. Polar-safe houses & one-call ChartSnapshot
    let obs = Observer::new(51.5074, -0.1278, 35.0)?;
    let houses = engine.houses(
        t,
        obs,
        HouseOptions {
            system: HouseSystem::Placidus,
            polar_policy: PolarPolicy::FallbackToWholeSign,
            ..Default::default()
        },
    )?;
    let snapshot = engine.chart_snapshot(
        t,
        obs,
        &[BodyId::Planet(PlanetId::Sun), BodyId::Planet(PlanetId::Moon)],
        HouseOptions::default(),
        CalcOptions::default(),
        AspectPreset::Major,
        1.0,
    )?;
    println!("ASC={:.4}°, MC={:.4}°, Lots={}", houses.angles.asc_deg, houses.angles.mc_deg, snapshot.lots.len());
    Ok(())
}
```

### Command-Line Interface (`lxephemeris-cli`)

```bash
# Calculate planetary & asteroid positions (works out of the box with zero external files)
cargo run --release -p lxephemeris-cli -- calc --jd 2460676.5 --bodies Sun,Moon,Chiron

# Calculate house cusps & angles
cargo run --release -p lxephemeris-cli -- houses --jd 2460676.5 --lat 51.5074 --lon -0.1278 --system P

# Vedic Panchanga for New Delhi
cargo run --release -p lxephemeris-cli -- panchanga --jd 2460676.5 --lat 28.6139 --lon 77.2090 --ayanamsa lahiri

# Legacy swetest-compatible output
cargo run --release -p lxephemeris-cli -- swetest -b1.1.2000 -p0123456789 -fPlbR

# Synchronize IERS finals2000A (Delta-T / UT1-UTC) & leap-second tables
cargo run --release -p lxephemeris-cli -- data-sync --data-dir ./data

# Fetch NASA JPL planetary kernels (de440s, de440, de441, inpop21a)
cargo run --release -p lxephemeris-cli -- fetch-kernel --kernel de440s --data-dir ./data
```

---

## 22 Upstream Bugs Eliminated by Design

Every behavioral difference between `lxephemeris` and legacy tools is documented and regression-tested in [`docs/SE_DIVERGENCES.md`](docs/SE_DIVERGENCES.md).

<details>
<summary><strong>Click to expand all 22 eliminated bugs across Swiss Ephemeris, PyEphem, and Kerykeion</strong></summary>

<br>

**Swiss Ephemeris (`SWE-01..SWE-11`)**
- **`SWE-01` (Global State Race Conditions)**: `set_ephe_path`, `set_sid_mode`, and `set_topo` mutate process-global C state. In `lxephemeris`, all configuration is immutable or passed per call (`Send + Sync`).
- **`SWE-02` (Star-Anchored Ayanamsa Wobble)**: `True Citra`, `Revati`, and `Pushya` in `libswe` include annual stellar aberration ($\pm 20.5''$ yearly oscillation). `lxephemeris` evaluates star anchors strictly in the geometric frame.
- **`SWE-03` (`swe_house_pos` Returning `0.0`)**: `libswe` returns an invalid `0.0` house position at circumpolar declinations or high latitudes. `lxephemeris` uses a closed-form 3D horizon/prime-vertical projection valid on $[1.0, 13.0)$.
- **`SWE-04` (`Mira` / `Mirach` Star Collision)**: `swe_fixstar2_ut("Mira")` prefix-matches `Mirach` ($>17^\circ$ error). `lxephemeris` uses exact normalized name, Bayer, and Hipparcos ID matching.
- **`SWE-05` (Sidereal Velocity Double-Nutation)**: Fixes frame-rate and nutation-rate inconsistencies in sidereal speeds.
- **`SWE-06` (Silent Ephemeris Fallback)**: Missing `.se1` files silently downgrade accuracy in `libswe`. `lxephemeris` validates SHA-256 manifests explicitly and exposes `engine.is_moshier_mode()`.
- **`SWE-07` (Silent Polar House Flips)**: Replaces silent Porphyry substitution and $180^\circ$ Ascendant flips with explicit `PolarPolicy` (`Strict`, `FallbackToWholeSign`, `FallbackToPorphyry`).
- **`SWE-08` (Zero/Negative Stellar Parallax Explosion)**: Guards Hipparcos-2 parallax $\varpi \le 0$ against division-by-zero and $180^\circ$ sky inversions.
- **`SWE-09` ($0^\circ / 360^\circ$ Velocity Glitch)**: Single-pass analytical Jacobians eliminate finite-difference branch-cut spikes at $0^\circ \ Aries$.
- **`SWE-10` (Besselian Eclipse Aberration Mixing)**: Separates solar annual aberration from lunar shadow-plane coordinates (`0.2–0.6 s` contact improvement).
- **`SWE-11` (`SE_MEAN_APOG` Oscillation)**: Provides true secular IERS 2003 `Mean_Lilith` alongside osculating `True_Lilith` and smooth $C^2$ `Interpolated_Lilith`.

**PyEphem (`EPH-01..EPH-05`)**
- **`EPH-01` (`Sun().hlong` $180^\circ$ Inversion)**: Fixes the heliocentric Earth / geocentric Sun confusion that breaks Chinese *Jieqi* solar terms.
- **`EPH-02` (Topocentric Moon $0.38^\circ$ Obliquity Error)**: Rotates topocentric coordinates using true obliquity of date $\varepsilon(t)$ instead of static J2000 obliquity.
- **`EPH-03` (Static `FixedBody` Stars)**: Applies full 3D Hipparcos-2 proper motion, parallax, and radial velocity in star parans.
- **`EPH-04` (Truncated VSOP87 / ELP2000 Drift)**: Replaces `libastro` series with JPL `DE440s` and `DE440`-calibrated series.
- **`EPH-05` (Naive Datetime & DST Fold Loss)**: `utc_from_local` enforces explicit IANA timezone + PEP 495 `fold` disambiguation.

**Kerykeion (`KER-01..KER-06`)**
- **`KER-01` ($\pm 66^\circ$ Latitude Clamping)**: Eliminates the silent latitude clamp that caused a **$7.85^\circ$ Ascendant error** at Svalbard ($78.22^\circ\text{N}$).
- **`KER-02` ($0.0 \to 0.0001^\circ$ Equator/Greenwich Hack)**: Handles $(0^\circ, 0^\circ)$ exactly with zero coordinate falsification.
- **`KER-03` (Birth-Time Seconds Truncation)**: Preserves full `f64` sub-second precision (preventing up to $15'$ of Ascendant drift).
- **`KER-04` (Cusp Rounding House Drop)**: `house_of_lon` uses a formal `1e-9°` boundary epsilon instead of `round(lon, 4)`.
- **`KER-05` (Mixed Tropical Points in Sidereal Charts)**: Applies sidereal ayanamsa uniformly across all planets, minor bodies, nodes, Liliths, lots, and fixed stars.
- **`KER-06` (Hardcoded $23.4367^\circ$ Obliquity)**: Uses exact IAU 2006/2000A true obliquity and GAST everywhere.

</details>

---

## Verification & Benchmarks

`lxephemeris` is continuously verified against **37,416 golden reference vectors** generated from **NASA JPL Horizons (`DE440` / `SB441-N16`)**, **IAU SOFA**, **USNO**, and reference astronomical catalogs across **145+ Rust tests**, **18 Python test suites**, and **12 Node.js test suites**:

| Verification Suite | Vectors | Coverage | Status |
| :--- | ---: | :--- | :--- |
| **Core Planetary, 68 Asteroids, 52 Stars & 23 Houses** | **10,242** | `1850..2100` full-domain grid across 10 planets, 68 minor bodies, 7 lunar points, 9 Uranians, 52 stars, 23 house systems | **PASS** |
| **Events, Parans, Eclipses, Occultations & 43 Ayanamsas** | **10,540** | Rise/set/transit, 24 Solar Terms (*Jieqi*), HD `-88°` solar arc, stations, lunistices, Brady parans, Moshier (`-500..+2500 CE`), `pheno_ut`, `nod_aps_ut` | **PASS** |
| **Extreme Boundaries & 22 Upstream Bug Immunity Grid** | **10,000** | Arctic/Antarctic houses, $0^\circ/360^\circ$ wrap velocities, retrograde triple passes, circumpolar `house_pos`, star-anchor sidereal nodes, DST folds | **PASS** |
| **Vedic Panchanga/Dasha/Vargas, Aspects, Returns & Lots** | **5,000** | Panchanga, 16 Parashara Vargas (`D1..D60`), Vimshottari Dasha, 24 Planetary Hours, 7 Hermetic Lots, exact aspect windows, planetary returns, 64 HD Gates | **PASS** |
| **First-Principles NASA JPL Horizons & IAU SOFA Oracles** | **1,634** | Direct JPL Horizons `DE440` ICRF (`< 0.003"`), `SB441-N16` 68 minor bodies (`< 0.00001"`), IAU SOFA `pmpx` stars, Holden/Munkasey houses | **PASS** |
| **Total Verified Reference Vectors** | **37,416** | **100% Pass across Rust, Python (`PyO3`), and Node.js (`napi-rs`)** | **100% PASS** |

---

## Documentation

- **[Quickstart & Complete API Reference (`docs/QUICKSTART_AND_API.md`)](docs/QUICKSTART_AND_API.md)** — Examples for every calculation mode, batch API, event solver, Vedic/Traditional/HD module, and CLI command.
- **[Migration Guide from `pyswisseph`, `PyEphem` & `Kerykeion` (`docs/SWE_MIGRATION_GUIDE.md`)](docs/SWE_MIGRATION_GUIDE.md)** — Side-by-side before/after examples for Python and TypeScript.
- **[22 Eliminated Upstream Bugs & Intentional Divergences (`docs/SE_DIVERGENCES.md`)](docs/SE_DIVERGENCES.md)** — Mathematical breakdown of every bug fixed in `lxephemeris`.
- **[Mathematical Model Passports (`docs/MODEL_PASSPORTS.md`)](docs/MODEL_PASSPORTS.md)** — Equations, constants, and peer-reviewed citations (IAU SOFA, IERS 2010, JPL DE440, Meeus, Parashara, Schmidt/Hand).

---

## Licensing & Commercial Use

`lxephemeris` is distributed under a **Dual License** ([`LICENSE.md`](LICENSE.md)):

1. **Free Non-Commercial License ([`PolyForm-Noncommercial-1.0.0`](LICENSE-NONCOMMERCIAL.md))**  
   Free for personal projects, hobbyists, academic research, educational institutions, and non-profit organizations — plus a **30-day evaluation grant** for commercial teams testing `lxephemeris` in non-production environments.

2. **Commercial License (`LicenseRef-Commercial`)**  
   Required for commercial products, paid SaaS/APIs, monetized mobile/web apps, and internal business production deployments.
   - **Get a Commercial License**: Submit a request at **[https://procoders.tech/contacts/](https://procoders.tech/contacts/)** or email **[lxephemeris@procoders.tech](mailto:lxephemeris@procoders.tech)**.
   - **100% Offline Activation (`Ed25519`)**: Commercial customers receive an offline cryptographic license key (`LXEPHEMERIS_LICENSE_KEY` or `LXEPHEMERIS_LICENSE_FILE`) verified locally in microseconds — **zero runtime phone-home, zero network calls, and perpetual fallback on covered engine releases**.

```bash
# Verify your commercial license key via CLI, Python, Node.js, or Rust
export LXEPHEMERIS_LICENSE_KEY="lxeph_live_v1...."
lxephemeris-cli license-verify --require-commercial
```

