Check an engine against independent references.
The suite is 500 test vectors for the numbers an astrology program computes: positions, angles and house cusps, time zone offsets, time scales and calendar dates. Each vector names its arbiter, the independent source that decides the expected value, and a tolerance that was fixed before any engine was run against it. None uses Swiss Ephemeris as its arbiter; Swiss Ephemeris is measured like any other engine.
Any engine can be run against it through a small adapter that reads and writes one JSON object per line. The vectors, the harness and the adapters are dedicated to the public domain under CC0 1.0. Version 0.1.0 is at zodiacs-org/engine, commit 782b496, with its format and protocol and full results.
What it checks
| Level | Kind | Vectors | Tolerance |
|---|---|---|---|
| L1 | Apparent positions, ecliptic of date | 240 | lon ±1″ (on the circle); lat ±1″ |
| L2 | Ascendant and midheaven | 60 | asc ±1″ (on the circle); mc ±1″ (on the circle) |
| L2 | Vertex and east point | 10 | vertex ±1″ (on the circle); east_point ±1″ (on the circle) |
| L2 | House cusps, thirteen systems | 80 | cusps each ±1″ (on the circle), or status exact |
| L3 | Time zone offsets | 45 | status exact; utc_offset_s exact, or status exact, or status exact; utc_offsets_s exact |
| L3 | Local mean time | 5 | utc_offset_s ±0.001 s |
| L3 | TT − UTC | 10 | tt_minus_utc_s ±0.0005 s |
| L3 | ΔT (TT − UT1) | 15 | delta_t_s ±0.1 s |
| L3 | Calendar date to day number | 25 | jdn exact |
| L3 | Day number to calendar date | 10 | year exact; month exact; day exact |
The arbiters
- Positions. NASA JPL Horizons (DE441) apparent geocentric ecliptic positions, carried into the IAU 2006/2000A true ecliptic and equinox of date.
- Houses and angles. ERFA sidereal time and obliquity; spherical geometry of the angles.
- Houses and angles. Ecliptic divisions: equal, whole-sign, Vehlow, equal-MC, Porphyry.
- Houses and angles. Fixed house circles: Regiomontanus, Campanus, meridian, Morinus.
- Houses and angles. Semi-arc and pole systems: Placidus, Koch, Alcabitius, topocentric.
- Houses and angles. Cusps that do not exist: the construction has no solution in zodiacal order.
- Time and calendars. IANA tzdb 2025c with backzone, compiled by zic 2025c.
- Time and calendars. Local mean time from longitude.
- Time and calendars. IERS leap-second table (leap-seconds.list, tzdata 2025c).
- Time and calendars. IERS UT1 - UTC (finals2000A, observed rows) with the leap-second table.
- Time and calendars. Julian and Gregorian calendar arithmetic, two published algorithms.
Each vector file records how its arbiter was applied, the digest of every input, and the arbiter's own uncertainty. The generators rebuild every file byte for byte, and the engine repository's continuous integration checks that they still do.
Results
A vector an engine has no function for is counted as unsupported, not as a failure. Residuals are the median and largest difference from the expected value.
The @zodiacs/engine results are for version 0.1.1-rc.17, the version this site's charts use.
@zodiacs/engine 0.1.1-rc.17
| Kind | Pass | Fail | Unsupported | Median / largest residual |
|---|---|---|---|---|
| Apparent positions, ecliptic of date | 48 | 192 | 0 | lon 2.083″ / 18.774″; lat 1.187″ / 19.028″ |
| Positions, all | 48 | 192 | 0 | |
| Ascendant and midheaven | 60 | 0 | 0 | asc 0.003″ / 0.019″; mc 0.004″ / 0.008″ |
| Vertex and east point | 10 | 0 | 0 | vertex 0.003″ / 0.013″; east_point 0.003″ / 0.007″ |
| House cusps, thirteen systems | 80 | 0 | 0 | cusps 0.004″ / 0.071″ |
| Houses and angles, all | 150 | 0 | 0 | |
| Time zone offsets | 45 | 0 | 0 | — |
| Local mean time | 0 | 0 | 5 | — |
| TT − UTC | 9 | 0 | 1 | tt_minus_utc_s 0.00 s / 2.03e-8 s |
| ΔT (TT − UT1) | 15 | 0 | 0 | delta_t_s 0.000132 s / 0.000505 s |
| Calendar date to day number | 0 | 0 | 25 | — |
| Day number to calendar date | 0 | 0 | 10 | — |
| Time and calendars, all | 69 | 0 | 41 |
- Positions (L1). The engine computes positions with astronomy-engine 2.1.19's series. Against DE441 they differ by a median of 2.08″ in longitude. The largest differences are 18.8″ in longitude (Neptune) and 19.0″ in latitude (Saturn); the Sun is within 1.64″ and the Moon within 3.75″. Since the engine took the full IAU 2000B nutation in place of astronomy-engine's five terms, L1-POS-0041 (the Sun in 1908, 1.076″ off in longitude before) passes. A precise backend is planned to close this gap.
- Time zones (L3). Before 1970 the engine reads the tzdb 2025c history with
backzonethat it ships, loaded withprepareLocalTime, so the 20 vectors taggedbackzone-historypass; from 1970 it reads the host'sIntldata. A repeated local time resolves to its earlier instant, and the transition the engine reports gives the offsets of both readings, so the five folds are answered. All 45 pass. - TT − UTC and ΔT (L3). From 1972 to 2027-10-02 the engine takes TAI − UTC from the IERS leap-second list updated 2026-07-06, and UT1 − UTC from IERS: the EOP 20 C04 series in 1972 and
finals2000A.allof 2026-09-24 from 1973-01-02. The adapter reports TT − UTC as a chart's ΔT (TT − UT1) plus its UT1 − UTC. A leap second itself cannot be expressed as a JavaScript date, so that case is unsupported. - Unsupported (L3). Release 0.1.1-rc.17 converts dates between the Julian and Gregorian calendars and reads a birthplace's local mean time inside a zone's local mean time era, but has no public function for a Julian Day Number or for local mean time from a longitude alone, so the 35 calendar vectors and the 5 local mean time vectors are unsupported.
Swiss Ephemeris 2.10.03
| Kind | Pass | Fail | Unsupported | Median / largest residual |
|---|---|---|---|---|
| Apparent positions, ecliptic of date | 240 | 0 | 0 | lon 0.001″ / 0.005″; lat 0.000″ / 0.002″ |
| Positions, all | 240 | 0 | 0 | |
| Ascendant and midheaven | 41 | 19 | 0 | asc 0.002″ / 5.862″; mc 0.001″ / 2.028″ |
| Vertex and east point | 6 | 4 | 0 | vertex 0.024″ / 2.952″; east_point 0.026″ / 2.040″ |
| House cusps, thirteen systems | 56 | 24 | 0 | cusps 0.001″ / 15.652″ |
| Houses and angles, all | 103 | 47 | 0 | |
| Time zone offsets | 0 | 0 | 45 | — |
| Local mean time | 0 | 0 | 5 | — |
| TT − UTC | 10 | 0 | 0 | tt_minus_utc_s 0.00000729 s / 0.0000196 s |
| ΔT (TT − UT1) | 15 | 0 | 0 | delta_t_s 0.00166 s / 0.0513 s |
| Calendar date to day number | 25 | 0 | 0 | — |
| Day number to calendar date | 10 | 0 | 0 | — |
| Time and calendars, all | 60 | 0 | 50 |
- Houses and angles (L2). Swiss Ephemeris 2.10.03 uses the IAU 2006/2000A sidereal time from 1850 to 2050, where its sidereal time agrees with the arbiter's to 0.001″ and its angles and cusps to within 0.007″. Outside that span it switches to its own long-term model. That model's sidereal time is 1.9″ from the IAU value just after 2050, falling to 0.7″ by 2199 (both measured with Swiss's own ΔT); the angles and cusps differ by up to 15.7″ here.
- All 47 failures are dated after 2050.
- The vectors before 1850 all pass.
- Given the arbiter's own sidereal time and obliquity, its house geometry agrees to within 0.0011″ in every system (see
arbiters/l2/README.md).
- Flags. Every position request returned
SEFLG_SWIEPH: Swiss read its.se1files rather than falling back to its Moshier theory. - Unsupported. Swiss Ephemeris has no time zone database and no function for local mean time from a longitude.
Run it yourself
With Node.js 20 or later, from a clone of the engine repository:
npm ci && npm run build
node conformance/harness/validate.mjs --expect-total 500
node conformance/harness/run.mjs \
--adapter "node conformance/adapters/zodiacs-engine.mjs" \
--out my-results.jsonTo measure another engine, write an adapter that follows the protocol: one JSON request per line in, one JSON response per line out, and unsupportedfor anything the engine cannot answer.
Report an error in the suite
If you believe a vector's expected value, tolerance or arbiter is wrong, open a conformance discrepancy with your evidence. Every report gets a public disposition in the log. A vector is never changed in place: a wrong one is withdrawn and replaced under a new id.











