spectro-kernel 0.6.2__tar.gz → 0.7.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 (366) hide show
  1. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/.gitignore +1 -0
  2. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/CHANGELOG.md +240 -0
  3. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/PKG-INFO +11 -1
  4. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/README.md +10 -0
  5. spectro_kernel-0.7.0/docs/.drafts/README.md +7 -0
  6. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/concepts/pipelines.md +6 -1
  7. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/notebooks/be-star-variability.md +2 -2
  8. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/notebooks/claude-mcp-end-to-end.md +1 -1
  9. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/notebooks/full-reduction-walkthrough.md +30 -20
  10. spectro_kernel-0.7.0/docs/recipes/format.md +163 -0
  11. spectro_kernel-0.7.0/docs/recipes/index.md +125 -0
  12. spectro_kernel-0.7.0/docs/recipes/share.md +88 -0
  13. spectro_kernel-0.7.0/docs/tutorials/long-slit-reduction.md +299 -0
  14. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/usage/cli.md +20 -5
  15. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/usage/mcp.md +2 -2
  16. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/why.md +1 -1
  17. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/activity/_bands.py +128 -0
  18. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/activity/activity_index_caii_hk.py +313 -0
  19. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/activity/activity_index_halpha.py +160 -0
  20. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/activity/ccf_bisector.py +404 -0
  21. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/catalogs/standard_star.py +426 -0
  22. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/continuum/normalize_edges.py +7 -2
  23. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/continuum/normalize_max.py +10 -1
  24. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/continuum/normalize_percentile.py +11 -4
  25. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/continuum/normalize_polynomial.py +11 -12
  26. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/continuum/normalize_region.py +7 -2
  27. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/continuum/normalize_spline.py +286 -0
  28. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/corrections/atmospheric_extinction.py +483 -0
  29. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/corrections/deredden_interstellar.py +187 -0
  30. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/io/read_fits.py +153 -0
  31. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/kinematics/vsini_fourier.py +425 -0
  32. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/nebular/balmer_decrement_extinction.py +333 -0
  33. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/quality/measure_resolving_power.py +281 -0
  34. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/smoothing/_kernel_uncertainty.py +122 -0
  35. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/smoothing/smooth_gaussian.py +28 -5
  36. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/smoothing/smooth_savgol.py +22 -5
  37. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/stacking/stack.py +213 -0
  38. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/timeseries/_light_curve.py +60 -0
  39. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/timeseries/box_least_squares.py +265 -0
  40. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/timeseries/phase_dispersion_minimization.py +226 -0
  41. spectro_kernel-0.7.0/src/spectro_kernel/algorithms/timeseries/temporal_variance_spectrum.py +287 -0
  42. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/transforms/combine_arithmetic.py +79 -9
  43. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/transforms/resample.py +23 -3
  44. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/cli.py +122 -5
  45. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/errors.py +4 -0
  46. spectro_kernel-0.7.0/src/spectro_kernel/io/fits.py +914 -0
  47. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/pipeline.py +97 -13
  48. spectro_kernel-0.7.0/src/spectro_kernel/presets/__init__.py +37 -0
  49. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/presets/catalog/analysis/balmer_quick.yaml +2 -0
  50. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/presets/catalog/analysis/embed_quick.yaml +2 -0
  51. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/presets/catalog/analysis/quality_report.yaml +2 -0
  52. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/presets/catalog/analysis/rv_quick.yaml +2 -0
  53. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/presets/catalog/analysis/snr_check.yaml +2 -0
  54. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/presets/catalog/analysis/time_series_overview.yaml +2 -0
  55. spectro_kernel-0.7.0/src/spectro_kernel/presets/catalog/reduction/full_reduction_easyspec.yaml +113 -0
  56. spectro_kernel-0.7.0/src/spectro_kernel/presets/loader.py +351 -0
  57. spectro_kernel-0.7.0/src/spectro_kernel/presets/preset.schema.json +65 -0
  58. spectro_kernel-0.7.0/src/spectro_kernel/presets/variables.py +265 -0
  59. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/types/enums.py +2 -0
  60. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/version.py +1 -1
  61. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_mcp/auto_tools.py +18 -6
  62. spectro_kernel-0.7.0/src/spectro_mcp/py.typed +0 -0
  63. spectro_kernel-0.7.0/tests/unit/test_activity_bisector.py +174 -0
  64. spectro_kernel-0.7.0/tests/unit/test_activity_caii_hk.py +144 -0
  65. spectro_kernel-0.7.0/tests/unit/test_activity_halpha.py +81 -0
  66. spectro_kernel-0.7.0/tests/unit/test_combine.py +236 -0
  67. spectro_kernel-0.7.0/tests/unit/test_flux_atmospheric_extinction.py +270 -0
  68. spectro_kernel-0.7.0/tests/unit/test_flux_balmer_decrement.py +170 -0
  69. spectro_kernel-0.7.0/tests/unit/test_flux_deredden_interstellar.py +134 -0
  70. spectro_kernel-0.7.0/tests/unit/test_flux_standard_star_reference.py +373 -0
  71. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_io.py +33 -0
  72. spectro_kernel-0.7.0/tests/unit/test_io_fits_zoo.py +476 -0
  73. spectro_kernel-0.7.0/tests/unit/test_normalize_spline.py +124 -0
  74. spectro_kernel-0.7.0/tests/unit/test_presets.py +366 -0
  75. spectro_kernel-0.7.0/tests/unit/test_resolving_power.py +151 -0
  76. spectro_kernel-0.7.0/tests/unit/test_timeseries_bls.py +157 -0
  77. spectro_kernel-0.7.0/tests/unit/test_timeseries_pdm.py +133 -0
  78. spectro_kernel-0.7.0/tests/unit/test_timeseries_tvs.py +210 -0
  79. spectro_kernel-0.7.0/tests/unit/test_uncertainty_propagation.py +331 -0
  80. spectro_kernel-0.7.0/tests/unit/test_vsini_fourier.py +200 -0
  81. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tools/docs/build.py +16 -4
  82. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tools/docs/generate.py +3 -1
  83. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tools/docs/generate_catalogue.py +4 -1
  84. spectro_kernel-0.7.0/tools/docs/generate_recipes.py +300 -0
  85. spectro_kernel-0.6.2/docs/cookbook/bess-dashboard.md +0 -118
  86. spectro_kernel-0.6.2/docs/tutorials/long-slit-reduction.md +0 -171
  87. spectro_kernel-0.6.2/src/spectro_kernel/algorithms/io/read_fits.py +0 -53
  88. spectro_kernel-0.6.2/src/spectro_kernel/algorithms/stacking/stack.py +0 -110
  89. spectro_kernel-0.6.2/src/spectro_kernel/io/fits.py +0 -345
  90. spectro_kernel-0.6.2/src/spectro_kernel/presets/__init__.py +0 -7
  91. spectro_kernel-0.6.2/src/spectro_kernel/presets/catalog/reduction/full_reduction_easyspec.yaml +0 -68
  92. spectro_kernel-0.6.2/src/spectro_kernel/presets/loader.py +0 -83
  93. spectro_kernel-0.6.2/tests/unit/test_combine.py +0 -118
  94. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/LICENSE +0 -0
  95. {spectro_kernel-0.6.2/docs → spectro_kernel-0.7.0/docs/.drafts}/notebooks/aurora-line-monitor.md +0 -0
  96. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/concepts/algorithms.md +0 -0
  97. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/concepts/architecture.md +0 -0
  98. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/concepts/data-types.md +0 -0
  99. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/contributing.md +0 -0
  100. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/cookbook/multi-star-viewer.md +0 -0
  101. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/cookbook/web-playground.md +0 -0
  102. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/getting-started.md +0 -0
  103. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_cyg_ew_timeseries.png +0 -0
  104. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_cyg_halpha_phase_stack.png +0 -0
  105. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_cyg_halpha_timeseries.png +0 -0
  106. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_cyg_overlay.png +0 -0
  107. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_cyg_pc1_vs_phase.png +0 -0
  108. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_cyg_pca_2d.png +0 -0
  109. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_cyg_pca_3d.png +0 -0
  110. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_cyg_periodogram.png +0 -0
  111. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_cyg_phase_folded.png +0 -0
  112. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_cyg_rv_timeseries.png +0 -0
  113. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_cyg_similarity.png +0 -0
  114. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_cyg_similarity_date.png +0 -0
  115. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_dra_halpha_phase_stack.png +0 -0
  116. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_dra_pc1_vs_phase.png +0 -0
  117. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_dra_pca_2d.png +0 -0
  118. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_dra_pca_3d.png +0 -0
  119. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_dra_periodogram.png +0 -0
  120. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_dra_phase_folded.png +0 -0
  121. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_dra_rv_timeseries.png +0 -0
  122. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_dra_similarity_date.png +0 -0
  123. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/images/notebooks/alpha_dra_similarity_phase.png +0 -0
  124. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/index.md +0 -0
  125. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/notebooks/alpha-cyg-time-series.md +0 -0
  126. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/notebooks/alpha-dra-binary-period.md +0 -0
  127. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/notebooks/exoplanet-transit-rv.md +0 -0
  128. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/notebooks/native-vs-easyspec-showdown.md +0 -0
  129. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/notebooks/your-first-sb2.md +0 -0
  130. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/reference.md +0 -0
  131. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/tutorials/add-an-algorithm.md +0 -0
  132. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/tutorials/analyse-a-spectrum.md +0 -0
  133. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/tutorials/discover-the-catalogue.md +0 -0
  134. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/tutorials/first-spectrum.md +0 -0
  135. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/docs/usage/library.md +0 -0
  136. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/pyproject.toml +0 -0
  137. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/__init__.py +0 -0
  138. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/adapters/__init__.py +0 -0
  139. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/adapters/easyspec.py +0 -0
  140. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/__init__.py +0 -0
  141. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/_common.py +0 -0
  142. {spectro_kernel-0.6.2/src/spectro_kernel/algorithms/classification → spectro_kernel-0.7.0/src/spectro_kernel/algorithms/activity}/__init__.py +0 -0
  143. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/advanced/__init__.py +0 -0
  144. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/advanced/aperture_photometry.py +0 -0
  145. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/advanced/disentangle_sb2.py +0 -0
  146. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/advanced/doppler_tomogram.py +0 -0
  147. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/catalogs/__init__.py +0 -0
  148. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/catalogs/gaia.py +0 -0
  149. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/catalogs/simbad.py +0 -0
  150. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/catalogs/vizier.py +0 -0
  151. {spectro_kernel-0.6.2/src/spectro_kernel/algorithms/embedding → spectro_kernel-0.7.0/src/spectro_kernel/algorithms/classification}/__init__.py +0 -0
  152. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/classification/classify_template_chi2.py +0 -0
  153. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/classification/pickles_atlas.py +0 -0
  154. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/continuum/__init__.py +0 -0
  155. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/continuum/compare_normalisations.py +0 -0
  156. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/continuum/subtract_continuum.py +0 -0
  157. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/corrections/__init__.py +0 -0
  158. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/corrections/air_vacuum.py +0 -0
  159. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/corrections/barycentric.py +0 -0
  160. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/corrections/doppler_shift.py +0 -0
  161. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/corrections/extinction_correct_easyspec.py +0 -0
  162. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/corrections/fit_telluric_scaling.py +0 -0
  163. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/corrections/flux_calibrate_easyspec.py +0 -0
  164. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/corrections/remove_telluric.py +0 -0
  165. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/corrections/response_from_standard.py +0 -0
  166. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/corrections/synth_telluric.py +0 -0
  167. {spectro_kernel-0.6.2/src/spectro_kernel/algorithms/kinematics → spectro_kernel-0.7.0/src/spectro_kernel/algorithms/embedding}/__init__.py +0 -0
  168. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/embedding/embed_band_power.py +0 -0
  169. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/embedding/embed_continuum_subtracted.py +0 -0
  170. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/embedding/embed_lick_indices.py +0 -0
  171. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/embedding/embed_log_lambda.py +0 -0
  172. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/embedding/embed_pretrained.py +0 -0
  173. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/embedding/embed_remote.py +0 -0
  174. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/embedding/embed_spectrum.py +0 -0
  175. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/embedding/embed_wavelets.py +0 -0
  176. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/exports/__init__.py +0 -0
  177. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/exports/_bess_contract.py +0 -0
  178. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/exports/export_csv.py +0 -0
  179. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/exports/export_fits.py +0 -0
  180. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/exports/export_fits_bess.py +0 -0
  181. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/exports/export_hdf5.py +0 -0
  182. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/exports/export_votable.py +0 -0
  183. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/extraction/__init__.py +0 -0
  184. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/extraction/boxcar.py +0 -0
  185. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/extraction/detect_trace.py +0 -0
  186. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/extraction/easyspec_extract.py +0 -0
  187. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/extraction/optimal.py +0 -0
  188. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/extraction/sky_lateral_bands.py +0 -0
  189. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/io/__init__.py +0 -0
  190. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/io/read_ascii.py +0 -0
  191. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/io/read_echelle.py +0 -0
  192. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/io/read_sdss.py +0 -0
  193. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/io/read_votable.py +0 -0
  194. {spectro_kernel-0.6.2/src/spectro_kernel/algorithms/nebular → spectro_kernel-0.7.0/src/spectro_kernel/algorithms/kinematics}/__init__.py +0 -0
  195. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/kinematics/rotation_curve.py +0 -0
  196. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/lines/__init__.py +0 -0
  197. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/lines/_line_flux.py +0 -0
  198. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/lines/_profiles.py +0 -0
  199. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/lines/catalogs.py +0 -0
  200. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/lines/compare_line_fits.py +0 -0
  201. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/lines/detect.py +0 -0
  202. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/lines/equivalent_width.py +0 -0
  203. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/lines/fit_gaussian.py +0 -0
  204. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/lines/fit_lorentzian.py +0 -0
  205. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/lines/fit_voigt.py +0 -0
  206. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/lines/vr_ratio.py +0 -0
  207. /spectro_kernel-0.6.2/src/spectro_kernel/py.typed → /spectro_kernel-0.7.0/src/spectro_kernel/algorithms/nebular/__init__.py +0 -0
  208. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/nebular/bpt_line_ratios.py +0 -0
  209. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/nebular/oiii_electron_temperature.py +0 -0
  210. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/nebular/sii_electron_density.py +0 -0
  211. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/quality/__init__.py +0 -0
  212. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/quality/compare_snr_methods.py +0 -0
  213. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/quality/snr_der.py +0 -0
  214. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/quality/snr_edge.py +0 -0
  215. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/quality/snr_linear_fit.py +0 -0
  216. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/quality/validate_bess_header.py +0 -0
  217. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/__init__.py +0 -0
  218. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/_easyspec_apply.py +0 -0
  219. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/_easyspec_helpers.py +0 -0
  220. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/bias_combine.py +0 -0
  221. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/clip_cosmic_rays.py +0 -0
  222. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/dark_combine.py +0 -0
  223. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/dark_subtract.py +0 -0
  224. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/denoise_2d.py +0 -0
  225. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/easyspec_bias.py +0 -0
  226. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/easyspec_cosmic_ray.py +0 -0
  227. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/easyspec_dark.py +0 -0
  228. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/easyspec_flat.py +0 -0
  229. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/easyspec_flat_normalize.py +0 -0
  230. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/easyspec_subtract_bias.py +0 -0
  231. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/easyspec_subtract_dark.py +0 -0
  232. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/extract_spectrum_sum.py +0 -0
  233. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/flat_combine.py +0 -0
  234. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/flat_normalize.py +0 -0
  235. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/geometry.py +0 -0
  236. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/subtract_sky_2d.py +0 -0
  237. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/reduction/wavelength_calibrate.py +0 -0
  238. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/rv/__init__.py +0 -0
  239. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/rv/cross_correlate.py +0 -0
  240. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/rv/fit_keplerian_orbit.py +0 -0
  241. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/rv/measure.py +0 -0
  242. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/rv/precision_bouchy.py +0 -0
  243. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/rv/redshift_lines.py +0 -0
  244. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/smoothing/__init__.py +0 -0
  245. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/smoothing/_nan_bridge.py +0 -0
  246. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/smoothing/compare_smoothings.py +0 -0
  247. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/stacking/__init__.py +0 -0
  248. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/stacking/merge_echelle_orders.py +0 -0
  249. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/timeseries/__init__.py +0 -0
  250. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/timeseries/lomb_scargle.py +0 -0
  251. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/timeseries/phase_fold.py +0 -0
  252. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/transforms/__init__.py +0 -0
  253. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/transforms/clip_sigma.py +0 -0
  254. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/transforms/extract_region.py +0 -0
  255. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/transforms/mask_range.py +0 -0
  256. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/transforms/resample_flux_conserving.py +0 -0
  257. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/viz/__init__.py +0 -0
  258. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/viz/plot_3d_surface.py +0 -0
  259. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/viz/plot_animation.py +0 -0
  260. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/viz/plot_dynamic_spectrum.py +0 -0
  261. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/viz/plot_plotly.py +0 -0
  262. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/wavelength_calibration/__init__.py +0 -0
  263. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/wavelength_calibration/arc_geometry.py +0 -0
  264. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/wavelength_calibration/easyspec_wavelength.py +0 -0
  265. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/wavelength_calibration/in_situ.py +0 -0
  266. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/wavelength_calibration/lamp_atlas.py +0 -0
  267. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/wavelength_calibration/match_lamp.py +0 -0
  268. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/wavelength_calibration/reidentify.py +0 -0
  269. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/algorithms/wavelength_calibration/solar.py +0 -0
  270. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/base.py +0 -0
  271. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/embeddings.py +0 -0
  272. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/io/__init__.py +0 -0
  273. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/io/ascii.py +0 -0
  274. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/io/votable.py +0 -0
  275. {spectro_kernel-0.6.2/src/spectro_mcp → spectro_kernel-0.7.0/src/spectro_kernel}/py.typed +0 -0
  276. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/registry.py +0 -0
  277. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/types/__init__.py +0 -0
  278. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/types/catalog.py +0 -0
  279. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/types/context.py +0 -0
  280. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/types/history.py +0 -0
  281. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/types/image.py +0 -0
  282. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/types/line.py +0 -0
  283. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/types/spectrum.py +0 -0
  284. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/types/timeseries.py +0 -0
  285. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_kernel/url_safety.py +0 -0
  286. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_mcp/__init__.py +0 -0
  287. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_mcp/__main__.py +0 -0
  288. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_mcp/auth.py +0 -0
  289. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_mcp/observability.py +0 -0
  290. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_mcp/server.py +0 -0
  291. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_mcp/session.py +0 -0
  292. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/src/spectro_mcp/url_safety.py +0 -0
  293. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/conftest.py +0 -0
  294. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/reference/conftest.py +0 -0
  295. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/reference/test_known_answers.py +0 -0
  296. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/reference/test_sun.py +0 -0
  297. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/reference/test_vega.py +0 -0
  298. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_aperture_photometry.py +0 -0
  299. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_barycentric_bjd.py +0 -0
  300. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_base.py +0 -0
  301. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_catalog_queries_mocked.py +0 -0
  302. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_classify_template_chi2.py +0 -0
  303. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_cli.py +0 -0
  304. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_combine_arithmetic.py +0 -0
  305. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_continuum.py +0 -0
  306. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_corrections.py +0 -0
  307. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_cross_correlate_extension.py +0 -0
  308. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_dark_flat_combine.py +0 -0
  309. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_denoise_2d.py +0 -0
  310. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_detect_lines_blind.py +0 -0
  311. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_detect_trace.py +0 -0
  312. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_disentangle_sb2.py +0 -0
  313. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_doppler_tomogram.py +0 -0
  314. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_easyspec_apply_staging.py +0 -0
  315. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_easyspec_sessions.py +0 -0
  316. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_easyspec_wrappers.py +0 -0
  317. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_embedding.py +0 -0
  318. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_embedding_pretrained.py +0 -0
  319. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_embedding_remote_lick.py +0 -0
  320. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_embedding_tier1.py +0 -0
  321. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_export_fits_bess.py +0 -0
  322. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_export_hdf5.py +0 -0
  323. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_extract_boxcar.py +0 -0
  324. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_extract_optimal.py +0 -0
  325. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_extract_spectrum_sum.py +0 -0
  326. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_flux_calibrate_easyspec.py +0 -0
  327. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_geometry_corrections.py +0 -0
  328. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_lamp_atlas_match.py +0 -0
  329. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_line_profiles.py +0 -0
  330. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_lines.py +0 -0
  331. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_mcp.py +0 -0
  332. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_mcp_http_entry.py +0 -0
  333. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_mcp_param_guard.py +0 -0
  334. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_mcp_production.py +0 -0
  335. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_mcp_security.py +0 -0
  336. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_mcp_tools_extra.py +0 -0
  337. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_measure_arc_geometry.py +0 -0
  338. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_misc_algorithms.py +0 -0
  339. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_nebular_diagnostics.py +0 -0
  340. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_no_circular_imports.py +0 -0
  341. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_normalize_to_region.py +0 -0
  342. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_output_produces_contract.py +0 -0
  343. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_pipeline.py +0 -0
  344. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_quality.py +0 -0
  345. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_read_sdss.py +0 -0
  346. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_redshift_lines.py +0 -0
  347. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_registry.py +0 -0
  348. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_reidentify.py +0 -0
  349. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_resample_flux_conserving.py +0 -0
  350. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_response_from_standard.py +0 -0
  351. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_rotation_curve.py +0 -0
  352. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_rv_precision_bouchy.py +0 -0
  353. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_sky_lateral_bands.py +0 -0
  354. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_smoothing.py +0 -0
  355. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_timeseries.py +0 -0
  356. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_transforms.py +0 -0
  357. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_types.py +0 -0
  358. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_url_safety_kernel.py +0 -0
  359. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_validate_bess_header.py +0 -0
  360. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_viz.py +0 -0
  361. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_vr_ratio.py +0 -0
  362. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_wavelength_calibration_in_situ.py +0 -0
  363. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tests/unit/test_wavelength_calibration_solar.py +0 -0
  364. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tools/docs/__init__.py +0 -0
  365. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tools/docs/generate_llms.py +0 -0
  366. {spectro_kernel-0.6.2 → spectro_kernel-0.7.0}/tools/docs/netlify.toml +0 -0
