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 8c4946b, 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.12, the version in the engine repository when the suite was released. This site's charts use version 0.1.1-rc.10.
@zodiacs/engine 0.1.1-rc.12
| Kind | Pass | Fail | Unsupported | Median / largest residual |
|---|---|---|---|---|
| Apparent positions, ecliptic of date | 47 | 193 | 0 | lon 2.067″ / 18.846″; lat 1.187″ / 19.028″ |
| Positions, all | 47 | 193 | 0 | |
| Ascendant and midheaven | 60 | 0 | 0 | asc 0.037″ / 0.182″; mc 0.043″ / 0.178″ |
| Vertex and east point | 10 | 0 | 0 | vertex 0.083″ / 0.285″; east_point 0.083″ / 0.103″ |
| House cusps, thirteen systems | 80 | 0 | 0 | cusps 0.051″ / 0.489″ |
| Houses and angles, all | 150 | 0 | 0 | |
| Time zone offsets | 20 | 20 | 5 | — |
| Local mean time | 0 | 0 | 5 | — |
| TT − UTC | 0 | 9 | 1 | tt_minus_utc_s 0.388 s / 0.634 s |
| ΔT (TT − UT1) | 15 | 0 | 0 | delta_t_s 0.00410 s / 0.0689 s |
| Calendar date to day number | 0 | 0 | 25 | — |
| Day number to calendar date | 0 | 0 | 10 | — |
| Time and calendars, all | 35 | 29 | 46 |
- Positions (L1). The engine computes positions with astronomy-engine 2.1.19's series. Against DE441 they differ by a median of 2.07″ 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.9″. A precise backend is planned to close this gap.
- Time zones (L3). The engine reads the host's
Intltime zone data, which does not carry tzdb'sbackzonehistory. All 20 failures are the vectors taggedbackzone-history, and on each the engine returns what tzdb's default build gives.- A repeated local time is resolved to its earlier instant only, and the engine has no public way to give the later one. Those vectors are unsupported.
- TT − UTC (L3). The engine reads a UTC instant as UT1, so its TT − UTC is its ΔT. Each residual (engine minus expected) is −(UT1 − UTC) for that date, up to 0.63 s here. A leap-second table is planned. A leap second itself cannot be expressed as a JavaScript date, so that case is unsupported.
- Unsupported (L3). Release 0.1.1-rc.12 has no public function for local mean time from a longitude or for calendar conversion. Both are planned for the next engine release.
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.











