astrox-python 1.1.0__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. {astrox_python-1.1.0 → astrox_python-1.2.0}/.gitignore +3 -0
  2. {astrox_python-1.1.0 → astrox_python-1.2.0}/PKG-INFO +1 -1
  3. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/celestial.py +8 -1
  4. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/celestial/README.md +12 -9
  5. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/celestial/README.md +12 -9
  6. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/test-principles.md +2 -0
  7. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/celestial.md +19 -14
  8. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/libration.md +1 -1
  9. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/11_celestial/celestial_queries.py +2 -2
  10. {astrox_python-1.1.0 → astrox_python-1.2.0}/pyproject.toml +2 -2
  11. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/celestial/test_celestial.py +20 -0
  12. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/README.md +15 -0
  13. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/celestial/test_cb_axes_rotation_invariants.py +54 -2
  14. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/celestial/test_ephemeris_skyfield.py +59 -6
  15. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/celestial/test_lambert_transfer_lamberthub.py +119 -11
  16. astrox_python-1.2.0/tests/validation/cross_validation/celestial/test_mpc_target_elements.py +307 -0
  17. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/libration/test_e2m2e_qualification.py +2 -14
  18. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/astrogator/test_run_mcs.py +4 -1
  19. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/celestial/celestial.snap.json +2 -2
  20. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/celestial/test_celestial.py +2 -2
  21. {astrox_python-1.1.0 → astrox_python-1.2.0}/uv.lock +7 -7
  22. astrox_python-1.1.0/tests/validation/cross_validation/celestial/test_mpc_target_elements.py +0 -170
  23. {astrox_python-1.1.0 → astrox_python-1.2.0}/LICENSE +0 -0
  24. {astrox_python-1.1.0 → astrox_python-1.2.0}/README.md +0 -0
  25. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/__init__.py +0 -0
  26. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/_http.py +0 -0
  27. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/access.py +0 -0
  28. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/astrogator/__init__.py +0 -0
  29. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/astrogator/_api.py +0 -0
  30. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/astrogator/_models.py +0 -0
  31. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/astrogator/_results.py +0 -0
  32. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/cat.py +0 -0
  33. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/catalog.py +0 -0
  34. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/components/__init__.py +0 -0
  35. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/components/_axes.py +0 -0
  36. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/components/_common.py +0 -0
  37. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/components/_constraints.py +0 -0
  38. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/components/_objects.py +0 -0
  39. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/components/_positions.py +0 -0
  40. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/components/_rotations.py +0 -0
  41. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/components/_sensors.py +0 -0
  42. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/components/_vgt.py +0 -0
  43. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/conjunction.py +0 -0
  44. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/coverage/__init__.py +0 -0
  45. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/coverage/_core.py +0 -0
  46. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/coverage/_fom.py +0 -0
  47. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/coverage/coverage_time.py +0 -0
  48. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/coverage/number_of_assets.py +0 -0
  49. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/coverage/response_time.py +0 -0
  50. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/coverage/revisit_time.py +0 -0
  51. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/coverage/simple_coverage.py +0 -0
  52. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/exceptions.py +0 -0
  53. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/libration.py +0 -0
  54. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/lighting.py +0 -0
  55. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/orbits.py +0 -0
  56. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/propagator.py +0 -0
  57. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/rocket.py +0 -0
  58. {astrox_python-1.1.0 → astrox_python-1.2.0}/astrox/terrain.py +0 -0
  59. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/CONTRIBUTING.md +0 -0
  60. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/README.md +0 -0
  61. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/automated-workflows.md +0 -0
  62. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/docs-principles.md +0 -0
  63. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/getting_started.md +0 -0
  64. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/how_to/README.md +0 -0
  65. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/how_to/build_an_hpop_configuration.md +0 -0
  66. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/how_to/compute_access_intervals.md +0 -0
  67. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/how_to/compute_lambert_transfer.md +0 -0
  68. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/how_to/compute_lighting_conditions.md +0 -0
  69. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/how_to/convert_between_orbit_representations.md +0 -0
  70. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/how_to/generate_a_crtbp_periodic_orbit.md +0 -0
  71. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/how_to/propagate_an_orbit.md +0 -0
  72. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/how_to/run_an_astrogator_mcs.md +0 -0
  73. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/how_to/screen_close_approaches.md +0 -0
  74. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/README.md +0 -0
  75. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/getting_started.md +0 -0
  76. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/how_to/README.md +0 -0
  77. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/how_to/build_an_hpop_configuration.md +0 -0
  78. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/how_to/compute_access_intervals.md +0 -0
  79. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/how_to/compute_lambert_transfer.md +0 -0
  80. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/how_to/compute_lighting_conditions.md +0 -0
  81. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/how_to/convert_between_orbit_representations.md +0 -0
  82. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/how_to/generate_a_crtbp_periodic_orbit.md +0 -0
  83. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/how_to/propagate_an_orbit.md +0 -0
  84. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/how_to/run_an_astrogator_mcs.md +0 -0
  85. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/how_to/screen_close_approaches.md +0 -0
  86. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/README.md +0 -0
  87. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/access/README.md +0 -0
  88. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/astrogator/README.md +0 -0
  89. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/cat/README.md +0 -0
  90. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/catalog/README.md +0 -0
  91. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/components/README.md +0 -0
  92. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/conjunction/README.md +0 -0
  93. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/coverage/README.md +0 -0
  94. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/libration/README.md +0 -0
  95. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/lighting/README.md +0 -0
  96. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/orbits/README.md +0 -0
  97. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/propagator/README.md +0 -0
  98. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/rocket/README.md +0 -0
  99. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/i18n/en/manual/terrain/README.md +0 -0
  100. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/README.md +0 -0
  101. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/access/README.md +0 -0
  102. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/astrogator/README.md +0 -0
  103. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/cat/README.md +0 -0
  104. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/catalog/README.md +0 -0
  105. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/components/README.md +0 -0
  106. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/conjunction/README.md +0 -0
  107. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/coverage/README.md +0 -0
  108. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/libration/README.md +0 -0
  109. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/lighting/README.md +0 -0
  110. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/orbits/README.md +0 -0
  111. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/propagator/README.md +0 -0
  112. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/rocket/README.md +0 -0
  113. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/manual/terrain/README.md +0 -0
  114. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/sdk-principles.md +0 -0
  115. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/README.md +0 -0
  116. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/access.md +0 -0
  117. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/astrogator.md +0 -0
  118. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/cat.md +0 -0
  119. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/catalog.md +0 -0
  120. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/conjunction.md +0 -0
  121. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/coverage.md +0 -0
  122. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/lighting.md +0 -0
  123. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/orbits.md +0 -0
  124. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/propagator.md +0 -0
  125. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/rocket.md +0 -0
  126. {astrox_python-1.1.0 → astrox_python-1.2.0}/docs/validation/terrain.md +0 -0
  127. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/README.md +0 -0
  128. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/ballistic_apogee_alt.py +0 -0
  129. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/ballistic_delta_v.py +0 -0
  130. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/ballistic_min_ecc.py +0 -0
  131. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/ballistic_time_of_flight.py +0 -0
  132. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/batch_propagators.py +0 -0
  133. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/hpop.py +0 -0
  134. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/j2_classical.py +0 -0
  135. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/propagator_reference.py +0 -0
  136. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/sgp4_tle.py +0 -0
  137. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/simple_ascent.py +0 -0
  138. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/two_body_classical.py +0 -0
  139. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/01_propagation/two_body_rv.py +0 -0
  140. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/02_orbits/README.md +0 -0
  141. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/02_orbits/conversions.py +0 -0
  142. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/02_orbits/lambert_delta_v.py +0 -0
  143. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/02_orbits/orbit_system.py +0 -0
  144. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/02_orbits/wizards.py +0 -0
  145. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/03_lighting/README.md +0 -0
  146. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/03_lighting/lighting.py +0 -0
  147. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/04_access/README.md +0 -0
  148. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/04_access/chain.py +0 -0
  149. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/04_access/compute.py +0 -0
  150. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/04_access/constraints.py +0 -0
  151. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/04_access/custom_axes.py +0 -0
  152. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/04_access/sensor_pointing.py +0 -0
  153. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/05_rocket/README.md +0 -0
  154. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/05_rocket/landing_zone.py +0 -0
  155. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/06_coverage/README.md +0 -0
  156. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/06_coverage/compute.py +0 -0
  157. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/06_coverage/fom.py +0 -0
  158. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/06_coverage/grid_points.py +0 -0
  159. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/06_coverage/reports.py +0 -0
  160. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/07_astrogator/run_mcs.py +0 -0
  161. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/08_conjunction/README.md +0 -0
  162. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/08_conjunction/close_approaches.py +0 -0
  163. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/09_cat/README.md +0 -0
  164. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/09_cat/cat_workflows.py +0 -0
  165. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/10_catalog/README.md +0 -0
  166. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/10_catalog/catalog_queries.py +0 -0
  167. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/11_celestial/README.md +0 -0
  168. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/12_terrain/README.md +0 -0
  169. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/12_terrain/terrain_masks.py +0 -0
  170. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/13_libration/README.md +0 -0
  171. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/13_libration/libration_dynamics.py +0 -0
  172. {astrox_python-1.1.0 → astrox_python-1.2.0}/examples/manifest.toml +0 -0
  173. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/README.md +0 -0
  174. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/conftest.py +0 -0
  175. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/access/helpers.py +0 -0
  176. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/access/test_chain.py +0 -0
  177. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/access/test_compute.py +0 -0
  178. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/access/test_values.py +0 -0
  179. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/astrogator/test_api.py +0 -0
  180. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/astrogator/test_models.py +0 -0
  181. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/astrogator/test_results.py +0 -0
  182. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/cat/test_cat.py +0 -0
  183. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/catalog/test_catalog.py +0 -0
  184. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/client/test_client.py +0 -0
  185. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/components/test_components.py +0 -0
  186. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/conjunction/test_conjunction.py +0 -0
  187. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/coverage/test_coverage.py +0 -0
  188. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/coverage/test_coverage_fom.py +0 -0
  189. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/helpers.py +0 -0
  190. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/libration/test_libration.py +0 -0
  191. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/lighting/test_lighting.py +0 -0
  192. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/orbits/helpers.py +0 -0
  193. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/orbits/test_conversions.py +0 -0
  194. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/orbits/test_keplerian.py +0 -0
  195. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/orbits/test_orbit_system.py +0 -0
  196. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/orbits/test_tle.py +0 -0
  197. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/orbits/test_wizards.py +0 -0
  198. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/propagator/helpers.py +0 -0
  199. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/propagator/test_ballistic.py +0 -0
  200. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/propagator/test_hpop.py +0 -0
  201. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/propagator/test_j2_two_body.py +0 -0
  202. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/propagator/test_multi.py +0 -0
  203. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/propagator/test_public_contract.py +0 -0
  204. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/propagator/test_sgp4_simple_ascent.py +0 -0
  205. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/propagator/test_two_body_rv.py +0 -0
  206. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/rocket/__init__.py +0 -0
  207. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/rocket/test_rocket.py +0 -0
  208. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/sdk/terrain/test_terrain.py +0 -0
  209. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_external/gmat/README.md +0 -0
  210. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_external/gmat/hpop_driver.py +0 -0
  211. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_external/gmat/test_hpop_driver.py +0 -0
  212. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_support/__init__.py +0 -0
  213. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_support/contracts.py +0 -0
  214. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_support/external_tools.py +0 -0
  215. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_support/gmat.py +0 -0
  216. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_support/orekit.py +0 -0
  217. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_support/skyfield.py +0 -0
  218. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_support/test_contracts.py +0 -0
  219. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_support/test_external_tools.py +0 -0
  220. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_support/test_gmat.py +0 -0
  221. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/_support/test_skyfield.py +0 -0
  222. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/__init__.py +0 -0
  223. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/README.md +0 -0
  224. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/__init__.py +0 -0
  225. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/_aer.py +0 -0
  226. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/_cases.py +0 -0
  227. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/_constraints.py +0 -0
  228. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/_exclusion.py +0 -0
  229. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/_geometry.py +0 -0
  230. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/_mixed_model.py +0 -0
  231. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/_orientation.py +0 -0
  232. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_axes_orientation_geometry.py +0 -0
  233. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_chain_sgp4_skyfield.py +0 -0
  234. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_composite_czml_axes_geometry.py +0 -0
  235. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_compute_constraints_skyfield.py +0 -0
  236. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_compute_exclusion_constraints_invariants.py +0 -0
  237. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_compute_ground_sgp4_skyfield.py +0 -0
  238. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_compute_j2_two_body_geometry.py +0 -0
  239. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_compute_sgp4_j2_geometry.py +0 -0
  240. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_compute_site_hpop_geometry.py +0 -0
  241. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_compute_site_j2_geometry.py +0 -0
  242. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_compute_site_two_body_geometry.py +0 -0
  243. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_sensor_pointing_geometry.py +0 -0
  244. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/access/test_vgt_orientation_resolution.py +0 -0
  245. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/astrogator/__init__.py +0 -0
  246. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/astrogator/test_branch_semantics.py +0 -0
  247. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/astrogator/test_initial_state_conversions.py +0 -0
  248. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/astrogator/test_maneuver_invariants.py +0 -0
  249. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/astrogator/test_run_mcs_two_body_brahe.py +0 -0
  250. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/astrogator/test_scalar_invariants.py +0 -0
  251. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/astrogator/test_sequence_czml_brahe.py +0 -0
  252. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/astrogator/test_target_sequence_local.py +0 -0
  253. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/cat/test_cat_skyfield.py +0 -0
  254. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/conjunction/test_close_approaches_skyfield.py +0 -0
  255. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/_fom_helpers.py +0 -0
  256. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/test_exclusion_grid_constraints_skyfield.py +0 -0
  257. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/test_fom_at_time_boundaries_invariants.py +0 -0
  258. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/test_fom_edge_cases_invariants.py +0 -0
  259. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/test_fom_grid_options_invariants.py +0 -0
  260. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/test_fom_interval_invariants.py +0 -0
  261. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/test_fom_resource_options_invariants.py +0 -0
  262. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/test_fom_response_shapes_invariants.py +0 -0
  263. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/test_fom_response_time_dynamic_invariants.py +0 -0
  264. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/test_grid_generation_local.py +0 -0
  265. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/test_grid_point_modifiers_invariants.py +0 -0
  266. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/test_resource_reports_invariants.py +0 -0
  267. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/coverage/test_sgp4_grid_membership_skyfield.py +0 -0
  268. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/libration/_support.py +0 -0
  269. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/libration/test_cross_endpoint_consistency.py +0 -0
  270. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/libration/test_crtbp_trajectory.py +0 -0
  271. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/libration/test_fixed_x_correction.py +0 -0
  272. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/libration/test_orekit_qualification.py +0 -0
  273. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/libration/test_periodic_families.py +0 -0
  274. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/libration/test_positions_and_units.py +0 -0
  275. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/lighting/__init__.py +0 -0
  276. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/lighting/test_site_sun_skyfield.py +0 -0
  277. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/lighting/test_spacecraft_solar_intensity_orekit.py +0 -0
  278. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/lighting/test_spacecraft_sun_skyfield.py +0 -0
  279. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/orbit_system/__init__.py +0 -0
  280. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/orbit_system/_support.py +0 -0
  281. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/orbit_system/test_convert_czml_position.py +0 -0
  282. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/orbit_system/test_earth_moon_libration.py +0 -0
  283. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/orbits/__init__.py +0 -0
  284. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/orbits/test_kozai_izsak_mean_elements_invariants.py +0 -0
  285. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/orbits/test_lambert_lamberthub.py +0 -0
  286. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/orbits/test_lambert_path_points.py +0 -0
  287. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/orbits/test_walker_constellation_equations.py +0 -0
  288. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/orbits/test_wizards_local_derivation.py +0 -0
  289. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/propagator/test_ballistic_geodetic.py +0 -0
  290. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/propagator/test_hpop_gmat.py +0 -0
  291. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/propagator/test_j2_analytical.py +0 -0
  292. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/propagator/test_multi_sgp4_skyfield.py +0 -0
  293. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/propagator/test_sgp4_skyfield.py +0 -0
  294. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/propagator/test_simple_ascent_geodetic.py +0 -0
  295. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/propagator/test_two_body_brahe.py +0 -0
  296. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/propagator/test_two_body_rv_brahe.py +0 -0
  297. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/rocket/__init__.py +0 -0
  298. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/rocket/test_landing_zone_geographiclib.py +0 -0
  299. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/cross_validation/terrain/test_terrain_mask_invariants.py +0 -0
  300. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/__init__.py +0 -0
  301. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/access/__init__.py +0 -0
  302. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/access/access.snap.json +0 -0
  303. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/access/test_access.py +0 -0
  304. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/access/test_chain_topology.py +0 -0
  305. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/access/test_compute_model_pairs.py +0 -0
  306. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/access/test_compute_options.py +0 -0
  307. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/astrogator/__init__.py +0 -0
  308. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/astrogator/run_mcs.snap.json +0 -0
  309. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/cat/cat.snap.json +0 -0
  310. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/cat/test_cat.py +0 -0
  311. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/catalog/catalog.snap.json +0 -0
  312. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/catalog/test_catalog.py +0 -0
  313. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/conjunction/close_approaches.snap.json +0 -0
  314. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/conjunction/test_close_approaches.py +0 -0
  315. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/coverage/coverage.snap.json +0 -0
  316. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/coverage/test_coverage.py +0 -0
  317. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/libration/libration.snap.json +0 -0
  318. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/libration/test_libration.py +0 -0
  319. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/lighting/__init__.py +0 -0
  320. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/lighting/lighting.snap.json +0 -0
  321. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/lighting/test_lighting.py +0 -0
  322. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/orbits/__init__.py +0 -0
  323. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/orbits/conversions.snap.json +0 -0
  324. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/orbits/orbit_system.snap.json +0 -0
  325. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/orbits/test_conversion_roundtrip.py +0 -0
  326. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/orbits/test_conversions.py +0 -0
  327. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/orbits/test_orbit_system.py +0 -0
  328. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/orbits/test_wizards.py +0 -0
  329. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/orbits/wizards.snap.json +0 -0
  330. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/__init__.py +0 -0
  331. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/ballistic.snap.json +0 -0
  332. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/hpop.snap.json +0 -0
  333. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/j2.snap.json +0 -0
  334. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/multi_j2.snap.json +0 -0
  335. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/multi_sgp4.snap.json +0 -0
  336. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/multi_two_body.snap.json +0 -0
  337. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/sgp4.snap.json +0 -0
  338. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/simple_ascent.snap.json +0 -0
  339. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/test_ballistic.py +0 -0
  340. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/test_hpop.py +0 -0
  341. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/test_j2.py +0 -0
  342. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/test_multi_j2.py +0 -0
  343. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/test_multi_sgp4.py +0 -0
  344. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/test_multi_two_body.py +0 -0
  345. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/test_sgp4.py +0 -0
  346. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/test_simple_ascent.py +0 -0
  347. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/test_two_body.py +0 -0
  348. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/propagator/two_body.snap.json +0 -0
  349. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/rocket/__init__.py +0 -0
  350. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/rocket/landing_zone.snap.json +0 -0
  351. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/rocket/test_landing_zone.py +0 -0
  352. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/terrain/terrain.snap.json +0 -0
  353. {astrox_python-1.1.0 → astrox_python-1.2.0}/tests/validation/live_snapshot/terrain/test_terrain.py +0 -0
