Rust Backend Contracts¶
This document defines boundary and behavior contracts for migrated APIs in adam_core.
Runtime Availability Contract¶
The compiled
adam_core._rust_nativeextension is mandatory for this migration branch.Importing
adam_core._rust.apiraisesImportErrorimmediately if the native extension is missing or if the installed extension lacks a required native symbol.Python wrappers around native kernels return concrete results or propagate native exceptions. They do not return
Noneto signal backend unavailability.CI and local validation scripts rely on the mandatory import contract; they no longer need
ADAM_CORE_REQUIRE_RUST_BACKEND.
Boundary Selection Rule¶
Use a NumPy boundary for dense numerical kernels where contiguous array inputs are natural.
Use an Arrow boundary for table-centric APIs that require schema/null semantics.
For high-level entrypoints, use a single Python->Rust boundary crossing per call and execute the full internal pipeline in Rust before returning results.
Complete Surface Status¶
The authoritative latest-main inventory is
migration/public_surface/manifest.json (595 symbols / 67 constants at
upstream 9b756803ab3afbe11e33df9e57d30a28e7976b92). The
selected parity registry is a benchmark set, not the public-surface count.
Every adam-core-owned non-plotting operation is either Rust-backed, a thin
single-crossing compatibility veneer, or an explicitly documented provider
boundary. The API examples below describe boundary contracts; they are not an
exhaustive migration-status list.
Migration Surface Scope Rule¶
Default migration target is the highest-level atomic function entrypoint used by
adam-corecallers or downstream users.Internal-only helper functions behind that entrypoint are not required migration targets by default.
Helper-level Rust replacements should be added only when they are needed for measurable performance/correctness gains and do not fragment the public migration surface.
High-level orchestrators (for example
transform_coordinates) are only considered migrated when orchestration + sub-transform execution happen end-to-end in Rust without Python<->Rust ping-pong.
Current Migrated APIs¶
coordinates.cartesian_to_spherical- Boundary: NumPyfloat64array with shape(N, 6). - Rust entrypoint:adam_core._rust_native.cartesian_to_spherical_numpy. - Error behavior: raisesValueErroron shape mismatch.coordinates.cartesian_to_geodetic- Boundary: NumPyfloat64array with shape(N, 6)and scalara/fparameters. - Rust entrypoint:adam_core._rust_native.cartesian_to_geodetic_numpy. - Error behavior: raisesValueErroron shape mismatch.coordinates.cartesian_to_keplerian- Boundary: NumPyfloat64arrays with shape(N, 6)forcoordsand(N,)fort0/mu. - Rust entrypoint:adam_core._rust_native.cartesian_to_keplerian_numpy. - Error behavior: raisesValueErroron shape/length mismatch.coordinates.keplerian.to_cartesian- Boundary: NumPyfloat64arrays with shape(N, 6)forcoordsand(N,)formu. - Rust entrypoint:adam_core._rust_native.keplerian_to_cartesian_numpy. - Error behavior: raisesValueErroron shape/length mismatch.coordinates.transform_coordinates(Rust high-level dispatcher with explicit provider boundaries) - Boundary: Python coordinate tables, with a single internal crossing intoadam_core._rust_native.transform_coordinates_numpyfor supported paths. - Current Rust-supported single-crossing paths:cartesian|spherical|keplerian -> cartesian|spherical|geodetic|keplerianwith unchanged origin and NaN covariances; frame support includes unchanged frame andequatorial <-> ecliptic. - Unsupported paths remain whole-call Python execution (no mixed Python<->Rust ping-pong within one call).coordinates.spherical.from_cartesian- Boundary: Arrow table with columnsx, y, z, vx, vy, vz(float64-compatible). - Rust entrypoint:adam_core._rust.api.cartesian_to_spherical_arrow->adam_core._rust_native.cartesian_to_spherical_numpy. - Null behavior: Arrow nulls are converted toNaNin the numeric kernel path. - Error behavior: raisesValueErrorwhen required columns are missing.coordinates.spherical.to_cartesian- Boundary: NumPyfloat64array with shape(N, 6). - Rust entrypoint:adam_core._rust_native.spherical_to_cartesian_numpy. - Error behavior: raisesValueErroron shape mismatch.coordinates.residuals.calculate_chi2- Boundary: NumPyfloat64arrays with shapes(N, D)forresiduals and
(N, D, D)for covariances.Rust entrypoint:
adam_core._rust_native.calculate_chi2_numpy.Contract: covariance matrices must be symmetric positive definite; the Rust kernel solves with Cholesky rather than forming an explicit inverse.
NaN behavior: NaN diagonal entries raise
ValueError; NaN off-diagonal entries are treated as zero with a PythonUserWarningfor legacy compatibility.Error behavior: raises
ValueErroron shape mismatch or non-positive-definite covariance input.
dynamics.calc_mean_motion- Boundary: NumPyfloat64arrays with shape(N,)foraandmu. - Rust entrypoint:adam_core._rust_native.calc_mean_motion_numpy. - Error behavior: raisesValueErrorwhen lengths differ.orbit_determination.calcGibbs- Boundary: NumPyfloat64arrays with shape(3,)forr1,r2, andr3. - Rust entrypoint:adam_core._rust_native.calc_gibbs_numpy. - Error behavior: raisesValueErroron shape mismatch.orbit_determination.calcHerrickGibbs- Boundary: NumPyfloat64arrays with shape(3,)forr1,r2, andr3;t1,t2,t3as scalar float inputs. - Rust entrypoint:adam_core._rust_native.calc_herrick_gibbs_numpy. - Error behavior: raisesValueErroron shape mismatch.orbit_determination.calcGauss- Boundary: NumPyfloat64arrays with shape(3,)forr1,r2, andr3;t1,t2,t3as scalar float inputs. - Rust entrypoint:adam_core._rust_native.calc_gauss_numpy. - Error behavior: raisesValueErroron shape mismatch.orbit_determination.gaussIOD- Boundary: NumPy arrays forcoords(3, 2),observation_times(3,), andcoords_obs(3, 3). - Rust entrypoint:adam_core._rust_native.gauss_iod_orbits_numpy(candidate-generation kernel from precomputed roots). - Backend default: legacy path, with Rust path held indualmode pending +20% p50/p95 perf gate. - Error behavior: velocity-method validation raisesValueErrorfor unsupported solver names.
Fallback and Waivers¶
If a Rust-backed API cannot satisfy parity/performance criteria, keep that API off the migrated production surface or record an explicit waiver. Do not add rustless production fallbacks. Optional Astropy/UT1, Astroquery monkeypatch, Healpy, plotting, external propagator, and live provider calls are explicit compatibility/provider boundaries rather than default backends.
Waivers are tracked in
migration/waivers.yamlwith owner and review date.
Status Registry¶
Single source of truth for migration state:
adam_core._rust.status(API_MIGRATIONS).API_MIGRATION_STATUSis a compatibility projection of the same data used by runtime dispatch.Migration governance scripts (
migration/scripts/*) import from this module; there is no separate YAML registry.
Validation Contract¶
The standard Python test suite command
pytest --benchmark-skip -m 'not profile'must run in a Rust-enabled environment for migration validation.Release candidates additionally run every profile-marked scientific fixture and the opt-in live external-service integration gates after wheel acceptance.
Validation runs fail during import if the Rust extension is unavailable.
High-level migrated APIs must include a contract test that enforces single-crossing execution (one Python->Rust entry and one Rust->Python return).
Engineering Requirements Contract¶
This migration is bound to
/Users/aleck/Code/AGENTS.mdas a normative engineering policy.Control flow must prioritize readability: guard clauses, early returns, and decomposition of large functions.
Prefer functions over classes unless using classes is clearly less awkward for the local design.
Reuse existing functionality before adding new entrypoints; avoid duplicate abstractions.
Do not add fallback behavior unless explicitly requested; fail loudly when contracts are not met.
Prefer vectorized and batched operations in Python-facing numerical paths.
Keep scripts minimal: use inline terminal checks for quick validation and avoid leaving throwaway top-level scripts.
Require Python type hints in migration code, with strong concrete types when feasible.