# Calculation Accuracy

## TL;DR

AstroWay API uses **Swiss Ephemeris** (the official C code by Astrodienst,
creators of astro.com) — the same engine professional astrologers have trusted
for 30+ years inside **Solar Fire ($495), Kepler ($995), Astro Gold ($29.99/mo),
and Janus**. We compile it to WebAssembly and expose it as a REST API, without
the middleman markup. Every core calculation endpoint is covered by regression
snapshot tests; engine precision is verified through **triangulation** against
three independent sources, plus **NASA 5-Millennium Eclipse Catalog**:

- **Planet positions**: `< 0.1 arcsec` vs official swetest CGI at Astrodienst
- **Placidus house cusps**: `0.000"` exact match
- **Eclipses**: `< 1 minute` vs NASA 5-Millennium Eclipse Catalog
- **ACG lines**: `< 1.5 km` at the equator vs swetest
- **Sunrise/sunset**: `< 10 seconds` vs timeanddate.com
- **Moon VOC, ingresses, planet conjunctions**: sub-second precision

## Engine

| Component | Value |
|-----------|-------|
| Library | Swiss Ephemeris C code (aloistr/swisseph) |
| Version | upstream Astrodienst C code |
| Bindings | swisseph-wasm (WebAssembly, Node.js) |
| Ephemeris | DE431 JPL ephemeris (via .se1 files) |
| Fallback | Moshier analytical (for dates outside 1800-2399) |
| Code sharing | Shared `@/core` with app.astroway.info — one engine, two transports |

## Methodology

Accuracy is verified through **triangulation** — comparison against three
independent sources:

### 1. swetest CGI (authoritative)

The official Swiss Ephemeris reference implementation hosted by Astrodienst —
the team behind **Astro.com**, which serves millions of astrologers worldwide.
The most authoritative public reference. Our engine is **identical**
(0.00–0.07 arcsec drift).

### 2. Kerykeion (Python)

An independent Python library using `pyswisseph` bindings instead of our
WASM. Confirms that our WASM layer does not distort the data.

### 3. Prokerala API

A remote Swiss Ephemeris API (sidereal Lahiri). Systemic drift of 8–17 arcsec
is caused by different Lahiri ayanamsa formula versions — **not** by engine
accuracy.

## Triangulation results

| Chart | vs swetest (Astrodienst) | vs Kerykeion (Python) | vs Prokerala API |
|-------|---------------------------|------------------------|-------------------|
| Monroe 1926 | **0.00"** | 0.19" | 16.95" (systemic) |
| Diana 1961 | **0.00"** | 0.69" | 8.18" (systemic) |
| Einstein 1879 | 0.07" | Kerykeion LMT artifact | 14.96" (systemic) |

## Endpoint-level regression suite

Each of the core calculation endpoints is covered by frozen snapshot tests
on 3 reference charts (Monroe / Diana / Einstein) = **{siteMeta.snapshotCount} snapshots**.

The snapshot suite catches:

- **Input-mapping bugs** — wrong planet id, UT, house system
- **Post-processing** — rounding, unit conversion, sign loss
- **Defaults divergence** — mean vs true node, geocentric vs topocentric
- **Schema drift** — validation let through a wrong shape
- **Stale deploy** — prod dist out of sync with code

Default tolerance: `5e-5°` (≈0.18 arcsec) for all numeric fields.

## Detailed benchmarks

### Planet positions (tropical, vs swetest)

| Chart | Date | Max drift |
|-------|------|-----------|
| Marilyn Monroe | 1926-06-01 | **0.00"** |
| Princess Diana | 1961-07-01 | **0.00"** |
| Albert Einstein | 1879-03-14 | 0.07" |

### House cusps Placidus (vs swetest)

| Chart | ASC drift | MC drift | Max cusp drift |
|-------|-----------|----------|----------------|
| Monroe | 0.000" | 0.000" | 0.000" |
| Diana | 0.000" | 0.000" | 0.000" |

### Eclipses (vs NASA 5-Millennium Catalog)

| Event | NASA max | Ours max | Drift |
|-------|----------|----------|-------|
| 2025-03-14 Lunar Total | 06:58 UT | 06:58 UT | 0.8 min |
| 2025-03-29 Solar Partial | 10:47 UT | 10:47 UT | 0.5 min |
| 2025-09-07 Lunar Total | 18:11 UT | 18:11 UT | 0.8 min |
| 2025-09-21 Solar Partial | 19:41 UT | 19:42 UT | 1.0 min |

### Astrocartography (vs swetest RA formula)

All MC/IC/ASC/DSC lines use the correct `longitude = RA - GMST` formula
(Kenneth Bowser standard). Drift from authoritative: **< 1.5 km** at the
equator for all planets.

### Sunrise/Sunset (vs timeanddate.com)

| Location | Date | Parameter | Drift |
|----------|------|-----------|-------|
| London | 2026-04-15 | Sunrise | 0.6 sec |
| London | 2026-04-15 | Sunset | 9 sec |

**Polar locations** (|lat| > 66.5°) automatically return `polarState` +
a warning that regular planetary hours are undefined.

### Aspect orbs

AstroWay uses **variable per-planet orbs** (MIN-of-two-planets rule), as in
ZET9 and astro.com. Default orbs (natal chart):

| Aspect | Sun | Moon | Inner | Jupiter | Outer |
|--------|-----|------|-------|---------|-------|
| Conjunction | 12° | 10° | 5° | 8° | 5° |
| Sextile | 6.5° | 6° | 5° | 5° | 5° |
| Square | 10° | 8° | 5° | 7° | 5° |
| Trine | 12° | 8° | 5° | 5° | 5° |
| Opposition | 12° | 10° | 5° | 8° | 5° |

Minor aspects (36°, 40°, 45°, 72°, 108°, 135°, 144°) are **off by default**.
Enable explicitly via `ALL_ASPECTS`.

## Polar latitudes

For |lat| > 66.5° the Placidus/Koch/Regiomontanus systems are mathematically
undefined. In that case Swiss Ephemeris automatically falls back to Porphyry,
and our API adds a warning:

```json
{
  "system": "P",
  "warning": "Placidus system is undefined for lat=68.96° (> 66.5°). Swiss Ephemeris fell back to Porphyry..."
}
```

## Continuous verification

Regression is checked **on every PR** through CI:

- `api-calc/tests/endpoints/` — {siteMeta.snapshotCount} snapshots against reference charts (Monroe / Diana / Einstein) + synastry / composite / davison
- `.github/workflows/api-accuracy.yml` — auto-run on PR
- Triangulation against swetest CGI + Kerykeion — weekly
- Upstream Swiss Ephemeris monitoring via Dependabot

## Known limitations

- **Extreme dates** (before 1800 and after 2399): uses Moshier analytical,
  precision ~0.1" (vs < 0.01" for SWIEPH with DE431 files)
- **True Lilith (id=13) vs Mean Lilith (id=12)**: up to 12° difference — the
  default is Mean Lilith (stable behavior), True Lilith is available via
  `planetIds: [13]`
- **Topocentric vs geocentric**: geocentric by default

## References

- Swiss Ephemeris: https://www.astro.com/swisseph/
- swetest CGI: https://www.astro.com/swisseph/swetest.htm
- NASA Eclipse Catalog: https://eclipse.gsfc.nasa.gov/
- Kerykeion: https://github.com/g-battaglia/kerykeion
- Astrodienst: https://www.astro.com/

## Contact

Accuracy issues: report via support@astroway.info with chart data + expected
reference (from astro.com or similar authoritative source).