@@ -11,6 +11,9 @@ wheels/
11
11
  # Virtual environments
12
12
  .venv
13
13
 
14
+ # Local-only server runtime for validation triage (never commit)
15
+ .local-runtime/
16
+
14
17
  # Internal & intermediate docs
15
18
  *.md
16
19
  !README.md
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: astrox-python
3
- Version: 1.1.0
3
+ Version: 1.2.0
4
4
  Summary: Python SDK for the ASTROX Web API.
5
5
  Project-URL: Homepage, https://github.com/Mtrya/astrox-python
6
6
  Project-URL: Repository, https://github.com/Mtrya/astrox-python.git
@@ -369,13 +369,15 @@ def mpc_ephemeris(
369
369
  observer_frame: str | None = None,
370
370
  start: str | None = None,
371
371
  stop: str | None = None,
372
+ step_s: float | None = None,
372
373
  target_elements: MpcOrbitalElements | None = None,
373
374
  ) -> dict[str, Any]:
374
375
  """Return ASTROX minor-planet ephemeris output from its MPC-backed route.
375
376
 
376
377
  When ``target_elements`` is supplied, the server integrates those MPC
377
378
  orbital elements directly instead of resolving ``target_name`` through the
378
- MPC network query.
379
+ MPC network query. ``step_s`` controls the output sampling cadence; zero
380
+ requests the server's internal integration grid.
379
381
  """