@@ -166,6 +166,7 @@ venv.bak/
166
166
 
167
167
  # documentation - generated by tools/docs/generate.py
168
168
  docs/algorithms/
169
+ docs/recipes/catalogue/
169
170
  docs/ai/
170
171
  docs/llms.txt
171
172
 
@@ -6,6 +6,246 @@ Until `1.0.0` the public API may change between minor versions.
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.7.0] — 2026-09-26
10
+
11
+ The release that turns presets into **recipes** : a measurement written once,
12
+ with its conventions fixed and everything instrument-dependent declared as a
13
+ variable, so that observers with different spectrographs produce comparable
14
+ numbers. It also lands the bricks those recipes need for pro-am campaigns
15
+ (time-series line-profile analysis, the flux-calibration chain, stellar
16
+ activity and rotation indicators, resolving power, spline continuum) and a
17
+ FITS reader that copes with the amateur "zoo". Numerical changes are carried
18
+ by MAJOR bumps of the bricks concerned and listed below.
19
+
20
+ ### Added — recipes, variables and profiles (presets v2)
21
+
22
+ - A preset may declare a `variables` block (`type` among `str`, `int`,
23
+ `float`, `bool`, `path`, `list`; `default`, `required`, `description`,
24
+ `choices`) and reference them as `"${name}"` in step parameters. The
25
+ values come from a **profile** (`spectro pipeline <recipe> --profile
26
+ file.yaml`), from `--set name=value` (converted to the declared type),
27
+ from `PipelineBuilder().from_preset(name, variables={...})` /
28
+ `from_config(config, variables)`, or from the `variables` argument of
29
+ the MCP `run_preset` tool. Defaults fill the gaps ; a missing required
30
+ variable, an undeclared token or a value of the wrong type is refused
31
+ before anything runs, with the variable's description in the message.
32
+ A preset without `variables` is unchanged.
33
+ - `requires: ">=0.7, <1.0"` : the kernel range a recipe was validated for
34
+ (plain comparison operators) ; a recipe outside the range refuses to build.
35
+ - Standard metadata vocabulary : `kind` (`analysis`, `reduction`,
36
+ `campaign`, `template`), `status` (`draft`, `reviewed`, `reference`),
37
+ `references` (mandatory for a campaign recipe), `conventions`.
38
+ - **Discovery** : besides the bundled catalogue, the kernel lists recipes
39
+ from every directory in `SPECTRO_PRESET_PATH` and from installed
40
+ packages registering the `spectro_kernel.presets` entry point (a
41
+ `Path` to a directory of YAML files). `list_presets()` reports each
42
+ recipe's `source` ; a bundled name wins over an external one.
43
+ - **Validation** : `spectro preset validate <file-or-name>...` (also
44
+ `--profile` / `--set` to type-check values) reports every problem at
45
+ once : name not snake_case, missing or malformed version, missing
46
+ description, unknown `kind` / `status`, campaign recipe without
47
+ references, unsatisfied `requires`, unknown algorithm, unknown parameter,
48
+ required parameter neither set nor bound, undeclared token, unused
49
+ variable, `depends_on` matching no step. `spectro preset show <name>`
50
+ prints a recipe's variables and steps ; `spectro presets` shows the
51
+ source and the number of variables. Python : `validate_preset`,
52
+ `validate_preset_file`, `preset_sources`, `find_preset`.
53
+ - **Provenance** : every named pipeline built from a file or a config
54
+ closes its run with a `pipeline:<name>` `ProcessingStep` carrying the
55
+ recipe version, the bound variables, the kernel version and the source,
56
+ so a result states which recipe produced it. Ad-hoc pipelines assembled
57
+ in Python without a name are unchanged.
58
+ - The bundled `full_reduction_easyspec` template (2.0.0) replaces its
59
+ `__REPLACE__` placeholders by ten declared variables (`bias_dir`,
60
+ `dark_dir`, `flat_dir`, `science_path`, `exposure_seconds`, `airmass`,
61
+ `gain`, `readnoise`, `target_name`, `combine_method`) ; the six analysis
62
+ presets gain `kind` and `status` metadata. The preset file format is
63
+ published as `preset.schema.json`.
64
+ - The curated collection lives in a separate repository,
65
+ [spectro-kernel-recipes](https://github.com/matthieulel/spectro-kernel-recipes)
66
+ (`pip install spectro-kernel-recipes`), starting with `be_halpha_ew`,
67
+ `binary_rv_ccf`, `solar_long_slit` and `stellar_long_slit` (all `draft`).
68
+
69
+ ### Added — time-series line-profile analysis (category `timeseries`, `stacking`)
70
+
71
+ - **`temporal_variance_spectrum` v1.0.0** (scipy) — Fullerton, Gies & Bolton
72
+ 1996, ApJS 103, 475, §3 : N ≥ 3 continuum-normalised epochs in
73
+ `ctx.spectra`, resampled on the finest common grid over the overlap ;
74
+ per-epoch noise σ_ic from `uncertainty` or DER_SNR on a continuum window
75
+ (`continuum_lo` / `continuum_hi`) ; weights w_i = (σ_0/σ_ic)² with
76
+ σ_0 = [(1/N) Σ σ_ic⁻²]^(−1/2) ; (TVS)_j = (N−1)⁻¹ Σ_i w_i (S_ij − S̄_j)² ;
77
+ reported as (TVS)^{1/2} with the χ²_(N−1) significance threshold at
78
+ `confidence` (0.99). Writes `extras.tvs` and the `tvs_*` metrics, the
79
+ bounds of the longest significant run as `tvs_variable_lo_aa` /
80
+ `tvs_variable_hi_aa`. Caveat documented : the pixel-dependent
81
+ photon-noise term α_ij of the paper is not applied (uniform noise across
82
+ the profile). Tests : variability confined to |v| < 120 km/s → 71 % of
83
+ pixels flagged inside, 2.2 % beyond 200 km/s ; no variability → 1.2 %
84
+ above the 99 % threshold ; threshold exact to 1e-12.
85
+ - **`phase_dispersion_minimization` v1.0.0** (numpy) — Stellingwerf 1978,
86
+ ApJ 224, 953 : Θ = s²/σ² over M = N_b·N_c overlapping phase samples
87
+ (`n_bins` 10, `n_covers` 3), uniform frequency grid (`n_periods` 2000),
88
+ light-curve input exactly as `lomb_scargle`. `ctx.periodograms[key]`
89
+ carries Θ with `meta.lower_is_better` ; metrics `pdm_best_period_days`,
90
+ `pdm_theta_min`. No false-alarm probability on purpose
91
+ (Schwarzenberg-Czerny 1997, ApJ 489, 941). Tests : eclipse and sawtooth
92
+ signals at 3.7 d over 60 d recovered to 0.11 % ; pure noise → Θ ≈ 1.00.
93
+ - **`box_least_squares` v1.0.0** (astropy) — Kovács, Zucker & Mazeh 2002,
94
+ A&A 391, 369, wrapping `astropy.timeseries.BoxLeastSquares` ;
95
+ `duration_hours` list, `objective` likelihood / snr ; periodogram plus
96
+ `extras.bls_model` and the `bls_*` metrics. Without uncertainties the
97
+ noise is 1.4826·MAD (Rousseeuw & Croux 1993) instead of astropy's
98
+ implicit σ = 1 (which gave a 41-σ transit an SNR of 0.09). Tests :
99
+ P = 2.5 d, depth 1 %, 3 h box on a 30 d series → period to 0.012 %,
100
+ depth to 1.8 %, SNR 41.
101
+ - **`stack_spectra` 2.0.0 → 2.1.0** (additive) : `method: "weighted"`, the
102
+ Bevington & Robinson inverse-variance mean with the stack uncertainty
103
+ (Σ w)^(−1/2) ; weights from the `weights` parameter, else from every
104
+ spectrum's `uncertainty`, else from DER_SNR² (Tody 1993, IRAF `scombine`).
105
+ mean / median / sum are bit-identical to v2.0.0. Test : σ = 1 and 2 →
106
+ weights 4:1, output σ = 1/√1.25.
107
+
108
+ ### Added — flux-calibration chain (categories `correction`, `catalog`, `nebular`)
109
+
110
+ - **`atmospheric_extinction_correct` v1.0.0** (numpy) — F_0 = F·10^{0.4 k(λ) X}
111
+ (Hayes & Latham 1975, ApJ 197, 593 ; Hardie 1962). Built-in `curve`
112
+ `"kpno"`, the IRAF `onedstds$kpnoextinct.dat` mean extinction table
113
+ (3200–10400 Å, Tody 1986 ; all 82 nodes checked against the IRAF source,
114
+ the last four being CTIO values), or a user table in `ctx.extras`. Airmass from
115
+ `airmass`, else from the header / site with Kasten & Young 1989, Appl.
116
+ Opt. 28, 4735, eq. 3. Uncertainty scaled with the flux. Metrics
117
+ `airmass`, `k_mag_median`, `n_outside_curve`.
118
+ - **`deredden_interstellar` v1.0.0** (dust_extinction, optional extra
119
+ `reduction`) — F_0 = F / 10^{−0.4 A(λ)} with CCM89 (Cardelli, Clayton &
120
+ Mathis 1989, ApJ 345, 245 ; default), F99 (Fitzpatrick 1999, PASP 111,
121
+ 63) or G23 (Gordon et al. 2023, ApJ 950, 86) ; `ebv`, `rv` (3.1) ; fails
122
+ outside a law's validity range. Test : CCM89, R_V = 3.1, E(B−V) = 0.1 at
123
+ 5500 Å → factor 10^{0.4·0.31} = 1.330, checked against the package.
124
+ - **`standard_star_reference` v1.0.0** (astropy ; network, lazy) — loads a
125
+ CALSPEC standard (Bohlin, Gordon & Tremblay 2014, PASP 126, 711 ; Bohlin,
126
+ Hubeny & Rauch 2020, AJ 160, 21) by name or `filename` from the STScI
127
+ reference-atlas archive through the SSRF-guarded fetch with timeout and
128
+ size cap, or a Pickles 1998 (PASP 110, 863) template ; vacuum → air with
129
+ Morton 2000 (`to_air`) ; writes `extras.catalog_spectrum` (rename with
130
+ `output_key`, e.g. to `reference_spectrum` for `response_from_standard`).
131
+ Pickles templates are normalised to unity at 5556 Å by construction
132
+ (Pickles 1998, §3 and §5) and passed through unchanged ; the brick reports
133
+ `flux_at_5556_aa` so the caller can see it.
134
+ - **`balmer_decrement_extinction` v1.0.0** (scipy) — c(Hβ), E(B−V) and A_V
135
+ from the observed Hα/Hβ ratio against Case B 2.86 (Osterbrock & Ferland
136
+ 2006, Table 4.4, §7.2) with the CCM89 f(λ) ; negative extinction clamped
137
+ to 0 with a note ; metrics `balmer_ratio_observed`, `c_hbeta`,
138
+ `ebv_balmer`, `a_v_balmer`, `flux_halpha`, `flux_hbeta`.
139
+
140
+ ### Changed — uncertainties are now propagated (MAJOR bumps ; flux byte-identical)
141
+
142
+ Until now every one of these bricks copied the input `uncertainty` array
143
+ unchanged, which is wrong after any of them. Each now documents its rule ;
144
+ a spectrum without uncertainty is processed exactly as before.
145
+
146
+ - `smooth_gaussian` 1.0.1 → 2.0.0 and `smooth_savgol` 1.0.1 → 2.0.0 :
147
+ σ_out,i = sqrt(Σ_k w_k² σ²) with the very kernel applied (Gaussian
148
+ truncated at 4σ ; Savitzky-Golay coefficients incl. the edge polynomials).
149
+ White noise, sigma = 2 px → σ_out = 0.376 σ in the interior and 0.641 σ
150
+ at the first and last samples (the 'nearest' edge weights add before
151
+ squaring) ; window 11 / order 3 → 0.4555 σ. Both checked against the full
152
+ linear operator to 1e-9 and by Monte-Carlo. Correlated noise is not
153
+ tracked (documented).
154
+ - `normalize_polynomial` 1.1.1 → 2.0.0, `normalize_to_region` 1.0.1 →
155
+ 2.0.0, `normalize_max` 1.0.2 → 2.0.0, `normalize_percentile` 1.0.2 →
156
+ 2.0.0, `normalize_edges` 1.0.2 → 2.0.0 : σ_out = σ_in / |continuum|,
157
+ continuum treated as noise-free.
158
+ - `resample_linear` 1.0.1 → 2.0.0 : σ_out = sqrt(interp(σ²)) (linear
159
+ interpolation of the variance ; v1 interpolated σ itself).
160
+ - `combine_spectra_arithmetic` 1.0.1 → 2.0.0 : add/sub in quadrature ;
161
+ mul/div with the relative errors in quadrature when the reference
162
+ carries an uncertainty (Bevington & Robinson §3.2), else σ·|r| or σ/|r|.
163
+
164
+ ### Added — stellar activity, rotation, resolution, continuum (new category `activity`)
165
+
166
+ - **`activity_index_caii_hk` v1.0.0** (numpy, `activity`) — the Mount
167
+ Wilson S index, S = α (H + K)/(R + V) with the HKP-2 triangular 1.09 Å
168
+ H and K bands and the 20 Å R and V bands (Vaughan, Preston & Wilson 1978,
169
+ PASP 90, 267 ; Duncan et al. 1991, ApJS 76, 383), `alpha` 2.3 (échelle
170
+ convention, Lovis et al. 2011) with an optional linear calibration to the
171
+ Mount Wilson scale ; log R'_HK when `b_v` is given (Noyes et al. 1984,
172
+ ApJ 279, 763 ; Middelkoop 1982, A&A 107, 31). Fails outside 3890–4011 Å.
173
+ - **`activity_index_halpha` v1.0.0** (numpy, `activity`) — Gomes da Silva
174
+ et al. 2011, A&A 534, A30 (after Boisse et al. 2009, A&A 495, 959) : 1.6 Å
175
+ core at 6562.808 Å over the 6550.87 ± 5.375 Å and 6580.31 ± 4.375 Å
176
+ reference bands ; `halpha_index` and its error.
177
+ - **`ccf_bisector` v1.0.0** (numpy, `activity`) — bisector of the CCF
178
+ written by `cross_correlate_rv` (or of one line of the spectrum) after
179
+ Toner & Gray 1988, ApJ 334, 1008, and the bisector inverse slope BIS =
180
+ v_top(10–40 %) − v_bottom(55–90 %) of Queloz et al. 2001, A&A 379, 279 ;
181
+ `bis_kms`, `bisector_span_kms`, `extras.ccf_bisector`. Symmetric profile
182
+ → BIS = 0 within 0.01 km/s.
183
+ - **`vsini_fourier` v1.0.0** (scipy, `kinematics`) — v sin i from the first
184
+ zero of the Fourier transform of a line profile (Carroll 1933, MNRAS 93,
185
+ 478 ; Gray 2005, ch. 18) with q₁(ε) from Dravins, Lindegren & Nordlund
186
+ 1990, A&A 228, 203 (`epsilon` 0.6 → q₁ = 0.660) ; the first zero is
187
+ accepted only when the side lobe stands above the Fourier noise floor
188
+ (`metrics.fourier_noise_floor`, `fourier_sidelobe_ratio`), and unresolved,
189
+ emission or noise-dominated lines fail explicitly. Tests : 30, 80 and
190
+ 150 km/s recovered within 5 % at 0.5 % noise. Reference to the modern
191
+ recipe : Díaz, González, Levato & Grosso 2011, A&A 531, A143.
192
+ - **`measure_resolving_power` v1.0.0** (scipy, `quality`) — R = λ/FWHM from
193
+ Gaussian fits of the `n_lines` strongest isolated lamp / sky lines
194
+ (isolation by `min_separation_aa`), median and scatter of R, instrumental
195
+ FWHM in Å and km/s (Gray 2005, ch. 12 ; Tody 1986, IRAF `splot`). Test :
196
+ 12 lines of FWHM = λ/5000 → R = 5000 ± 2 %.
197
+ - **`normalize_spline` v1.0.0** (scipy, `continuum`) — the IRAF
198
+ `continuum` recipe (Tody 1986 ; Tody 1993) : iteratively clipped cubic
199
+ spline (`n_knots`, `low_reject` 2.0, `high_reject` 3.0, `niterate` 10,
200
+ `grow` 0), `extras.continuum_spline`, σ/continuum propagated ;
201
+ cross-references `normalize_polynomial`.
202
+
203
+ ### Changed — FITS reading and writing (`read_fits` 2.0.0 → 3.0.0, `io/fits.py`)
204
+
205
+ The reader now takes explicit, documented decisions on the FITS "zoo"
206
+ (audit items C6 / C7) ; 37 new tests in `test_io_fits_zoo.py`.
207
+
208
+ - `CD1_1` wins over `CDELT1` when both exist (Greisen & Calabretta 2002 ;
209
+ v2 preferred `CDELT1`), `PC1_1` scales `CDELT1` ; `CUNIT1` (or IRAF
210
+ `WAT1` units) in nm / µm / m converted to Å with the original label in
211
+ `meta["wavelength_unit_original"]` ; WAVE-LOG (Paper III) and IRAF
212
+ `DC-FLAG` handling unchanged.
213
+ - No dispersion keywords → 0-based pixel axis, `wavelength_unit="pixel"`,
214
+ `meta["wcs"]="none"` (v2 labelled the pixel index "Angstrom").
215
+ - A genuine 2-D image is refused unless the new `row` parameter selects a
216
+ row (v2 silently returned row 0) ; length-1 axes are squeezed ; IRAF
217
+ multispec / échelle markers redirect to `read_echelle_fits` ; 3-D cubes
218
+ are refused.
219
+ - Extension selection : a data-bearing PRIMARY wins over tables (v2
220
+ preferred any table) ; otherwise the first table with recognisable
221
+ wavelength / flux columns (incl. SDSS `loglam`) ; the new `hdu`
222
+ parameter (index or EXTNAME) overrides ; when nothing is readable the
223
+ error lists the HDUs found.
224
+ - `ERROR` / `ERR` / `ERRS` / `SIGMA` / `UNCERT(AINTY)` (1σ) and `IVAR`
225
+ (1/√ivar) image extensions and error / ivar table columns fill
226
+ `uncertainty` ; `MASK` extensions and `mask` / `and_mask` columns fill
227
+ `mask` ; `BUNIT` becomes the flux unit ; descending axes are kept and
228
+ flagged `meta["wavelength_descending"]`.
229
+ - `write_fits` : the linear layout now appends `ERROR` and `MASK`
230
+ extensions when the spectrum carries them, read back by `read_fits`
231
+ (round-trip tested) ; a spectrum without either is still a single HDU.
232
+
233
+
234
+ ### Documentation
235
+
236
+ - A new **Recipes** section (the recipe / profile idea, the format
237
+ reference, how to share a recipe) and a generated recipe catalogue with
238
+ one page per recipe plus `/ai/presets.json` ; the CLI, MCP, pipelines and
239
+ reduction-walkthrough pages updated accordingly.
240
+
241
+ - The long-slit tutorial is now worked on a **solar** spectrum (Fraunhofer
242
+ wavelength calibration, no lamp) with a **stellar** arc-lamp variant ;
243
+ the aurora example is gone. Its code samples were also corrected : the
244
+ 2-D reduction runs from Python (`spectro pipeline` loads 1-D spectra) and
245
+ the lamp hand-off uses the real `lamp_identifications` keys.
246
+ - The BeSS-dashboard cookbook page is removed ; the aurora line-monitor
247
+ notebook is parked in `docs/.drafts/` (not published) for a later return.
248
+
9
249
  ## [0.6.2] — 2026-09-19
