Ephemeris5 MIN READ05 / 31

Swiss adapter module implementation

The implemented slice consists of two reusable TypeScript ESM workspace packages: adapter-contract and swiss-ephemeris-adapter. The former HTTP host, routes, HTTP status mapping, startup script, and HTTP tests have been removed. Consumer applications own transport and lifecycle. The broader binder HLD still contains planned orchestration, caching, normalisation and semantics.

Shared contract

@astrology/adapter-contract has no runtime dependencies. It owns the EphemerisAdapter interface, canonical vocabulary and DTOs, PositionQuery, validateRequest, parseInstant, AdapterError, and ERROR_CODES. Swiss depends on it through workspace:*; its public entry point exports only SwissAdapter and its options. There is no copied contract inside Swiss.

Method Result
capabilities() Live features, zodiacs, bodies, house systems, ayanamsas, installed coverage and versions
positions(request) { data: { positions }, declaration }
houses(request) { data: { cusps, ascendant, midheaven, ... }, declaration }

Capabilities describe native eligibility. The future NASA adapter can declare only tropical positions with empty house-system/ayanamsa arrays. Unsupported operations or zodiacs reject with UNSUPPORTED_FEATURE. Binding versions, native flags, and tidal acceleration accept null when not applicable. The contract does not require a NASA implementation to fabricate Swiss metadata. A compile-only consumer fixture checks this shape; it is not a NASA integration.

Errors have stable codes and messages, without a status property. Consumers decide whether failures become HTTP responses, UI messages, or CLI output.

Request and result behavior

  • Instants are integer epoch milliseconds or strict offset-bearing ISO strings with seconds and at most milliseconds. Bare local times, invalid dates, leap-second strings and unknown fields fail validation.
  • Zodiac is explicit. Sidereal requires Lahiri, Raman, Krishnamurti or Fagan-Bradley; tropical refuses an ayanamsa.
  • Observer coordinates are WGS84 degrees, east-positive longitude; elevation defaults to zero metres and is limited to −500…100000 metres. Presence selects topocentric positions. Houses require latitude/longitude and do not use elevation.
  • Bodies are one to twelve distinct canonical lowercase ids, Sun through Pluto plus Rahu/Ketu. Node requests require an explicit mean/true convention.
  • Speeds are optional and null when absent. Units are degrees, AU, degrees/day and AU/day. Body order is preserved.
  • Ketu is the selected node’s antipode: longitude +180° wrapped, latitude and latitude speed negated, distance and remaining speeds retained.
  • House systems are Placidus, Whole Sign, Equal, Sripati, Koch and Campanus. Twelve cusps use array index zero for house one. Eight angles are named explicitly; ARMC remains equatorial.
  • Shared validation returns an owned snapshot. Fluent transformations return new queries and use identical validation at build time.

Swiss mapping and evidence

Concern Implementation and evidence
Binding Exact sweph@2.10.3-8; engine reports 2.10.03
Time utc_to_jd returns TT/UT1; calc takes TT, houses_ex2 takes UT1; deltat_ex reports model seconds
Consistent historical model set_tid_acc(-25.936) pins official DE441 tidal acceleration before UTC conversion. The 1900 CLI comparison exposed the default-tide mismatch otherwise present inside utc_to_jd.
Positions SEFLG_SWIEPH, optional speed/sidereal/topocentric flags; canonical ids map to named native constants
Observer and zodiac set_topo, set_sid_mode, get_ayanamsa_ex; sidereal applied once by the provider
Houses houses_ex2 P/W/E/S/K/C, rejecting every nonzero status including polar fallback cusps
Native admission Reject fallback source bits, missing requested options, unexpected frames, and invalid/nonfinite geometry
Process isolation One disposable child_process.fork per operation, no shared native state with the consumer
Resource budget Default four concurrent calls per instance, 5000 ms including startup; immediate overload refusal, no retry; timeout kills the process and settlement waits for exit

The engine/files are loaded only in the internal child. Import and construction have no I/O. Options are ephemerisDirectory, timeoutMs, and maxConcurrency; there is no host, port, server startup or listener. Applications may explicitly call capabilities during their own startup.

Pinned data and reproducibility

Official sepl_18.se1 and semo_18.se1 are pinned to source revision c69c14adb7a0f94829586ffd92cd422aacb21e86, with SHA-256 identities in the manifest. Setup downloads them into the Swiss package’s ignored ephemeris/ directory and verifies bytes.

Every operation verifies both files before native loading. J2000 Sun/Moon probes supply native file metadata; both must report DE441 and the verified paths. The advertised common TT coverage is 2378497.5–2597650.3591467496, approximately 1800–2400, reserving one day on either edge. Requested dates outside it fail before request calculation. Houses use the same service range.

The worker pins SE_EPHE_PATH, which native code prioritizes over its path argument. Unpinned seleapsec.txt, swe_deltat.txt, or sedeltat.txt overrides are refused so identical ephemeris hashes cannot hide different time models. No runtime download or Moshier fallback occurs.

The pinned engine treats UTC as UT1 before 1972 and can do so far into the future when its leap-second table cannot establish UTC. The file range does not imply modern UTC precision over that range. Precision remains null rather than an unverified universal accuracy claim.

Verification

pnpm test:adapters builds in dependency order and runs standalone contract tests plus native Swiss and workspace consumer tests. Contract tests need no native addon, files or network. Swiss tests exercise real calculations, shared errors across the IPC boundary, declared capabilities, coverage, file/time-model refusal, concurrent observers/ayanamsas, polar houses, overload, and process deadlines. No server or HTTP test remains.

The checked-in numerical references come from an independently compiled official swetest executable using the same verified files. The optional reference script fetches official Swiss 2.10.03 C source at revision 175e1fcb3108bcd5c0d146c803f51dcf23508012 and compiles it with cc. It reproduces tropical J2000, 1990 Lahiri Mumbai topocentric, 1900 tropical, four ayanamsas, all six house systems and Lahiri houses. -tidacc-25.936 matches the adapter’s explicit model. Fixture tolerances allow printed precision and platform floating-point differences.

This verifies the workspace/native boundary against the official C CLI. It does not establish independent NASA agreement, per-body accuracy or production latency. NASA runtime integration, normalisation, routing, caching, semantics, provenance storage, rise/set, timeseries and cancellation tokens remain later work. The professional/AGPL decision remains a distribution/deployment requirement.