380
382
  payload: dict[str, Any] = {
381
383
  "TargetName": _string(target_name, parameter="target_name"),
@@ -395,6 +397,11 @@ def mpc_ephemeris(
395
397
  "Stop",
396
398
  _optional_string(stop, parameter="stop"),
397
399
  )
400
+ _include_if_supplied(
401
+ payload,
402
+ "Step",
403
+ _optional_number(step_s, parameter="step_s"),
404
+ )
398
405
  _include_if_supplied(
399
406
  payload,
400
407
  "TargetElements",
@@ -32,7 +32,7 @@ Computes an ephemeris for a target body over a time window and returns a raw JSO
32
32
  | `start` | `Start` | Analysis start time (UTC, `yyyy-MM-ddTHH:mm:ssZ`). Optional; the server default is January 1 of the current year |
33
33
  | `stop` | `Stop` | Analysis stop time (UTC). Optional; the server default is December 31 of the current year |
34
34
  | `observer_name` | `ObserverName` | Observer name, e.g. `Earth`; the server default is `Sun` |
35
- | `observer_frame` | `ObserverFrame` | Observer frame, server options `FIXED`, `INERTIAL`, `MeanEclpJ2000`, `J2000`, default `MeanEclpJ2000` |
35
+ | `observer_frame` | `ObserverFrame` | Observer frame; the server currently accepts `FIXED`, `INERTIAL`, `MeanEclpJ2000`, `EclpJ2000ICRF`, `J2000`, and `ICRF`; default `MeanEclpJ2000` |
36
36
  | `step_s` | `Step` | Sample step, in s, server default 86400 s |
37
37
 
38
38
  `target_name` is the only required request field of this function; `start` and `stop` are optional — when omitted they are not sent to ASTROX and the server selects January 1 to December 31 of the current year as the window. Other optional fields that are not supplied are likewise not sent to ASTROX, and the server retains its default values.
@@ -43,7 +43,7 @@ from astrox import celestial
43
43
  start = "2026-01-01T00:00:00.000Z"
44
44
  stop = "2026-01-02T00:00:00.000Z"
45
45
 
46
- for frame in ("J2000", "MeanEclpJ2000"):
46
+ for frame in ("J2000", "MeanEclpJ2000", "EclpJ2000ICRF"):
47
47
  ephemeris = celestial.ephemeris(
48
48
  target_name="Moon",
49
49
  start=start,
@@ -81,11 +81,11 @@ Computes the rotation from the coordinate axes of the source central body to tho
81
81
  | `from_central_body` | `FromCbName` | Source central body name, e.g. `Earth` |
82
82
  | `to_central_body` | `ToCbName` | Target central body name, e.g. `Moon` |
83
83
  | `epoch` | `Epoch` | Epoch time (UTC) |
84
- | `from_frame` | `FromCbFrame` | Source frame, server options `FIXED`, `INERTIAL`, `J2000`, `ICRF`, `MeanEclpJ2000`, default `INERTIAL` |
84
+ | `from_frame` | `FromCbFrame` | Source frame, server options `FIXED`, `INERTIAL`, `J2000`, `ICRF`, `MeanEclpJ2000`, `EclpJ2000ICRF`, default `INERTIAL` |
85
85
  | `to_frame` | `ToCbFrame` | Target frame, same options, default `FIXED` |
86
86
  | `order` | `Order` | Rotation motion order: `0` returns the quaternion only, `1` returns the quaternion and angular velocity; passed through as an integer |
87
87
 
88
- `order` is preserved as an integer and lowered to the server as-is; the SDK does not rewrite the branch. The `Rotation` field of the response is a numeric array: with `order=0` it has length 4 (quaternion `[qx, qy, qz, qw]`), and with `order=1` it has length 7 (quaternion plus angular-velocity components, unit rad/s per the server documentation). Verified numeric semantics include: for the same central body on both sides with `INERTIAL` frames on both sides, the server returns the identity quaternion with zero angular velocity at `order=1`; the Earth `INERTIAL`→`FIXED` quaternion and angular velocity; and the Earth→Moon `INERTIAL`→`FIXED` angular velocity at `order=1`. The Earth→Moon `INERTIAL`→`FIXED` quaternion is unresolved, and other combinations are unverified, so verify their meaning yourself before use.
88
+ `order` is preserved as an integer and lowered to the server as-is; the SDK does not rewrite the branch. The `Rotation` field of the response is a numeric array: with `order=0` it has length 4 (quaternion `[qx, qy, qz, qw]`), and with `order=1` it has length 7 (quaternion plus angular-velocity components, unit rad/s per the server documentation). Verified numeric semantics include: for the same central body on both sides with `INERTIAL` frames on both sides, the server returns the identity quaternion with zero angular velocity at `order=1`; Earth→Earth `EclpJ2000ICRF`→`ICRF` follows the fixed J2000 mean-obliquity rotation with zero angular velocity at the two maintained epochs and `order=0/1`; the Earth `INERTIAL`→`FIXED` quaternion and angular velocity; and the Earth→Moon `INERTIAL`→`FIXED` angular velocity at `order=1`. The Earth→Moon `INERTIAL`→`FIXED` quaternion is unresolved, and other combinations are unverified, so verify their meaning yourself before use.
89
89
 
90
90
  ```python
91
91
  rotation = celestial.cb_axes_rotation(
@@ -113,6 +113,7 @@ celestial.mpc_ephemeris(
113
113
  observer_frame: str | None = None,
114
114
  start: str | None = None,
115
115
  stop: str | None = None,
116
+ step_s: float | None = None,
116
117
  target_elements: MpcOrbitalElements | None = None,
117
118
  ) -> dict[str, Any]
118
119
  ```
@@ -125,14 +126,15 @@ Queries an MPC minor-planet ephemeris by asteroid name or number and returns a r
125
126
  | `observer_frame` | `ObserverFrame` | Heliocentric frame, server options `FIXED`, `INERTIAL`, `J2000`, `ICRF`, `MeanEclpJ2000`, `EclpJ2000ICRF`, default `MeanEclpJ2000` |
126
127
  | `start` | `Start` | Start time (UTC); defaults to the orbital epoch and cannot be earlier than the orbital epoch (server rule) |
127
128
  | `stop` | `Stop` | Stop time (UTC); defaults to 1 year after `Start` |
129
+ | `step_s` | `Step` | Output sample step, in s, server default 86400 s; pass `0` to output at the internal integration steps |
128
130
  | `target_elements` | `TargetElements` | Explicit MPC orbital elements (built with `mpc_orbital_elements`); when omitted, the server queries MPC over the network |
129
131
 
130
- This route fetches orbital elements from the external MPC data source (element epoch in MJD TDT), which the server propagates heliocentrically with a fixed 3-day step, and outputs a heliocentric CZML Position structure. The response contains `OrbitElements` (orbital elements with keys `EpochMjdTdt`, `PeriTimeMjdTdt`, `Q`, `SemimajorAxis`, `Eccentricity`, `Inclination`, `Raan`, `ArgOfPeriapsis`, `MeanAnomaly`, `ReferenceFrame`) and `Position` (CZML structure, same as `ephemeris`). The orbital-element values come from external MPC data, are owned by that external data source, and may change with MPC updates. When `start`/`stop` are omitted, the server uses the orbital-epoch default window (`start` is the orbital epoch and `stop` is one year after it); an explicit fixed window depends on the orbital epoch at query time, and once the external MPC orbital epoch updates, a previously fixed window may fall before the new epoch and be rejected by the server, so prefer omitting the window parameters or following the current epoch.
132
+ This route fetches orbital elements from the external MPC data source (element epoch in MJD TDT). The server contract declares adaptive heliocentric integration followed by Hermite interpolation onto the fixed output grid selected by `step_s`; `step_s=0` requests output at the server-declared internal integration steps. The response is a heliocentric CZML Position structure containing `OrbitElements` (orbital elements with keys `EpochMjdTdt`, `PeriTimeMjdTdt`, `Q`, `SemimajorAxis`, `Eccentricity`, `Inclination`, `Raan`, `ArgOfPeriapsis`, `MeanAnomaly`, `ReferenceFrame`) and `Position` (CZML structure, same as `ephemeris`). The orbital-element values come from external MPC data, are owned by that external data source, and may change with MPC updates. When `start`/`stop` are omitted, the server uses the orbital-epoch default window (`start` is the orbital epoch and `stop` is one year after it); an explicit fixed window depends on the orbital epoch at query time, and once the external MPC orbital epoch updates, a previously fixed window may fall before the new epoch and be rejected by the server, so prefer omitting the window parameters or following the current epoch.
131
133
 
132
- Verified (endpoint-internal invariant): passing the `OrbitElements` returned by a name query back as `target_elements` reproduces the name-query ephemeris exactly; the `reference_frame` values `EclpJ2000ICRF` (MPC convention, server default) and `MeanEclpJ2000` (JPL convention) are two distinguishable branches. See the [celestial validation page](../../../../validation/celestial.md) for the evidence.
134
+ Verified (within-route invariants): passing the `OrbitElements` returned by a name query back as `target_elements` reproduces the name-query ephemeris exactly; omitting `step_s` exactly matches explicit `86400`, `172800` produces an exact subset of the daily grid, and `0` returns the same endpoints on a nonuniform internal integration grid; the `reference_frame` values `EclpJ2000ICRF` (MPC convention, server default) and `MeanEclpJ2000` (JPL convention) are two distinguishable branches. This evidence verifies request branches and output-sampling semantics, not absolute orbit accuracy. See the [celestial validation page](../../../../validation/celestial.md) for details.
133
135
 
134
136
  ```python
135
- mpc = celestial.mpc_ephemeris(target_name="Ceres")
137
+ mpc = celestial.mpc_ephemeris(target_name="Ceres", step_s=172800.0)
136
138
 
137
139
  print(f"Ceres MPC ephemeris: {len(mpc['Position']['cartesianVelocity']) // 7} state samples")
138
140
  ```
@@ -227,7 +229,7 @@ Samples over the departure time window and the arrival time window, computes Lam
227
229
  | `departure_stop` | `DepartureInterval` | Departure time window end (UTC) |
228
230
  | `arrival_start` | `ArrivalInterval` | Arrival time window start (UTC); combined with `arrival_stop` into `"start/stop"` |
229
231
  | `arrival_stop` | `ArrivalInterval` | Arrival time window end (UTC) |
230
- | `sun_frame` | `SunFrameName` | Heliocentric frame, server options `MeanEclpJ2000`, `ICRF`, default `MeanEclpJ2000` |
232
+ | `sun_frame` | `SunFrameName` | Heliocentric output frame; the server currently accepts `MeanEclpJ2000`, `EclpJ2000ICRF`, and `ICRF`; default `EclpJ2000ICRF` |
231
233
  | `min_time_of_flight_days` | `MinTofDays` | Minimum transfer time, in d, integer; server default 10 |
232
234
  | `departure_step_days` | `DepartureStepDay` | Departure time sample step, in d; server default 1 |
233
235
  | `arrival_step_days` | `ArrivalStepDay` | Arrival time sample step, in d; server default 1 |
@@ -279,7 +281,7 @@ The response contains `TransferResults` (an array of transfer results; each elem
279
281
  | `TimeOfFlightDays` | number | Time of flight, in d; verified to be the exact day difference between `ArrivalTime` and `DepartureTime` |
280
282
  | `ArrivalLightAngle` | number | Sun lighting angle at arrival, in deg; verified to be the angle between `DeltaV2` and the `RV2` position vector |
281
283
 
282
- Verified (supported by independent cross-validation): with `sun_frame="ICRF"`, the transfer velocities in `RV1`/`RV2` follow the zero-revolution prograde Lambert relationship, and the endpoint position directions use the ICRF axes; `max_departure_delta_v_m_s`/`max_arrival_delta_v_m_s`/`max_time_of_flight_days` filter the sampled grid by the `DV1_Mag`/`DV2_Mag`/time-of-flight upper bounds respectively. Note that since 2026-08-20 the server defaults (10000 m/s each for departure/arrival, 500 d) filter out cases beyond the defaults, so scans over large-ΔV windows need explicitly widened bounds. Unresolved: the exact coordinate relationship between `MeanEclpJ2000` and ICRF, the physical meaning of `DeltaV` relative to the endpoint-body velocities, and independent Kepler propagation of explicit MPC elements (the `reference_frame` option does not change the arrival states of that route; the element convention is still unconfirmed). These branches currently have only request-construction and response-structure evidence, so verify their meaning yourself before use.
284
+ Verified (supported by independent cross-validation): omitting `sun_frame` produces exactly the same `TransferResults` as explicit `EclpJ2000ICRF`; `EclpJ2000ICRF` output is the `ICRF` output rotated by the fixed 23.43929111111111° J2000 mean obliquity; with `sun_frame="ICRF"`, the transfer velocities in `RV1`/`RV2` follow the zero-revolution prograde Lambert relationship, and the endpoint position directions use the ICRF axes; `max_departure_delta_v_m_s`/`max_arrival_delta_v_m_s`/`max_time_of_flight_days` filter the sampled grid by the `DV1_Mag`/`DV2_Mag`/time-of-flight upper bounds respectively. Note that since 2026-08-20 the server defaults (10000 m/s each for departure/arrival, 500 d) filter out cases beyond the defaults, so scans over large-ΔV windows need explicitly widened bounds. Unresolved: the exact coordinate relationship between explicit `MeanEclpJ2000` and ICRF, the physical meaning of `DeltaV` relative to the endpoint-body velocities, and independent Kepler propagation of explicit MPC elements (the `reference_frame` option does not change the arrival states of that route; the element convention is still unconfirmed). The numeric semantics of those branches remain unverified, so check them before use.
283
285
 
284
286
  ## Convention notes
285
287
 
@@ -287,6 +289,7 @@ Verified (supported by independent cross-validation): with `sun_frame="ICRF"`, t
287
289
  - Each `cartesianVelocity` sample is `[Time, X, Y, Z, dX, dY, dZ]`, with `Time` in seconds from the reference epoch, positions in m, and velocities in m/s.
288
290
  - `cb_axes_rotation` passes the integer `order` through as-is; the `Rotation` length corresponds to `order` (`0` → 4, `1` → 7).
289
291
  - `mpc_ephemeris` relies on the server's orbital-epoch default window when `start`/`stop` are omitted; an explicit fixed window may expire when the external MPC orbital epoch updates.
292
+ - `mpc_ephemeris` `step_s` controls the output sampling grid; when omitted the server default is 86400 s, while `0` outputs at the internal integration steps.
290
293
  - The returns of all four functions on this page have the transport-level `IsSuccess` and `Message` removed, and the remaining server fields are preserved; errors are still raised by the HTTP layer (see error handling).
291
294
  - `lambert_transfer_window` combines `departure_start`/`departure_stop` and `arrival_start`/`arrival_stop` into the `"start/stop"` strings of `DepartureInterval`/`ArrivalInterval` respectively.
292
295
  - `mpc_orbital_elements` only performs the type checks required for lowering and does not perform physical-validity validation; fields that are not supplied do not appear in the `to_wire()` fragment.
@@ -32,7 +32,7 @@ celestial.ephemeris(
32
32
  | `start` | `Start` | 分析开始时刻(UTC,`yyyy-MM-ddTHH:mm:ssZ`)。可选;服务端缺省为当年 1 月 1 日 |
33
33
  | `stop` | `Stop` | 分析结束时刻(UTC)。可选;服务端缺省为当年 12 月 31 日 |
34
34
  | `observer_name` | `ObserverName` | 观测者名称,如 `Earth`;服务端缺省为 `Sun` |
35
- | `observer_frame` | `ObserverFrame` | 观测者坐标系,服务端可选 `FIXED`、`INERTIAL`、`MeanEclpJ2000`、`J2000`,缺省为 `MeanEclpJ2000` |
35
+ | `observer_frame` | `ObserverFrame` | 观测者坐标系,服务端当前接受 `FIXED`、`INERTIAL`、`MeanEclpJ2000`、`EclpJ2000ICRF`、`J2000`、`ICRF`,缺省为 `MeanEclpJ2000` |
36
36
  | `step_s` | `Step` | 采样步长,单位 s,服务端缺省 86400 s |
37
37
 
38
38
  `target_name` 是本函数唯一必填的请求字段;`start` 与 `stop` 可选,省略时不会被发往 ASTROX,由服务端选择当年 1 月 1 日至 12 月 31 日作为窗口,其它未提供的可选字段同样不会被发往 ASTROX,由服务器保留默认值。
@@ -43,7 +43,7 @@ from astrox import celestial
43
43
  start = "2026-01-01T00:00:00.000Z"
44
44
  stop = "2026-01-02T00:00:00.000Z"
45
45
 
46
- for frame in ("J2000", "MeanEclpJ2000"):
46
+ for frame in ("J2000", "MeanEclpJ2000", "EclpJ2000ICRF"):
47
47
  ephemeris = celestial.ephemeris(
48
48
  target_name="Moon",
49
49
  start=start,
@@ -81,11 +81,11 @@ celestial.cb_axes_rotation(
81
81
  | `from_central_body` | `FromCbName` | 起始中心天体名称,如 `Earth` |
82
82
  | `to_central_body` | `ToCbName` | 目标中心天体名称,如 `Moon` |
83
83
  | `epoch` | `Epoch` | 历元时刻(UTC) |
84
- | `from_frame` | `FromCbFrame` | 起始坐标系,服务端可选 `FIXED`、`INERTIAL`、`J2000`、`ICRF`、`MeanEclpJ2000`,缺省为 `INERTIAL` |
84
+ | `from_frame` | `FromCbFrame` | 起始坐标系,服务端可选 `FIXED`、`INERTIAL`、`J2000`、`ICRF`、`MeanEclpJ2000`、`EclpJ2000ICRF`,缺省为 `INERTIAL` |
85
85
  | `to_frame` | `ToCbFrame` | 目标坐标系,选项同上,缺省为 `FIXED` |
86
86
  | `order` | `Order` | 旋转运动阶数:`0` 仅返回四元数,`1` 返回四元数及角速度;整数原样传递 |
87
87
 
88
- `order` 保留为整数并原样 lower 到服务端,SDK 不做分支改写。响应中的 `Rotation` 是数值数组:`order=0` 时长度为 4(四元数 `[qx, qy, qz, qw]`),`order=1` 时长度为 7(四元数加角速度分量,服务端文档标注角速度单位为 rad/s)。已验证的数值语义包括:同一中心天体、两侧均为 `INERTIAL` 时,服务端返回单位四元数且 `order=1` 时角速度为 0;`Earth` 的 `INERTIAL`→`FIXED` 四元数与角速度;`Earth`→`Moon` 的 `INERTIAL`→`FIXED` 在 `order=1` 时的角速度。`Earth`→`Moon` 的 `INERTIAL`→`FIXED` 四元数尚未确认,其它组合未验证,使用前请自行核对。
88
+ `order` 保留为整数并原样 lower 到服务端,SDK 不做分支改写。响应中的 `Rotation` 是数值数组:`order=0` 时长度为 4(四元数 `[qx, qy, qz, qw]`),`order=1` 时长度为 7(四元数加角速度分量,服务端文档标注角速度单位为 rad/s)。已验证的数值语义包括:同一中心天体、两侧均为 `INERTIAL` 时,服务端返回单位四元数且 `order=1` 时角速度为 0;`Earth`→`Earth` 的 `EclpJ2000ICRF`→`ICRF` 在两个已维护历元、`order=0/1` 下符合固定 J2000 平黄赤交角旋转且角速度为 0;`Earth` 的 `INERTIAL`→`FIXED` 四元数与角速度;`Earth`→`Moon` 的 `INERTIAL`→`FIXED` 在 `order=1` 时的角速度。`Earth`→`Moon` 的 `INERTIAL`→`FIXED` 四元数尚未确认,其它组合未验证,使用前请自行核对。
89
89
 
90
90
  ```python
91
91
  rotation = celestial.cb_axes_rotation(
@@ -113,6 +113,7 @@ celestial.mpc_ephemeris(
113
113
  observer_frame: str | None = None,
114
114
  start: str | None = None,
115
115
  stop: str | None = None,
116
+ step_s: float | None = None,
116
117
  target_elements: MpcOrbitalElements | None = None,
117
118
  ) -> dict[str, Any]
118
119
  ```
@@ -125,14 +126,15 @@ celestial.mpc_ephemeris(
125
126
  | `observer_frame` | `ObserverFrame` | 日心坐标系,服务端可选 `FIXED`、`INERTIAL`、`J2000`、`ICRF`、`MeanEclpJ2000`、`EclpJ2000ICRF`,缺省为 `MeanEclpJ2000` |
126
127
  | `start` | `Start` | 开始时刻(UTC);缺省为轨道历元时刻,不能早于轨道历元时刻(服务端规则) |
127
128
  | `stop` | `Stop` | 结束时刻(UTC);缺省为 `Start` 起 1 年 |
129
+ | `step_s` | `Step` | 输出采样步长,单位 s,服务端缺省 86400 s;传入 `0` 时按内部积分步长输出 |
128
130
  | `target_elements` | `TargetElements` | 显式 MPC 轨道根数(`mpc_orbital_elements` 构造);省略时服务端通过网络查询 MPC |
129
131
 
130
- 该路由从外部 MPC 数据源获取轨道根数(历元为 MJD TDT),由服务端以固定 3 天步长进行日心轨道递推,输出为日心系 CZML Position 结构。响应包含 `OrbitElements`(轨道根数,键为 `EpochMjdTdt`、`PeriTimeMjdTdt`、`Q`、`SemimajorAxis`、`Eccentricity`、`Inclination`、`Raan`、`ArgOfPeriapsis`、`MeanAnomaly`、`ReferenceFrame`)与 `Position`(CZML 结构,同 `ephemeris`)。轨道根数的数值来自外部 MPC 数据,属于外部数据所有,可能随 MPC 数据更新而变化。省略 `start`/`stop` 时,服务端使用轨道历元默认窗口(`start` 为轨道历元时刻,`stop` 为其后 1 年);显式固定窗口依赖查询时的轨道历元,外部 MPC 轨道历元更新后,先前固定的窗口可能早于新历元而被服务端拒绝,建议省略窗口参数或跟随当前历元选择。
132
+ 该路由从外部 MPC 数据源获取轨道根数(历元为 MJD TDT)。服务端契约声明其使用自适应日心积分器递推,再通过 Hermite 插值重采样到 `step_s` 指定的固定输出网格;`step_s=0` 表示请求按服务端声明的内部积分步长输出。响应为日心系 CZML Position 结构,包含 `OrbitElements`(轨道根数,键为 `EpochMjdTdt`、`PeriTimeMjdTdt`、`Q`、`SemimajorAxis`、`Eccentricity`、`Inclination`、`Raan`、`ArgOfPeriapsis`、`MeanAnomaly`、`ReferenceFrame`)与 `Position`(CZML 结构,同 `ephemeris`)。轨道根数的数值来自外部 MPC 数据,属于外部数据所有,可能随 MPC 数据更新而变化。省略 `start`/`stop` 时,服务端使用轨道历元默认窗口(`start` 为轨道历元时刻,`stop` 为其后 1 年);显式固定窗口依赖查询时的轨道历元,外部 MPC 轨道历元更新后,先前固定的窗口可能早于新历元而被服务端拒绝,建议省略窗口参数或跟随当前历元选择。
131
133
 
132
- 已验证(端点间不变量):把名称查询返回的 `OrbitElements` 以 `target_elements` 原样回传,得到的星历与名称查询结果完全一致;`reference_frame` 的 `EclpJ2000ICRF`(MPC 约定,服务端缺省)与 `MeanEclpJ2000`(JPL 约定)是可区分的两个分支。验证证据见 [celestial 验证页](../../validation/celestial.md)。
134
+ 已验证(路由内不变量):把名称查询返回的 `OrbitElements` 以 `target_elements` 原样回传,得到的星历与名称查询结果完全一致;省略 `step_s` 与显式传入 `86400` 结果完全一致,`172800` 输出是日采样网格的精确子集,`0` 返回端点一致但中间时间不等距的内部积分网格;`reference_frame` 的 `EclpJ2000ICRF`(MPC 约定,服务端缺省)与 `MeanEclpJ2000`(JPL 约定)是可区分的两个分支。这些证据验证请求分支与输出采样语义,不验证绝对轨道精度;详见 [celestial 验证页](../../validation/celestial.md)。
133
135
 
134
136
  ```python
135
- mpc = celestial.mpc_ephemeris(target_name="Ceres")
137
+ mpc = celestial.mpc_ephemeris(target_name="Ceres", step_s=172800.0)
136
138
 
137
139
  print(f"Ceres MPC 星历: {len(mpc['Position']['cartesianVelocity']) // 7} 个状态样本")
138
140
  ```
@@ -227,7 +229,7 @@ celestial.lambert_transfer_window(
227
229
  | `departure_stop` | `DepartureInterval` | 出发时间窗口终点(UTC) |
228
230
  | `arrival_start` | `ArrivalInterval` | 到达时间窗口起点(UTC),与 `arrival_stop` 一起 lower 为 `"start/stop"` |
229
231
  | `arrival_stop` | `ArrivalInterval` | 到达时间窗口终点(UTC) |
230
- | `sun_frame` | `SunFrameName` | 日心参考系,服务端可选 `MeanEclpJ2000`、`ICRF`,缺省为 `MeanEclpJ2000` |
232
+ | `sun_frame` | `SunFrameName` | 日心输出参考系,服务端当前接受 `MeanEclpJ2000`、`EclpJ2000ICRF`、`ICRF`,缺省为 `EclpJ2000ICRF` |
231
233
  | `min_time_of_flight_days` | `MinTofDays` | 最小转移时间,单位 d,整数;服务端缺省 10 |
232
234
  | `departure_step_days` | `DepartureStepDay` | 出发时间采样步长,单位 d;服务端缺省 1 |
233
235
  | `arrival_step_days` | `ArrivalStepDay` | 到达时间采样步长,单位 d;服务端缺省 1 |
@@ -279,7 +281,7 @@ print(
279
281
  | `TimeOfFlightDays` | number | 飞行时间,单位 d;已验证为 `ArrivalTime` 与 `DepartureTime` 的精确天数差 |
280
282
  | `ArrivalLightAngle` | number | 到达时刻太阳光照角,单位 deg;已验证为 `DeltaV2` 与 `RV2` 位置矢量的夹角 |
281
283
 
282
- 已验证(独立交叉验证支持):`sun_frame="ICRF"` 时,`RV1`/`RV2` 中的转移速度遵循零圈顺行 Lambert 关系,端点位置方向使用 ICRF 轴;`max_departure_delta_v_m_s`/`max_arrival_delta_v_m_s`/`max_time_of_flight_days` 分别按 `DV1_Mag`/`DV2_Mag`/飞行时间上限过滤采样网格。注意 2026-08-20 起服务端缺省值(出发/到达各 10000 m/s、500 d)会过滤掉超出缺省的算例,扫描大 ΔV 窗口时需显式放宽。未解决:`MeanEclpJ2000` 与 ICRF 之间的精确坐标关系、`DeltaV` 相对端点天体速度的物理含义、显式 MPC 根数的独立开普勒递推(`reference_frame` 选项不改变该路由的到达状态,元素约定仍未确认)。这些分支目前只有请求构造与响应结构层面的证据,使用前请自行核对。
284
+ 已验证(独立交叉验证支持):省略 `sun_frame` 与显式传入 `EclpJ2000ICRF` 的 `TransferResults` 完全一致;`EclpJ2000ICRF` 输出是 `ICRF` 输出按 23.43929111111111° J2000 平黄赤交角进行的固定旋转;`sun_frame="ICRF"` 时,`RV1`/`RV2` 中的转移速度遵循零圈顺行 Lambert 关系,端点位置方向使用 ICRF 轴;`max_departure_delta_v_m_s`/`max_arrival_delta_v_m_s`/`max_time_of_flight_days` 分别按 `DV1_Mag`/`DV2_Mag`/飞行时间上限过滤采样网格。注意 2026-08-20 起服务端缺省值(出发/到达各 10000 m/s、500 d)会过滤掉超出缺省的算例,扫描大 ΔV 窗口时需显式放宽。未解决:显式 `MeanEclpJ2000` 与 ICRF 之间的精确坐标关系、`DeltaV` 相对端点天体速度的物理含义、显式 MPC 根数的独立开普勒递推(`reference_frame` 选项不改变该路由的到达状态,元素约定仍未确认)。这些分支的数值语义尚未验证,使用前请自行核对。
283
285
 
284
286
  ## 约定说明
285
287
 
@@ -287,6 +289,7 @@ print(
287
289
  - `cartesianVelocity` 每个样本为 `[Time, X, Y, Z, dX, dY, dZ]`,`Time` 为相对历元的秒数,位置 m、速度 m/s。
288
290
  - `cb_axes_rotation` 的 `order` 是整数,SDK 原样传递;`Rotation` 长度与 `order` 对应(`0` → 4,`1` → 7)。
289
291
  - `mpc_ephemeris` 省略 `start`/`stop` 时由服务端使用轨道历元默认窗口;显式固定窗口可能因外部 MPC 轨道历元更新而过期。
292
+ - `mpc_ephemeris` 的 `step_s` 控制输出采样网格;省略时服务端缺省为 86400 s,传入 `0` 时按内部积分步长输出。
290
293
  - 本页四个函数的返回都移除了传输层 `IsSuccess` 与 `Message`,保留其余服务器字段;错误仍由 HTTP 层抛出(见错误处理)。
291
294
  - `lambert_transfer_window` 的 `departure_start`/`departure_stop` 与 `arrival_start`/`arrival_stop` 分别组合为 `DepartureInterval`/`ArrivalInterval` 的 `"start/stop"` 字符串。
292
295
  - `mpc_orbital_elements` 只做 lowering 所需的类型检查,不做物理有效性校验;未提供的字段不出现在 `to_wire()` 片段中。
@@ -68,6 +68,8 @@ Start with the most obvious external convention and expect it to fail. Deliberat
68
68
 
69
69
  The bounded investigation limit is three external adjustments plus two branch-variant probes per branch. If no explainable residual is found after that budget, mark the case `unresolved` and stop. Do not random-walk parameters.
70
70
 
71
+ The budget applies to work against the shared live server. Exploratory probing beyond the budget—wider parameter sweeps, larger case batches, trial-and-error triage—is allowed only against a local ASTROX runtime (see `tests/validation/README.md`). When a local probe finds a candidate convention or mismatch, reduce it to a hypothesis-driven case within the budget and re-confirm it against the live server before it becomes a committed test, snapshot, or evidence claim.
72
+
71
73
  Tolerances are precision bounds for an explained comparison. They are set at the start based on the comparison's claimed precision. They are never widened to absorb an unexplained residual, a unit mistake, a frame confusion, or a branch misunderstanding.
72
74
 
73
75
  If the residual is stable and can be characterized as "ASTROX does X instead of Y," that is valid calibration. Document the observed ASTROX convention. Do not judge ASTROX against a textbook; the goal is to understand what ASTROX actually does.
@@ -4,59 +4,64 @@ This page records the cross-validation and live-snapshot evidence for `astrox.ce
4
4
 
5
5
  ## Ephemeris
6
6
 
7
- Status of `celestial.ephemeris`: `partial` — response, wire-declared frame, epoch, and sample-layout fields are `verified`; the numeric geometric state semantics are `unresolved`.
7
+ Status of `celestial.ephemeris`: `partial` — response, wire-declared frame, epoch, sample-layout fields, and the `EclpJ2000ICRF`↔`ICRF` coordinate relation are `verified`; the absolute numeric geometric state semantics are `unresolved`.
8
8
 
9
9
  - Response structure: `verified` through live snapshots for an explicit Moon window — envelope (`Position`, `Period`; the transport status wrapper fields `IsSuccess`/`Message` are removed from curated returns) and the `Position` keys (`CentralBody`, `referenceFrame`, `epoch`, `interval`, `interpolationAlgorithm`, `interpolationDegree`, `cartesianVelocity`), with `cartesianVelocity` as a 7-value-per-sample list `[Time, X, Y, Z, dX, dY, dZ]` where positions are m and velocities are m/s.
10
- - Wire-declared frame and central body: `verified` for the maintained cases. `Position.CentralBody` is `Earth` and `Position.referenceFrame` matches the requested `observer_frame` for `J2000` and `MeanEclpJ2000` at the requested epoch.
11
- - Geometric state semantics: `unresolved`. The maintained executable comparison uses Skyfield 1.54 with the DE421 ephemeris as the independent target-minus-Earth geometric state at the same epoch; `MeanEclpJ2000` is obtained by applying the standard J2000 mean-obliquity rotation (23.439291111 deg) to the same geometric state. The comparison intentionally does not use Skyfield `observe()`, which would apply light-time and compare a retarded apparent state with ASTROX's sampled same-epoch state. DE430t is only probe history (its kernel contains a Mars barycenter segment rather than a Mars center segment) and is not part of the maintained comparison. ASTROX's internal planetary kernel is not known to be identical to Skyfield's, so the comparison stays a calibration probe: the residual is not explained and no passing tolerance is derived.
10
+ - Wire-declared frame and central body: `verified` for the maintained cases. `Position.CentralBody` is `Earth` and `Position.referenceFrame` matches the requested `observer_frame` for `J2000`, `MeanEclpJ2000`, `ICRF`, and `EclpJ2000ICRF` at the requested epoch.
11
+ - `EclpJ2000ICRF`↔`ICRF` coordinate relation: `verified` for Moon and Mars at the three maintained sample offsets. Applying a fixed 23.43929111111111° J2000 mean-obliquity rotation to the live ICRF position and velocity reproduces the live `EclpJ2000ICRF` state within `ECLIPTIC_RELATION_POSITION_ABS_M = 1e-3 m` and `ECLIPTIC_RELATION_VELOCITY_ABS_M_S = 1e-10 m/s`; current maximum residuals are approximately 6.2e-5 m and 7.3e-12 m/s. This verifies the relation between two live branches, not their absolute ephemeris accuracy.
12
+ - Absolute geometric state semantics: `unresolved`. The maintained executable comparison uses Skyfield 1.54 with the DE421 ephemeris as the independent target-minus-Earth geometric state at the same epoch; `MeanEclpJ2000` is obtained by applying the standard J2000 mean-obliquity rotation (23.43929111111111 deg) to the same geometric state. The comparison intentionally does not use Skyfield `observe()`, which would apply light-time and compare a retarded apparent state with ASTROX's sampled same-epoch state. DE430t is only probe history (its kernel contains a Mars barycenter segment rather than a Mars center segment) and is not part of the maintained comparison. ASTROX's internal planetary kernel is not known to be identical to Skyfield's, so the comparison stays a calibration probe: the residual is not explained and no passing tolerance is derived.
12
13
 
13
14
  Key constants and probes from [`tests/validation/cross_validation/celestial/test_ephemeris_skyfield.py`](../../tests/validation/cross_validation/celestial/test_ephemeris_skyfield.py):
14
15
 
15
16
  - `START = "2026-01-01T00:00:00.000Z"`, `STOP = "2026-01-02T00:00:00.000Z"`, sample step 43200 s, sample offsets 0, 43200, and 86400 s.
16
17
  - Diagnostic resolution thresholds only: position 1e-6 km, velocity 1e-12 km/s. These are not passing tolerances; the numeric comparisons are retained as strict calibration xfails.
17
- - Coverage: Moon and Mars × `J2000`/`MeanEclpJ2000` × three sample offsets (12 comparisons).
18
+ - Coverage: Moon and Mars × `J2000`/`MeanEclpJ2000` × three sample offsets for the unresolved external-kernel comparisons, plus Moon and Mars × three offsets for the verified live `EclpJ2000ICRF`↔`ICRF` relation.
18
19
 
19
20
  Known residuals and probe history: at the maintained 2026-01 window the Moon residuals are approximately 0.056 km / 2.37e-7 km/s and the Mars barycenter residuals are approximately 33.6 km / 1.26e-5 km/s; DE421 is similar. Applying an ERFA frame-bias rotation in either direction does not explain both position and velocity residuals. A second 2026-06 window changes the Mars position residual to about 69.8 km, and a 3600 s sample step leaves the 2026-01 residual essentially unchanged. The numeric geometric semantics therefore remain `unresolved`: the comparisons stay visible as strict calibration xfails with the probe notes preserved in the script, and no tolerance is derived from these observations.
20
21
 
21
22
  ## Central-body axes rotation
22
23
 
23
- Status of `celestial.cb_axes_rotation`: `partial` — the same-body identity invariant, the Earth INERTIAL→FIXED transformation, and the Earth→Moon order=1 angular velocity are `verified`; the Earth→Moon quaternion remains `unresolved`.
24
+ Status of `celestial.cb_axes_rotation`: `partial` — the same-body identity invariant, the Earth→Earth `EclpJ2000ICRF`→`ICRF` relation, the Earth INERTIAL→FIXED transformation, and the Earth→Moon order=1 angular velocity are `verified`; the Earth→Moon quaternion remains `unresolved`.
24
25
 
25
26
  - Response structure: `verified` through live snapshots for `order=0` (Rotation length 4) and `order=1` (Rotation length 7), with numeric items, on the default Earth→Moon request.
26
27
  - Same-body identity invariant: `verified` through [`tests/validation/cross_validation/celestial/test_cb_axes_rotation_invariants.py`](../../tests/validation/cross_validation/celestial/test_cb_axes_rotation_invariants.py). With the same central body on both sides (`Earth` and `Moon`) and `INERTIAL` frames on both sides, the returned Rotation is the identity quaternion `(0, 0, 0, 1)` and the angular-velocity suffix is zero for `order=1`, within `ABS_TOL = 1e-12`, at two maintained epochs (`2026-01-01T00:00:00.000Z` and `2026-06-01T00:00:00.000Z`), for 8 checks total.
28
+ - Earth→Earth `EclpJ2000ICRF`→`ICRF` transformation: `verified` for `order=0` and `order=1` at the two maintained epochs against the analytic fixed 23.43929111111111° J2000 mean-obliquity rotation, within `MATRIX_ABS_TOL = 1e-8`; the current matrix residual is approximately 1.1e-16 and the `order=1` angular velocity is zero within `ABS_TOL = 1e-12`.
27
29
  - Earth INERTIAL→FIXED transformation: `verified` for `order=0` and `order=1` against an independent ERFA construction (`c2i06a` plus the Earth rotation angle evaluated with UTC, matching the service's observed UTC rotation convention), at the two maintained epochs, within `MATRIX_ABS_TOL = 1e-8` and `ANGULAR_VELOCITY_ABS_TOL = 1e-10` rad/s.
28
30
  - Earth→Moon INERTIAL→FIXED angular velocity (`order=1`): `verified` against an independent SPICE J2000→IAU_MOON orientation derivative (`xf2rav` on the maintained public PCK/DE440 data), at the two maintained epochs; the residual is about 4.7e-11 rad/s, within `ANGULAR_VELOCITY_ABS_TOL = 1e-10` rad/s.
29
31
  - Earth→Moon INERTIAL→FIXED quaternion (`order=0`): `unresolved`. The independent SPICE DE440 IAU_MOON orientation differs by 0.001–0.003 degrees across the maintained epochs; the comparison is retained as a strict calibration xfail (`QUATERNION_RESOLUTION_DEG = 1e-6` is a diagnostic resolution, not a passing tolerance) until the ASTROX Moon frame/model convention is identified.
30
- - Scope boundary: the maintained evidence covers the identity invariant, the Earth INERTIAL→FIXED branch, and the Earth→Moon order=1 angular velocity; the Earth→Moon quaternion and frame combinations beyond these remain `unverified`.
32
+ - Scope boundary: the maintained evidence covers the identity invariant, the Earth→Earth `EclpJ2000ICRF`→`ICRF` relation, the Earth INERTIAL→FIXED branch, and the Earth→Moon order=1 angular velocity; the Earth→Moon quaternion and frame combinations beyond these remain `unverified`.
31
33
 
32
34
  ## MPC ephemeris
33
35
 
34
- Status of `celestial.mpc_ephemeris`: structure `verified`, `target_elements` branch `verified`, numeric values external-data-owned.
36
+ Status of `celestial.mpc_ephemeris`: structure, `target_elements`, `reference_frame`, and output-cadence branches `verified`; absolute numeric values remain external-data-owned and `unverified`.
35
37
 
36
38
  - Response structure: `verified` through the live snapshot for `target_name="Ceres"` with the server-owned default window (fixed `Start`/`Stop` omitted) — envelope (`OrbitElements`, `Position`; the transport status wrapper fields are removed from curated returns), `OrbitElements` keys (`EpochMjdTdt`, `PeriTimeMjdTdt`, `Q`, `SemimajorAxis`, `Eccentricity`, `Inclination`, `Raan`, `ArgOfPeriapsis`, `MeanAnomaly`, `ReferenceFrame`), and a `Position` CZML-like structure with the same keys as `ephemeris`.
37
- - Numeric values: `unverified` as ASTROX semantics. The route fetches orbital elements from the external MPC API (`https://data.minorplanetcenter.net/api/get-orb`, element epoch in MJD TDT) and propagates them heliocentrically; since 2026-08-20 the server uses a fixed 3-day step (previously 1-day). The numeric orbital values are external-data-owned and may change with MPC updates. No independent oracle is maintained, so no semantic cross-validation is claimed. The maintained case omits `Start`/`Stop` so the server applies its orbital-epoch default window, avoiding fixed windows that could fall before a future MPC orbital epoch and be rejected.
39
+ - Numeric values: `unverified` as absolute ASTROX ephemeris semantics. The route fetches orbital elements from the external MPC API (`https://data.minorplanetcenter.net/api/get-orb`, element epoch in MJD TDT); the current server contract declares adaptive heliocentric integration followed by Hermite resampling onto the requested fixed output grid. The numeric orbital values are external-data-owned and may change with MPC updates. No independent orbit oracle is maintained, so no absolute physical-accuracy claim is made. The live snapshot omits `Start`/`Stop` so the server applies its orbital-epoch default window, avoiding fixed windows that could fall before a future MPC orbital epoch and be rejected.
38
40
  - `target_elements` explicit-element branch: `verified` through [`tests/validation/cross_validation/celestial/test_mpc_target_elements.py`](../../tests/validation/cross_validation/celestial/test_mpc_target_elements.py) as an endpoint-to-endpoint invariant: feeding the `OrbitElements` parsed from a name-based Ceres lookup back through `target_elements` reproduces the name-based ephemeris exactly (`ROUNDTRIP_ABS_M = 1e-6`, observed residual 0). This verifies branch wiring, not the absolute ephemeris semantics, which remain external-data-owned.
39
- - `reference_frame` branch: `verified` as a distinguishing pair. The same Ceres elements labelled `EclpJ2000ICRF` (MPC convention, server default) versus `MeanEclpJ2000` (JPL convention) produce ephemerides separated by about 87 km at the maintained 2026-01 window (`FRAME_SEPARATION_MIN_M = 1000`), so the two labels are live, distinguishable branches; the absolute convention of each label is not independently promoted.
41
+ - Output cadence: `verified` on a six-day window derived from the current Ceres element epoch. Omitting `step_s` exactly matches explicit `step_s=86400`; explicit `step_s=172800` returns the exact matching subset of the daily grid; and `step_s=0` returns a distinct, strictly increasing, nonuniform internal grid with the same interval endpoints. The current internal-grid case has four samples, with adjacent intervals from approximately 67137 s to 364863 s. `OUTPUT_GRID_ABS_TOL = 1e-6` is a precision bound for the matching fixed-grid values, whose observed residual is 0. This verifies sampling behavior, not integration accuracy.
42
+ - `reference_frame` branch: `verified` as a distinguishing pair. The same Ceres elements labelled `EclpJ2000ICRF` (MPC convention, server default) versus `MeanEclpJ2000` (JPL convention) produce ephemerides separated by tens of kilometres on the maintained orbit-epoch-derived window (currently about 90 km; `FRAME_SEPARATION_MIN_M = 1000`), so the two labels are live, distinguishable branches; the absolute convention of each label is not independently promoted.
40
43
 
41
44
  ## Lambert transfer windows
42
45
 
43
- Status of `celestial.lambert_transfer_window`: `partial` — the ICRF transfer-state relation for the maintained Earth→Mars grid, the ICRF axis identification of the `RV1`/`RV2` endpoint position directions, the `MinTofDays`/`MaxTofDays`/`MaxDepartureDV`/`MaxArrivalDV` filtering behavior, the DV-magnitude norm invariant, and the `TimeOfFlightDays`/`ArrivalLightAngle` field invariants are `verified`; the MeanEclpJ2000ICRF coordinate relation, the physical endpoint-body-velocity interpretation of `DeltaV`, and the independent Kepler semantics of explicit MPC elements are `unresolved`.
46
+ Status of `celestial.lambert_transfer_window`: `partial` — the server-default frame, the `EclpJ2000ICRF`↔`ICRF` coordinate relation, the ICRF transfer-state relation for the maintained Earth→Mars grid, the ICRF axis identification of the `RV1`/`RV2` endpoint position directions, the `MinTofDays`/`MaxTofDays`/`MaxDepartureDV`/`MaxArrivalDV` filtering behavior, the DV-magnitude norm invariant, and the `TimeOfFlightDays`/`ArrivalLightAngle` field invariants are `verified`; the explicit `MeanEclpJ2000`↔`ICRF` coordinate relation, the physical endpoint-body-velocity interpretation of `DeltaV`, and the independent Kepler semantics of explicit MPC elements are `unresolved`.
44
47
 
45
48
  - ICRF Earth→Mars zero-revolution prograde transfer states: `verified` through [`tests/validation/cross_validation/celestial/test_lambert_transfer_lamberthub.py`](../../tests/validation/cross_validation/celestial/test_lambert_transfer_lamberthub.py). The maintained case compares the complete six UTC departure/arrival timestamp pairs in a 2 departure days × 3 arrival days grid; the independent solver is `lamberthub.izzo2015` with the Sun gravitational parameter (`1.3271244004193938e20 m^3/s^2`), `M=0`, `prograde=True`, and `low_path=True` (a zero-revolution prograde Lambert solution), using the ASTROX `RV1`/`RV2` endpoint positions as its inputs. The ASTROX transfer velocities match the solver within `SOLVER_ABS_TOL_M_S = 1e-6` m/s. The endpoint positions themselves are the solver inputs; their full celestial-state meaning beyond the independently checked directions is not promoted here.
46
- - ICRF endpoint position-direction axis identification: `verified` through [`tests/validation/cross_validation/celestial/test_lambert_transfer_lamberthub.py`](../../tests/validation/cross_validation/celestial/test_lambert_transfer_lamberthub.py). For each of the six maintained Earth→Mars results, the `RV1`/`RV2` position directions at the returned UTC departure/arrival epochs are compared with independent Skyfield DE421 heliocentric Earth/Mars position directions (body-minus-Sun positions at the same epochs). The direct angular-separation maximum is approximately 8.54e-7 deg, within the pre-set `ICRF_AXIS_IDENTIFICATION_MAX_ANGLE_DEG = 0.01`; the best of the fixed ±23.439291111 deg obliquity rotations applied to the independent directions stays at approximately 22.35 deg maximum separation, above `WRONG_FRAME_MIN_SEPARATION_DEG = 1.0`. This verifies only the identification of the ICRF axes for the endpoint position directions — not full numerical-kernel precision, and not the celestial-state meaning of the endpoint positions beyond their direction. The MeanEclpJ2000ICRF coordinate relation, the `DeltaV` physical interpretation, and the explicit MPC-element semantics remain separate `unresolved` items.
49
+ - ICRF endpoint position-direction axis identification: `verified` through [`tests/validation/cross_validation/celestial/test_lambert_transfer_lamberthub.py`](../../tests/validation/cross_validation/celestial/test_lambert_transfer_lamberthub.py). For each of the six maintained Earth→Mars results, the `RV1`/`RV2` position directions at the returned UTC departure/arrival epochs are compared with independent Skyfield DE421 heliocentric Earth/Mars position directions (body-minus-Sun positions at the same epochs). The direct angular-separation maximum is approximately 8.54e-7 deg, within the pre-set `ICRF_AXIS_IDENTIFICATION_MAX_ANGLE_DEG = 0.01`; the best of the fixed ±23.43929111111111 deg obliquity rotations applied to the independent directions stays at approximately 22.35 deg maximum separation, above `WRONG_FRAME_MIN_SEPARATION_DEG = 1.0`. This verifies only the identification of the ICRF axes for the endpoint position directions — not full numerical-kernel precision, and not the celestial-state meaning of the endpoint positions beyond their direction. The explicit `MeanEclpJ2000`↔`ICRF` coordinate relation, the `DeltaV` physical interpretation, and the explicit MPC-element semantics remain separate `unresolved` items.
50
+ - Server-default frame: `verified` on the maintained Earth→Mars grid by exact `TransferResults` equality between omitted `sun_frame` and explicit `sun_frame="EclpJ2000ICRF"`. The default result is distinguishable from explicit `MeanEclpJ2000`, with a current maximum state-vector separation of about 54 km.
51
+ - `EclpJ2000ICRF`↔`ICRF` coordinate relation: `verified` on every `RV1`, `RV2`, `DeltaV1`, and `DeltaV2` vector in the maintained grid. A fixed 23.43929111111111° J2000 mean-obliquity rotation reproduces the ecliptic output from the independently anchored ICRF output within `ECLIPTIC_RELATION_POSITION_ABS_TOL_M = 1e-3 m` and `ECLIPTIC_RELATION_VELOCITY_ABS_TOL_M_S = 1e-9 m/s`; current maximum residuals are approximately 3.1e-5 m and 1.1e-11 m/s.
47
52
  - `MinTofDays` filtering: `verified` on a fixed 2×2 Earth→Mars sampling grid (departure 2028-06-01/06-03, arrival 2028-06-05/06-15, `departure_step_days=2.0`, `arrival_step_days=10.0`, `sun_frame="ICRF"`) by exact timestamp-pair comparison: with `min_time_of_flight_days=1` the response contains all four pairs (transfer times of 2, 4, 12, and 14 days), and with `min_time_of_flight_days=10` exactly the 12- and 14-day pairs remain. The evidence covers these two thresholds on this grid only; no other threshold values or grids are covered. Since 2026-08-20 the short-window grid requires explicit wide `MaxDepartureDV`/`MaxArrivalDV` bounds (its transfers need up to about 2e6 m/s), because the server now applies default ΔV/TOF filters.
48
53
  - `MaxTofDays`/`MaxDepartureDV`/`MaxArrivalDV` filtering: `verified` on the maintained 2×3 ICRF grid since 2026-08-20. Each bound retains exactly the pairs whose maintained `DV1_Mag`/`DV2_Mag`/timestamp-delta values satisfy it (`max_departure_delta_v_m_s=15000` retains the three 2028-06-03 departures, `max_arrival_delta_v_m_s=5500` retains the three 2028-06-03 arrivals, `max_time_of_flight_days=304` retains the four pairs with TOF ≤ 304 days), and each retained set is strictly smaller than the unfiltered grid, so the fixtures remain distinguishing. The server defaults (10000 m/s departure and arrival, 500 days) filter the maintained grid to zero results, so the maintained fixtures pass explicit wide bounds (`10000000` m/s, `1000` days).
49
54
  - `TimeOfFlightDays` field: `verified` since 2026-08-20 as the exact day delta between `ArrivalTime` and `DepartureTime` (abs tol 1e-9 days) on the maintained grid.
50
55
  - `ArrivalLightAngle` field: `verified` since 2026-08-20 as the angle in degrees between `DeltaV2` and the `RV2` position vector (abs tol 1e-9 deg, observed residuals at machine precision) on the maintained grid.
51
56
  - DV magnitude norm invariant: `verified` on the same maintained grid — `DV1_Mag`/`DV2_Mag` equal the Euclidean norms of `DeltaV1`/`DeltaV2` within `NORM_REL_TOL = 1e-12` and `NORM_ABS_TOL_M_S = 1e-9` m/s.
52
- - MeanEclpJ2000 ↔ ICRF exact relationship: `unresolved`. Fixed mean-obliquity rotations (±23.439291111 deg) applied to the ICRF transfer states do not explain the MeanEclpJ2000 states. The comparison is retained as a strict calibration xfail; `FRAME_POSITION_DIAGNOSTIC_TOL_M = 1 m` and `FRAME_VELOCITY_DIAGNOSTIC_TOL_M_S = 1e-6 m/s` are diagnostic thresholds, not passing tolerances, and the xfail note explicitly says they must not be widened to absorb the unknown frame relation.
57
+ - Explicit MeanEclpJ2000 ↔ ICRF exact relationship: `unresolved`. Fixed mean-obliquity rotations (±23.43929111111111 deg) applied to the ICRF transfer states do not explain the explicit `MeanEclpJ2000` states. The comparison is retained as a strict calibration xfail; `MEAN_FRAME_POSITION_DIAGNOSTIC_TOL_M = 1 m` and `MEAN_FRAME_VELOCITY_DIAGNOSTIC_TOL_M_S = 1e-6 m/s` are diagnostic thresholds, not passing tolerances, and the xfail note explicitly says they must not be widened to absorb the unknown frame relation.
53
58
  - `DeltaV` physical interpretation: `unresolved`. The route does not return the endpoint bodies' velocity convention, so a Skyfield DE421-based endpoint-body-velocity interpretation of `DeltaV1`/`DeltaV2` is retained as a strict calibration xfail with an unexplained residual.
54
59
  - Explicit MPC-element independent Kepler semantics: `unresolved`. A local standard elliptic Kepler propagation of the supplied MPC elements (both mean-anomaly-epoch and periapsis-time variants) does not reproduce the ASTROX arrival states; the server's exact element frame and time convention is not identified. The 2026-08-20 `ReferenceFrame` element option was probed with both `EclpJ2000ICRF` and `MeanEclpJ2000` and does not change this route's arrival states, so it does not resolve the convention. The comparison is a strict calibration xfail with `ELEMENT_POSITION_DIAGNOSTIC_TOL_M = 1 m` as a diagnostic threshold.
55
- - Response structure: `verified` through live snapshots for the Earth→Mars server-default-frame case and the Earth→2015 XF261 explicit-elements ICRF case — `TransferResults` is a non-empty array, and each entry carries `DepartureTime`/`ArrivalTime` strings, `DeltaV1`/`DeltaV2` numeric 3-vectors, `DV1_Mag`/`DV2_Mag` numbers, `RV1`/`RV2` numeric 6-vectors, and (since 2026-08-20) `TimeOfFlightDays`/`ArrivalLightAngle` numbers. Both snapshot cases pass explicit wide filter bounds because the 2026-08-20 server defaults would filter the maintained grids to zero results.
60
+ - Response structure: `verified` through live snapshots for the Earth→Mars server-default-`EclpJ2000ICRF` case and the Earth→2015 XF261 explicit-elements ICRF case — `TransferResults` is a non-empty array, and each entry carries `DepartureTime`/`ArrivalTime` strings, `DeltaV1`/`DeltaV2` numeric 3-vectors, `DV1_Mag`/`DV2_Mag` numbers, `RV1`/`RV2` numeric 6-vectors, and (since 2026-08-20) `TimeOfFlightDays`/`ArrivalLightAngle` numbers. Both snapshot cases pass explicit wide filter bounds because the 2026-08-20 server defaults would filter the maintained grids to zero results.
56
61
 
57
62
  ## Live snapshot coverage
58
63
 
59
- The celestial functions are exercised in [`tests/validation/live_snapshot/celestial/test_celestial.py`](../../tests/validation/live_snapshot/celestial/test_celestial.py), with sidecar [`tests/validation/live_snapshot/celestial/celestial.snap.json`](../../tests/validation/live_snapshot/celestial/celestial.snap.json) covering `ephemeris` (Moon, explicit window), `cb_axes_rotation` (order 0 and 1), `mpc_ephemeris` (Ceres, server-owned default window), and `lambert_transfer_window` (Earth→Mars with the server-default frame, and Earth→2015 XF261 with explicit MPC elements and `sun_frame="ICRF"`). The snapshots freeze recursive nested type/layout descriptors: per-field value kinds, the CZML `cartesianVelocity` 7-value grouping, the order-dependent `Rotation` lengths (4 for `order=0`, 7 for `order=1`), the MPC `OrbitElements` key set (including `ReferenceFrame` since 2026-08-20), and the transfer-result grid with its `DeltaV` 3-vector and `RV` 6-vector layouts plus the `TimeOfFlightDays`/`ArrivalLightAngle` numbers (since 2026-08-20); volatile numeric values are not frozen, and the MPC numeric values remain external-data-owned. Curated returns remove the transport status wrapper fields `IsSuccess`/`Message`, so the frozen shapes contain only server data fields. These live snapshots are drift detectors for the response shape of maintained public inputs.
64
+ The celestial functions are exercised in [`tests/validation/live_snapshot/celestial/test_celestial.py`](../../tests/validation/live_snapshot/celestial/test_celestial.py), with sidecar [`tests/validation/live_snapshot/celestial/celestial.snap.json`](../../tests/validation/live_snapshot/celestial/celestial.snap.json) covering `ephemeris` (Moon, explicit window), `cb_axes_rotation` (order 0 and 1), `mpc_ephemeris` (Ceres, server-owned default window), and `lambert_transfer_window` (Earth→Mars with the server-default `EclpJ2000ICRF` frame, and Earth→2015 XF261 with explicit MPC elements and `sun_frame="ICRF"`). The snapshots freeze recursive nested type/layout descriptors: per-field value kinds, the CZML `cartesianVelocity` 7-value grouping, the order-dependent `Rotation` lengths (4 for `order=0`, 7 for `order=1`), the MPC `OrbitElements` key set (including `ReferenceFrame` since 2026-08-20), and the transfer-result grid with its `DeltaV` 3-vector and `RV` 6-vector layouts plus the `TimeOfFlightDays`/`ArrivalLightAngle` numbers (since 2026-08-20); volatile numeric values are not frozen, and the MPC numeric values remain external-data-owned. Curated returns remove the transport status wrapper fields `IsSuccess`/`Message`, so the frozen shapes contain only server data fields. These live snapshots are drift detectors for the response shape of maintained public inputs.
60
65
 
61
66
  Cross-validation scripts:
62
67
  - [`tests/validation/cross_validation/celestial/test_ephemeris_skyfield.py`](../../tests/validation/cross_validation/celestial/test_ephemeris_skyfield.py)
@@ -1,6 +1,6 @@
1
1
  # Libration validation
2
2
 
3
- This page registers the live-contract and semantic evidence for `astrox.libration`. The primary comparison path is an independently written circular restricted three-body problem (CRTBP) model: bracketed equilibrium roots, closed-form unit scales, DOP853 integration, Jacobi conservation, symmetry-plane crossings, and full-period closure. Orekit 13.1 and e2m2e 5.6.8 provide separately qualified secondary comparisons; neither package is treated as an oracle. The exact e2m2e release is a development dependency because it is used only by maintained validation, not by the runtime SDK.
3
+ This page registers the live-contract and semantic evidence for `astrox.libration`. The primary comparison path is an independently written circular restricted three-body problem (CRTBP) model: bracketed equilibrium roots, closed-form unit scales, DOP853 integration, Jacobi conservation, symmetry-plane crossings, and full-period closure. Orekit 13.1 and the e2m2e release pinned in [`pyproject.toml`](../../pyproject.toml) provide separately qualified secondary comparisons; neither package is treated as an oracle. e2m2e is used only by maintained validation, not by the runtime SDK, and its behavior is qualified directly instead of duplicating its pinned version in the test contract.
4
4
 
5
5
  | Surface | Status | Primary evidence | Secondary evidence |
6
6
  | --- | --- | --- | --- |
@@ -12,7 +12,7 @@ STOP = "2026-01-02T00:00:00.000Z"
12
12
 
13
13
 
14
14
  def main() -> None:
15
- for frame in ("J2000", "MeanEclpJ2000"):
15
+ for frame in ("J2000", "MeanEclpJ2000", "EclpJ2000ICRF"):
16
16
  ephemeris = celestial.ephemeris(
17
17
  target_name="Moon",
18
18
  start=START,
@@ -34,7 +34,7 @@ def main() -> None:
34
34
  )
35
35
  print(f"Earth→Moon 旋转: {len(rotation['Rotation'])} 个数值")
36
36
 
37
- mpc = celestial.mpc_ephemeris(target_name="Ceres")
37
+ mpc = celestial.mpc_ephemeris(target_name="Ceres", step_s=172800.0)
38
38
  print(f"Ceres MPC 星历: {len(mpc['Position']['cartesianVelocity']) // 7} 个状态样本")
39
39
 
40
40
  transfer = celestial.lambert_transfer_window(
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "astrox-python"
7
- version = "1.1.0"
7
+ version = "1.2.0"
8
8
  description = "Python SDK for the ASTROX Web API."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -59,7 +59,7 @@ dev = [
59
59
  "astropy>=6.1.7",
60
60
  "spiceypy>=8.1.2",
61
61
  "scipy>=1.14",
62
- "e2m2e==5.6.10",
62
+ "e2m2e==5.8.5",
63
63
  ]
64
64
 
65
65
  [tool.hatch.build.targets.wheel]
@@ -189,6 +189,7 @@ def test_mpc_ephemeris_lowers_optional_arguments(
189
189
  observer_frame="topocentric",
190
190
  start=START,
191
191
  stop=STOP,
192
+ step_s=3600.0,
192
193
  )
193
194
 
194
195
  assert_canonical_equal(
@@ -200,11 +201,28 @@ def test_mpc_ephemeris_lowers_optional_arguments(
200
201
  "ObserverFrame": "topocentric",
201
202
  "Start": START,
202
203
  "Stop": STOP,
204
+ "Step": 3600.0,
203
205
  },
204
206
  },
205
207
  )
206
208
 
207
209
 
210
+ def test_mpc_ephemeris_preserves_zero_step(
211
+ monkeypatch: pytest.MonkeyPatch,
212
+ ) -> None:
213
+ calls = record_raw_post(monkeypatch, RESPONSE)
214
+
215
+ celestial.mpc_ephemeris(target_name="Ceres", step_s=0)
216
+
217
+ assert_canonical_equal(
218
+ calls[0],
219
+ {
220
+ "endpoint": "/celestial/mpc",
221
+ "json": {"TargetName": "Ceres", "Step": 0.0},
222
+ },
223
+ )
224
+
225
+
208
226
  def test_mpc_ephemeris_omits_none_optional_arguments(
209
227
  monkeypatch: pytest.MonkeyPatch,
210
228
  ) -> None:
@@ -215,6 +233,7 @@ def test_mpc_ephemeris_omits_none_optional_arguments(
215
233
  observer_frame=None,
216
234
  start=START,
217
235
  stop=None,
236
+ step_s=None,
218
237
  )
219
238
 
220
239
  assert_canonical_equal(
@@ -242,6 +261,7 @@ def test_mpc_ephemeris_omits_none_optional_arguments(
242
261
  "order",
243
262
  ),
244
263
  (celestial.mpc_ephemeris, {"target_name": 1}, "target_name"),
264
+ (celestial.mpc_ephemeris, {"target_name": "Ceres", "step_s": True}, "step_s"),
245
265
  ],
246
266
  )
247
267
  def test_celestial_rejects_mistyped_arguments(
@@ -97,3 +97,18 @@ Run calibration diagnostics:
97
97
  ```bash
98
98
  ASTROX_BASE_URL=http://astrox.cn:8765 GMAT_VALIDATION_IMAGE=ghcr.io/<owner>/astrox-gmat-validation:gmat-r2026a ASTROX_EXTERNAL_VALIDATION=strict uv run python -m pytest tests/validation -m calibration --runxfail
99
99
  ```
100
+
101
+ ## Local Runtime
102
+
103
+ A local ASTROX WebApi runtime, when available, is a triage and debugging convenience: it removes latency and load concerns from the shared live server, so broader exploratory probing is allowed against it (see `docs/test-principles.md`). All live validation scripts accept it through the same environment variable:
104
+
105
+ ```bash
106
+ ASTROX_BASE_URL=http://127.0.0.1:8765 uv run python -m pytest tests/validation/cross_validation/propagator
107
+ ```
108
+
109
+ Rules for local-runtime work:
110
+
111
+ - Bind the local runtime to `127.0.0.1` only; do not expose it on the network.
112
+ - The local runtime is not a source of truth. Its version may lag or differ from the live server; before a locally obtained result becomes a committed snapshot, test, or evidence claim, re-confirm it against the live server, and record the local runtime's version in investigation notes when it matters.
113
+ - Never refresh a committed snapshot against the local runtime.
114
+ - The local runtime distribution is private and ignored by git; do not commit it or reference its local path from committed files.
@@ -7,6 +7,8 @@
7
7
  # Earth and Moon at two explicit epochs
8
8
  # - Earth INERTIAL -> FIXED order 0/1: verified against an independent ERFA
9
9
  # Earth-orientation construction at two epochs
10
+ # - Earth same-body EclpJ2000ICRF -> ICRF order 0/1: verified against the
11
+ # analytic J2000 mean-obliquity rotation at two epochs
10
12
  # - Earth -> Moon INERTIAL -> FIXED order 1 angular velocity: verified against
11
13
  # an independent SPICE Moon orientation derivative at two epochs
12
14
  # - Earth -> Moon INERTIAL -> FIXED quaternion: unresolved; the SPICE DE440
@@ -18,6 +20,7 @@
18
20
  # - Earth quaternion and angular velocity: verified against ERFA
19
21
  # - Moon order-1 angular velocity: verified against SPICE
20
22
  # - Moon fixed quaternion: unresolved after an independent model comparison
23
+ # - EclpJ2000ICRF quaternion and zero angular velocity: verified analytically
21
24
  # Parameters:
22
25
  # - central-body/frame combinations above
23
26
  # - order 0 and 1 where the branch exposes both
@@ -29,6 +32,7 @@
29
32
  # - Moon oracle: SPICE J2000 -> IAU_MOON transform and xf2rav angular velocity
30
33
  # from the maintained public PCK/DE440 data; the quaternion residual is kept
31
34
  # unresolved instead of absorbed by a loose tolerance
35
+ # - Ecliptic oracle: fixed rotation by the standard J2000 mean obliquity
32
36
  # - Tolerances: matrix 1e-8, angular velocity 1e-10 rad/s, identity 1e-12;
33
37
  # these are precision bounds for independent comparisons, not model-fit
34
38
  # envelopes
@@ -63,6 +67,7 @@ ABS_TOL = 1.0e-12
63
67
  MATRIX_ABS_TOL = 1.0e-8
64
68
  ANGULAR_VELOCITY_ABS_TOL = 1.0e-10
65
69
  QUATERNION_RESOLUTION_DEG = 1.0e-6
70
+ J2000_MEAN_OBLIQUITY_DEG = 23.43929111111111
66
71
 
67
72
 
68
73
  class CrossValidationError(Exception):
@@ -166,7 +171,7 @@ def _assert_rotation_matrix_matches(
166
171
  expected_matrix: np.ndarray,
167
172
  *,
168
173
  label: str,
169
- ) -> None:
174
+ ) -> float:
170
175
  actual_matrix = Rotation.from_quat(actual_rotation[:4]).as_matrix()
171
176
  error = float(np.max(np.abs(actual_matrix - expected_matrix)))
172
177
  if error > MATRIX_ABS_TOL:
@@ -174,6 +179,7 @@ def _assert_rotation_matrix_matches(
174
179
  f"{label} rotation matrix residual={error:.12g}, "
175
180
  f"exceeds {MATRIX_ABS_TOL:g}"
176
181
  )
182
+ return error
177
183
 
178
184
 
179
185
  def test_same_body_inertial_rotations_are_identity() -> None:
@@ -219,6 +225,51 @@ def test_earth_inertial_to_fixed_matches_erfa() -> None:
219
225
  )
220
226
 
221
227
 
228
+ def _icrf_to_eclp_j2000_matrix() -> np.ndarray:
229
+ obliquity = math.radians(J2000_MEAN_OBLIQUITY_DEG)
230
+ return np.array(
231
+ [
232
+ [1.0, 0.0, 0.0],
233
+ [0.0, math.cos(obliquity), math.sin(obliquity)],
234
+ [0.0, -math.sin(obliquity), math.cos(obliquity)],
235
+ ]
236
+ )
237
+
238
+
239
+ def test_eclp_j2000_icrf_rotation_matches_mean_obliquity() -> None:
240
+ configure_astrox_from_env()
241
+ expected_matrix = _icrf_to_eclp_j2000_matrix()
242
+ residuals: list[float] = []
243
+ for epoch in EPOCHS:
244
+ for order in (0, 1):
245
+ actual = rotation_response(
246
+ from_central_body="Earth",
247
+ to_central_body="Earth",
248
+ epoch=epoch,
249
+ from_frame="EclpJ2000ICRF",
250
+ to_frame="ICRF",
251
+ order=order,
252
+ )
253
+ residuals.append(
254
+ _assert_rotation_matrix_matches(
255
+ actual,
256
+ expected_matrix,
257
+ label=f"Earth/EclpJ2000ICRF->ICRF/{epoch}/order={order}",
258
+ )
259
+ )
260
+ if order == 1 and not np.allclose(
261
+ actual[4:],
262
+ 0.0,
263
+ atol=ABS_TOL,
264
+ rtol=0.0,
265
+ ):
266
+ raise CrossValidationError(
267
+ "fixed EclpJ2000ICRF/ICRF relation returned nonzero angular "
268
+ f"velocity at {epoch}: {actual[4:].tolist()}"
269
+ )
270
+ print(f"ECLIPTIC_ROTATION_MAX_MATRIX_RESIDUAL={max(residuals):.12g}")
271
+
272
+
222
273
  def _moon_inertial_to_fixed_matrix(time: Time) -> np.ndarray:
223
274
  import spiceypy as spice
224
275
 
@@ -299,11 +350,12 @@ def main() -> int:
299
350
  try:
300
351
  test_same_body_inertial_rotations_are_identity()
301
352
  test_earth_inertial_to_fixed_matches_erfa()
353
+ test_eclp_j2000_icrf_rotation_matches_mean_obliquity()
302
354
  test_earth_moon_inertial_to_fixed_angular_velocity_matches_spice()
303
355
  except Exception as exc:
304
356
  print(f"CROSS_VALIDATION_FAILED={type(exc).__name__}: {exc}", file=sys.stderr)
305
357
  return 1
306
- print("CROSS_VALIDATION_CHECKED=14")
358
+ print("CROSS_VALIDATION_CHECKED=18")
307
359
  print("CROSS_VALIDATION_FAILED=0")
308
360
  return 0
309
361