10
250
 
11
251
  A documentation and web release : the docs move to a generated,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: spectro-kernel
3
- Version: 0.6.2
3
+ Version: 0.7.0
4
4
  Summary: A shared catalogue of astronomical spectroscopy algorithms, composable into reproducible pipelines, usable as a Python library, a CLI, or an MCP server.
5
5
  Project-URL: Homepage, https://github.com/matthieulel/spectro-kernel
6
6
  Project-URL: Documentation, https://docs.spectrokernel.io/
@@ -210,6 +210,16 @@ by environment variable (none of these affect stdio mode) :
210
210
  | `SPECTRO_MCP_S3_BUCKET`, `SPECTRO_MCP_S3_ENDPOINT`, … | unset | Presigned-URL uploads (`request_upload_url`). |
211
211
  | `SENTRY_DSN` | unset | Error reporting. |
212
212
 
213
+ ## Recipes and profiles
214
+
215
+ A recipe (preset) is a measurement written once with its conventions fixed;
216
+ what depends on your instrument is a variable, bound by a profile at run
217
+ time: `spectro pipeline be_halpha_ew --input obs.fits --profile my_setup.yaml`.
218
+ Generic recipes ship with the kernel; campaign recipes live in the curated
219
+ [spectro-kernel-recipes](https://github.com/matthieulel/spectro-kernel-recipes)
220
+ collection (`pip install spectro-kernel-recipes`). See the
221
+ [Recipes](https://docs.spectrokernel.io/recipes/) documentation.
222
+
213
223
  ## Architecture
214
224
 
215
225
  ```
@@ -121,6 +121,16 @@ by environment variable (none of these affect stdio mode) :
121
121
  | `SPECTRO_MCP_S3_BUCKET`, `SPECTRO_MCP_S3_ENDPOINT`, … | unset | Presigned-URL uploads (`request_upload_url`). |
122
122
  | `SENTRY_DSN` | unset | Error reporting. |
123
123
 
124
+ ## Recipes and profiles
125
+
126
+ A recipe (preset) is a measurement written once with its conventions fixed;
127
+ what depends on your instrument is a variable, bound by a profile at run
128
+ time: `spectro pipeline be_halpha_ew --input obs.fits --profile my_setup.yaml`.
129
+ Generic recipes ship with the kernel; campaign recipes live in the curated
130
+ [spectro-kernel-recipes](https://github.com/matthieulel/spectro-kernel-recipes)
131
+ collection (`pip install spectro-kernel-recipes`). See the
132
+ [Recipes](https://docs.spectrokernel.io/recipes/) documentation.
133
+
124
134
  ## Architecture
125
135
 
126
136
  ```
@@ -0,0 +1,7 @@
1
+ # Drafts (not published)
2
+
3
+ Pages parked here are excluded from the site: both Zensical and MkDocs skip
4
+ dot-directories. Move a page back under `docs/` (and add it to the `nav` in
5
+ `mkdocs.yml`) to publish it again.
6
+
7
+ - `notebooks/aurora-line-monitor.md` - parked on 2026-09-19, to be reinstated later.
@@ -90,7 +90,12 @@ spectro pipeline balmer_quick --input obs.fits # run one
90
90
  ```
91
91
 
92
92
  Presets are why an analysis can be cited and reproduced: *"this measurement used the
93
- `balmer_quick` v1.0.0 preset"* is a precise, checkable statement.
93
+ `balmer_quick` v1.0.0 preset"* is a precise, checkable statement. Since v0.7.0 a
94
+ preset can declare **variables** (the instrument- or observer-dependent values)
95
+ that a **profile** supplies at run time, and every run closes with a
96
+ `pipeline:<name>` record in the history naming the recipe, its version and the
97
+ bound values. The [Recipes](../recipes/index.md) section explains the idea and
98
+ the [format](../recipes/format.md) page is the reference.
94
99
 
95
100
  ## Reproducibility {#reproducibility}
96
101
 
@@ -63,8 +63,8 @@ natural answer; today the cleanest path is the Python snippet above.)
63
63
 
64
64
  ## Going further
65
65
 
66
- - Replace the synthetic spectra with real BeSS extractions - see the
67
- [BeSS cookbook page](../cookbook/bess-dashboard.md).
66
+ - Replace the synthetic spectra with real BeSS extractions: `read_fits` reads
67
+ them directly (see [As a Python library](../usage/library.md)).
68
68
  - Add `compare_normalisations` (Tier 2+) before stacking when continuum
69
69
  variations between nights are suspect.
70
70
  - Couple it with `lomb_scargle` on a per-epoch line-strength metric to look for
@@ -136,7 +136,7 @@ beyond `spectro-mcp --http`.
136
136
  workflows (e.g. "always run `compare_normalisations` before measuring a
137
137
  line").
138
138
  - Wrap the agent in a periodic task (cron + a Claude API call) for nightly
139
- monitoring - Be-star variability alerts, aurora amplitude history,
139
+ monitoring - Be-star variability alerts, solar line monitoring,
140
140
  exoplanet RV drift.
141
141
  - Pair with the [web playground](../cookbook/web-playground.md) for human-in-the-loop
142
142
  debugging when the agent picks the wrong tool.
@@ -109,30 +109,40 @@ run_algorithm(
109
109
  # → ctx.spectrum.flux is now in erg/s/cm²/Å.
110
110
  ```
111
111
 
112
- ## The same as a preset
112
+ ## The same as a recipe
113
+
114
+ The whole chain (steps 1-3, the file-driven portion) is the bundled recipe
115
+ `full_reduction_easyspec`. Everything that depends on your night is a
116
+ variable of the recipe; you supply the values with a profile:
117
+
118
+ ```yaml
119
+ # night_2026-06-09.yaml
120
+ bias_dir: /data/biases
121
+ dark_dir: /data/darks
122
+ flat_dir: /data/flats
123
+ science_path: /data/science/alf_cyg_001.fits
124
+ exposure_seconds: 300
125
+ airmass: 1.18
126
+ target_name: alf Cyg
127
+ ```
128
+
129
+ ```bash
130
+ spectro preset show full_reduction_easyspec # the variables and their meaning
131
+ spectro pipeline full_reduction_easyspec --profile night_2026-06-09.yaml
132
+ ```
113
133
 
114
- The whole chain (steps 1-3 - the parameter-free, file-driven portion) is
115
- templated in the bundled preset
116
- [`full_reduction_easyspec`](https://github.com/matthieulel/spectro-kernel/blob/main/src/spectro_kernel/presets/catalog/reduction/full_reduction_easyspec.yaml).
117
- It is a *template*: the `__REPLACE__` placeholders are the runtime paths you fill
118
- in before building the pipeline. A typical usage:
134
+ Or from Python:
119
135
 
120
136
  ```python
121
- from spectro_kernel import PipelineBuilder, WorkContext
122
- from spectro_kernel.presets import load_preset
123
-
124
- config = load_preset("full_reduction_easyspec")
125
- for step in config["steps"]:
126
- p = step["params"]
127
- for key, value in p.items():
128
- if isinstance(value, str) and value.startswith("__REPLACE_WITH_BIAS_DIR__"):
129
- p[key] = "/data/biases"
130
- elif isinstance(value, str) and value.startswith("__REPLACE_WITH_DARK_DIR__"):
131
- p[key] = "/data/darks"
132
- # … etc.
133
-
134
- pipeline = PipelineBuilder().from_config(config).build()
137
+ import yaml
138
+
139
+ from spectro_kernel import WorkContext
140
+ from spectro_kernel.pipeline import PipelineBuilder
141
+
142
+ profile = yaml.safe_load(open("night_2026-06-09.yaml"))
143
+ pipeline = PipelineBuilder().from_preset("full_reduction_easyspec", profile).build()
135
144
  result = pipeline.execute(WorkContext())
145
+ print(result.history[-1]) # pipeline:full_reduction_easyspec v2.0.0, the bound variables
136
146
  ```
137
147
 
138
148
  Steps 4-6 (wavelength + extinction + flux) stay separate calls because their
@@ -0,0 +1,163 @@
1
+ ---
2
+ description: Reference for the recipe (preset) file, its variables, profiles, validation and provenance.
3
+ ---
4
+
5
+ # Recipe format
6
+
7
+ A recipe is one YAML file. The schema is published at
8
+ [`/ai/schemas/preset.schema.json`](../ai/schemas/preset.schema.json) and
9
+ `spectro preset validate` checks a file against the running kernel: format,
10
+ metadata vocabulary, algorithm names, parameter names, variables, and the
11
+ kernel version range.
12
+
13
+ ## The file
14
+
15
+ ```yaml
16
+ name: be_halpha_ew # lowercase snake_case; the identifier users cite
17
+ version: 1.0.0 # semantic version of the recipe itself
18
+ description: >-
19
+ What is measured and how, in one paragraph.
20
+ requires: ">=0.7, <1.0" # spectro-kernel range the recipe was validated for
21
+ metadata:
22
+ kind: campaign # analysis | reduction | campaign | template
23
+ status: reviewed # draft | reviewed | reference
24
+ references: # mandatory for a campaign recipe
25
+ - "Vollmann & Eversberg 2006, AN 327, 862"
26
+ conventions: "continuum band 6500-6520 Å, 40 Å window around H-alpha"
27
+ author: "BeSS working group"
28
+ variables: # what depends on the instrument or the observer
29
+ tilt_deg: {type: float, required: true, description: "slit tilt (deg)"}
30
+ half_width: {type: int, default: 6}
31
+ steps: # the pipeline, in order
32
+ - name: Straighten the slit
33
+ algorithm: correct_tilt_affine
34
+ params: {tilt_deg: "${tilt_deg}"}
35
+ ```
36
+
37
+ `name`, `version`, `description` and `steps` are required. A recipe with no
38
+ `variables` block is a plain preset and runs as is; every preset written
39
+ before v0.7.0 is still valid.
40
+
41
+ ## Variables
42
+
43
+ Each variable has a `type`, an optional `default`, a `description`, and
44
+ optionally a list of `choices`. A variable without a default is required.
45
+ The shorthand `half_width: 6` declares an optional integer with that default.
46
+
47
+ | Type | Accepts | Example values |
48
+ |---|---|---|
49
+ | `int` | integers, or strings such as `"12"` from the command line | `6` |
50
+ | `float` | numbers | `0.4` |
51
+ | `bool` | booleans, or `true/false`, `yes/no`, `on/off`, `1/0` | `true` |
52
+ | `str` | text | `"alf Cyg"` |
53
+ | `path` | a file or directory path, kept as text | `/data/bias` |
54
+ | `list` | a YAML list, a JSON list such as `"[1, 2]"`, or `"a, b"` | `[5852.49, 6266.50]` |
55
+
56
+ Values coming from `--set name=value` are strings and are converted to the
57
+ declared type; a value outside `choices` or of the wrong type is refused
58
+ with the variable's name and description in the message.
59
+
60
+ ## Substitution rules
61
+
62
+ The rules are deliberately small:
63
+
64
+ - a parameter whose value is exactly `${name}` receives the variable's typed
65
+ value (a number stays a number, a list stays a list);
66
+ - a string that contains `${name}` among other text is interpolated as text
67
+ (`label: "H-${line}"`), useful for labels and file names;
68
+ - lists and mappings are walked recursively;
69
+ - every `${name}` must be declared in `variables`, and every declared variable
70
+ must be used, otherwise validation fails.
71
+
72
+ Write the token in quotes, `"${name}"`: YAML would otherwise read the braces
73
+ of `{tilt_deg: ${tilt_deg}}` as a nested mapping. The quotes change nothing
74
+ for the kernel, which still passes the typed value.
75
+
76
+ ## Profiles
77
+
78
+ A profile is any YAML mapping of variable name to value. It carries no
79
+ science, only what is true of one instrument and one observer:
80
+
81
+ ```yaml
82
+ # lhires_lyon.yaml
83
+ tilt_deg: 1.1
84
+ half_width: 4
85
+ ```
86
+
87
+ Ways to bind values, in increasing priority:
88
+
89
+ | From | How |
90
+ |---|---|
91
+ | the recipe | `default` of each variable |
92
+ | a profile file | `spectro pipeline <recipe> --profile lhires_lyon.yaml` |
93
+ | the command line | `--set tilt_deg=1.1` (repeatable) |
94
+ | Python | `PipelineBuilder().from_preset("be_halpha_ew", {"tilt_deg": 1.1})` |
95
+ | MCP | `run_preset(session_id, "be_halpha_ew", variables={"tilt_deg": 1.1})` |
96
+
97
+ Keep your profiles next to your data, one per instrument setup, and reuse
98
+ them across every recipe: the same `alpy600_toulouse.yaml` serves the Be
99
+ star recipe tonight and the nova recipe next month.
100
+
101
+ ## `requires`
102
+
103
+ The kernel version range the recipe was validated for, with the plain
104
+ comparison operators (`>=`, `>`, `<=`, `<`, `==`, `!=`, comma-separated). A
105
+ recipe whose range excludes the running kernel refuses to build. When a
106
+ brick used by a recipe changes its own major version (its numbers changed),
107
+ the recipe author re-validates and bumps the recipe.
108
+
109
+ ## Metadata vocabulary
110
+
111
+ | Key | Values | Meaning |
112
+ |---|---|---|
113
+ | `kind` | `analysis`, `reduction`, `campaign`, `template` | what the recipe is for; a *campaign* recipe fixes a measurement convention for a community |
114
+ | `status` | `draft`, `reviewed`, `reference` | how far the review went (see [Share a recipe](share.md)) |
115
+ | `references` | list of strings | the papers the conventions rest on; mandatory for `campaign` |
116
+ | `conventions` | text | the choices that are not fixed by the literature, stated plainly |
117
+ | `author`, `notes`, `expects`, `category` | text | free information shown on the recipe page |
118
+
119
+ ## Validation
120
+
121
+ ```bash
122
+ spectro preset validate be_halpha_ew.yaml # the file alone
123
+ spectro preset validate be_halpha_ew.yaml --profile p.yaml # plus your values
124
+ spectro preset show be_halpha_ew # variables and steps
125
+ ```
126
+
127
+ Validation is what the CI of a recipe collection runs on every contribution.
128
+ It reports, all at once: a name that is not snake_case, a missing or malformed
129
+ version, a missing description, an unknown `kind` or `status`, a campaign
130
+ recipe without references, a `requires` range the kernel does not satisfy,
131
+ an unknown algorithm, an unknown parameter name, a required parameter that is
132
+ neither set nor bound to a variable, an undeclared `${token}`, an unused
133
+ variable, and a `depends_on` that matches no step.
134
+
135
+ ## Provenance
136
+
137
+ When a recipe runs, every brick records itself in the context history as
138
+ before, and the run closes with one more record:
139
+
140
+ ```text
141
+ algorithm pipeline:be_halpha_ew
142
+ version 1.0.0
143
+ params {variables: {...}, n_steps: 4, kernel_version: 0.7.0, source: package:spectro-kernel-recipes}
144
+ ```
145
+
146
+ It is written by `Pipeline.execute` for every named pipeline built from a
147
+ file or a config, and carried into every export that serialises the history.
148
+ Ad-hoc pipelines assembled in Python without a name leave the history exactly
149
+ as their steps wrote it.
150
+
151
+ ## Discovery
152
+
153
+ `spectro presets` lists every recipe the kernel can see, in this search order:
154
+
155
+ 1. the recipes bundled with the kernel;
156
+ 2. the directories listed in the `SPECTRO_PRESET_PATH` environment variable
157
+ (`:`-separated on macOS and Linux);
158
+ 3. installed packages that register an entry point in the
159
+ `spectro_kernel.presets` group (see [Share a recipe](share.md)).
160
+
161
+ A bundled name always wins over an external one with the same name. A recipe
162
+ can also be run from a path (`spectro pipeline ./my_recipe.yaml`). Nothing is
163
+ ever fetched from the network.