spectro-kernel 0.6.2__tar.gz → 0.8.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 (388) hide show
  1. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/.gitignore +4 -0
  2. spectro_kernel-0.8.0/AGENTS.md +419 -0
  3. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/CHANGELOG.md +405 -0
  4. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/PKG-INFO +14 -2
  5. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/README.md +13 -1
  6. spectro_kernel-0.8.0/docs/.drafts/README.md +7 -0
  7. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/concepts/data-types.md +1 -1
  8. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/concepts/pipelines.md +6 -1
  9. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/getting-started.md +11 -0
  10. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/index.md +4 -0
  11. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/notebooks/be-star-variability.md +2 -2
  12. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/notebooks/claude-mcp-end-to-end.md +1 -1
  13. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/notebooks/full-reduction-walkthrough.md +30 -20
  14. spectro_kernel-0.8.0/docs/recipes/format.md +163 -0
  15. spectro_kernel-0.8.0/docs/recipes/index.md +125 -0
  16. spectro_kernel-0.8.0/docs/recipes/share.md +88 -0
  17. spectro_kernel-0.6.2/docs/reference.md → spectro_kernel-0.8.0/docs/reference/python.md +3 -2
  18. spectro_kernel-0.8.0/docs/tutorials/long-slit-reduction.md +299 -0
  19. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/usage/cli.md +24 -5
  20. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/usage/mcp.md +9 -2
  21. spectro_kernel-0.8.0/docs/validation/.nav.md +2 -0
  22. spectro_kernel-0.8.0/docs/validation/index.md +96 -0
  23. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/why.md +1 -1
  24. spectro_kernel-0.8.0/examples/mcp_client.py +57 -0
  25. spectro_kernel-0.8.0/examples/quickstart.py +37 -0
  26. spectro_kernel-0.8.0/examples/recipe_with_profile.py +58 -0
  27. spectro_kernel-0.8.0/examples/wavelength_calibration.py +53 -0
  28. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/pyproject.toml +1 -1
  29. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/activity/_bands.py +128 -0
  30. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/activity/activity_index_caii_hk.py +320 -0
  31. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/activity/activity_index_halpha.py +167 -0
  32. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/activity/ccf_bisector.py +410 -0
  33. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/catalogs/standard_star.py +426 -0
  34. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/continuum/compare_normalisations.py +8 -3
  35. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/continuum/normalize_edges.py +14 -3
  36. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/continuum/normalize_max.py +21 -2
  37. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/continuum/normalize_percentile.py +21 -5
  38. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/continuum/normalize_polynomial.py +22 -15
  39. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/continuum/normalize_region.py +22 -7
  40. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/continuum/normalize_spline.py +294 -0
  41. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/continuum/subtract_continuum.py +15 -3
  42. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/corrections/atmospheric_extinction.py +483 -0
  43. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/corrections/deredden_interstellar.py +187 -0
  44. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/embedding/embed_band_power.py +5 -3
  45. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/embedding/embed_continuum_subtracted.py +10 -7
  46. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/embedding/embed_lick_indices.py +5 -3
  47. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/embedding/embed_log_lambda.py +6 -3
  48. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/embedding/embed_pretrained.py +12 -7
  49. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/embedding/embed_remote.py +17 -3
  50. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/embedding/embed_spectrum.py +10 -6
  51. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/embedding/embed_wavelets.py +10 -5
  52. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/extraction/_aperture.py +58 -0
  53. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/extraction/boxcar.py +71 -51
  54. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/extraction/optimal.py +861 -0
  55. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/io/read_fits.py +153 -0
  56. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/kinematics/vsini_fourier.py +430 -0
  57. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/lines/_line_flux.py +6 -3
  58. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/lines/_profiles.py +10 -4
  59. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/lines/detect.py +19 -4
  60. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/lines/equivalent_width.py +22 -10
  61. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/lines/fit_gaussian.py +10 -2
  62. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/lines/fit_lorentzian.py +8 -2
  63. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/lines/fit_voigt.py +10 -2
  64. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/lines/vr_ratio.py +6 -3
  65. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/nebular/balmer_decrement_extinction.py +336 -0
  66. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/nebular/bpt_line_ratios.py +6 -2
  67. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/nebular/oiii_electron_temperature.py +6 -2
  68. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/nebular/sii_electron_density.py +5 -2
  69. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/quality/measure_resolving_power.py +284 -0
  70. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/quality/snr_der.py +22 -8
  71. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/quality/snr_edge.py +5 -3
  72. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/quality/snr_linear_fit.py +5 -3
  73. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/rv/cross_correlate.py +50 -28
  74. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/rv/measure.py +6 -2
  75. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/rv/precision_bouchy.py +11 -5
  76. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/rv/redshift_lines.py +5 -3
  77. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/smoothing/_kernel_uncertainty.py +122 -0
  78. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/smoothing/smooth_gaussian.py +28 -5
  79. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/smoothing/smooth_savgol.py +22 -5
  80. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/stacking/stack.py +213 -0
  81. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/timeseries/_light_curve.py +60 -0
  82. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/timeseries/box_least_squares.py +265 -0
  83. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/timeseries/phase_dispersion_minimization.py +226 -0
  84. spectro_kernel-0.8.0/src/spectro_kernel/algorithms/timeseries/temporal_variance_spectrum.py +333 -0
  85. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/transforms/combine_arithmetic.py +79 -9
  86. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/transforms/resample.py +23 -3
  87. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/cli.py +122 -5
  88. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/embeddings.py +10 -7
  89. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/errors.py +4 -0
  90. spectro_kernel-0.8.0/src/spectro_kernel/io/fits.py +914 -0
  91. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/pipeline.py +97 -13
  92. spectro_kernel-0.8.0/src/spectro_kernel/presets/__init__.py +37 -0
  93. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/presets/catalog/analysis/balmer_quick.yaml +2 -0
  94. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/presets/catalog/analysis/embed_quick.yaml +2 -0
  95. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/presets/catalog/analysis/quality_report.yaml +2 -0
  96. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/presets/catalog/analysis/rv_quick.yaml +2 -0
  97. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/presets/catalog/analysis/snr_check.yaml +2 -0
  98. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/presets/catalog/analysis/time_series_overview.yaml +2 -0
  99. spectro_kernel-0.8.0/src/spectro_kernel/presets/catalog/reduction/full_reduction_easyspec.yaml +113 -0
  100. spectro_kernel-0.8.0/src/spectro_kernel/presets/loader.py +351 -0
  101. spectro_kernel-0.8.0/src/spectro_kernel/presets/preset.schema.json +65 -0
  102. spectro_kernel-0.8.0/src/spectro_kernel/presets/variables.py +265 -0
  103. spectro_kernel-0.8.0/src/spectro_kernel/registry_export.py +334 -0
  104. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/types/enums.py +2 -0
  105. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/types/spectrum.py +36 -0
  106. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/version.py +1 -1
  107. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_mcp/auto_tools.py +18 -6
  108. spectro_kernel-0.8.0/src/spectro_mcp/py.typed +0 -0
  109. spectro_kernel-0.8.0/src/spectro_mcp/resources.py +184 -0
  110. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_mcp/server.py +11 -7
  111. spectro_kernel-0.8.0/tests/reference/cases.py +832 -0
  112. spectro_kernel-0.8.0/tests/reference/test_validation_cases.py +65 -0
  113. spectro_kernel-0.8.0/tests/unit/test_activity_bisector.py +174 -0
  114. spectro_kernel-0.8.0/tests/unit/test_activity_caii_hk.py +144 -0
  115. spectro_kernel-0.8.0/tests/unit/test_activity_halpha.py +81 -0
  116. spectro_kernel-0.8.0/tests/unit/test_combine.py +236 -0
  117. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_cross_correlate_extension.py +22 -8
  118. spectro_kernel-0.8.0/tests/unit/test_docs_generators.py +184 -0
  119. spectro_kernel-0.8.0/tests/unit/test_examples_run.py +63 -0
  120. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_extract_boxcar.py +99 -29
  121. spectro_kernel-0.8.0/tests/unit/test_extract_optimal.py +437 -0
  122. spectro_kernel-0.8.0/tests/unit/test_extraction_centring.py +108 -0
  123. spectro_kernel-0.8.0/tests/unit/test_flux_atmospheric_extinction.py +270 -0
  124. spectro_kernel-0.8.0/tests/unit/test_flux_balmer_decrement.py +170 -0
  125. spectro_kernel-0.8.0/tests/unit/test_flux_deredden_interstellar.py +134 -0
  126. spectro_kernel-0.8.0/tests/unit/test_flux_standard_star_reference.py +373 -0
  127. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_io.py +33 -0
  128. spectro_kernel-0.8.0/tests/unit/test_io_fits_zoo.py +476 -0
  129. spectro_kernel-0.8.0/tests/unit/test_mask_honoured.py +393 -0
  130. spectro_kernel-0.8.0/tests/unit/test_mcp_resources.py +159 -0
  131. spectro_kernel-0.8.0/tests/unit/test_normalize_spline.py +124 -0
  132. spectro_kernel-0.8.0/tests/unit/test_presets.py +366 -0
  133. spectro_kernel-0.8.0/tests/unit/test_resolving_power.py +151 -0
  134. spectro_kernel-0.8.0/tests/unit/test_timeseries_bls.py +157 -0
  135. spectro_kernel-0.8.0/tests/unit/test_timeseries_pdm.py +133 -0
  136. spectro_kernel-0.8.0/tests/unit/test_timeseries_tvs.py +210 -0
  137. spectro_kernel-0.8.0/tests/unit/test_uncertainty_propagation.py +331 -0
  138. spectro_kernel-0.8.0/tests/unit/test_vsini_fourier.py +200 -0
  139. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tools/docs/build.py +16 -4
  140. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tools/docs/generate.py +9 -1
  141. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tools/docs/generate_catalogue.py +21 -199
  142. spectro_kernel-0.8.0/tools/docs/generate_cli.py +275 -0
  143. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tools/docs/generate_llms.py +4 -0
  144. spectro_kernel-0.8.0/tools/docs/generate_mcp.py +362 -0
  145. spectro_kernel-0.8.0/tools/docs/generate_recipes.py +276 -0
  146. spectro_kernel-0.8.0/tools/docs/generate_validation.py +225 -0
  147. spectro_kernel-0.6.2/docs/cookbook/bess-dashboard.md +0 -118
  148. spectro_kernel-0.6.2/docs/tutorials/long-slit-reduction.md +0 -171
  149. spectro_kernel-0.6.2/src/spectro_kernel/algorithms/extraction/optimal.py +0 -403
  150. spectro_kernel-0.6.2/src/spectro_kernel/algorithms/io/read_fits.py +0 -53
  151. spectro_kernel-0.6.2/src/spectro_kernel/algorithms/stacking/stack.py +0 -110
  152. spectro_kernel-0.6.2/src/spectro_kernel/io/fits.py +0 -345
  153. spectro_kernel-0.6.2/src/spectro_kernel/presets/__init__.py +0 -7
  154. spectro_kernel-0.6.2/src/spectro_kernel/presets/catalog/reduction/full_reduction_easyspec.yaml +0 -68
  155. spectro_kernel-0.6.2/src/spectro_kernel/presets/loader.py +0 -83
  156. spectro_kernel-0.6.2/tests/unit/test_combine.py +0 -118
  157. spectro_kernel-0.6.2/tests/unit/test_extract_optimal.py +0 -178
  158. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/LICENSE +0 -0
  159. {spectro_kernel-0.6.2/docs → spectro_kernel-0.8.0/docs/.drafts}/notebooks/aurora-line-monitor.md +0 -0
  160. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/concepts/algorithms.md +0 -0
  161. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/concepts/architecture.md +0 -0
  162. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/contributing.md +0 -0
  163. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/cookbook/multi-star-viewer.md +0 -0
  164. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/cookbook/web-playground.md +0 -0
  165. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_cyg_ew_timeseries.png +0 -0
  166. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_cyg_halpha_phase_stack.png +0 -0
  167. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_cyg_halpha_timeseries.png +0 -0
  168. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_cyg_overlay.png +0 -0
  169. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_cyg_pc1_vs_phase.png +0 -0
  170. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_cyg_pca_2d.png +0 -0
  171. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_cyg_pca_3d.png +0 -0
  172. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_cyg_periodogram.png +0 -0
  173. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_cyg_phase_folded.png +0 -0
  174. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_cyg_rv_timeseries.png +0 -0
  175. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_cyg_similarity.png +0 -0
  176. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_cyg_similarity_date.png +0 -0
  177. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_dra_halpha_phase_stack.png +0 -0
  178. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_dra_pc1_vs_phase.png +0 -0
  179. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_dra_pca_2d.png +0 -0
  180. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_dra_pca_3d.png +0 -0
  181. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_dra_periodogram.png +0 -0
  182. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_dra_phase_folded.png +0 -0
  183. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_dra_rv_timeseries.png +0 -0
  184. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_dra_similarity_date.png +0 -0
  185. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/images/notebooks/alpha_dra_similarity_phase.png +0 -0
  186. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/notebooks/alpha-cyg-time-series.md +0 -0
  187. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/notebooks/alpha-dra-binary-period.md +0 -0
  188. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/notebooks/exoplanet-transit-rv.md +0 -0
  189. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/notebooks/native-vs-easyspec-showdown.md +0 -0
  190. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/notebooks/your-first-sb2.md +0 -0
  191. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/tutorials/add-an-algorithm.md +0 -0
  192. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/tutorials/analyse-a-spectrum.md +0 -0
  193. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/tutorials/discover-the-catalogue.md +0 -0
  194. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/tutorials/first-spectrum.md +0 -0
  195. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/docs/usage/library.md +0 -0
  196. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/__init__.py +0 -0
  197. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/adapters/__init__.py +0 -0
  198. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/adapters/easyspec.py +0 -0
  199. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/__init__.py +0 -0
  200. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/_common.py +0 -0
  201. {spectro_kernel-0.6.2/src/spectro_kernel/algorithms/classification → spectro_kernel-0.8.0/src/spectro_kernel/algorithms/activity}/__init__.py +0 -0
  202. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/advanced/__init__.py +0 -0
  203. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/advanced/aperture_photometry.py +0 -0
  204. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/advanced/disentangle_sb2.py +0 -0
  205. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/advanced/doppler_tomogram.py +0 -0
  206. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/catalogs/__init__.py +0 -0
  207. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/catalogs/gaia.py +0 -0
  208. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/catalogs/simbad.py +0 -0
  209. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/catalogs/vizier.py +0 -0
  210. {spectro_kernel-0.6.2/src/spectro_kernel/algorithms/embedding → spectro_kernel-0.8.0/src/spectro_kernel/algorithms/classification}/__init__.py +0 -0
  211. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/classification/classify_template_chi2.py +0 -0
  212. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/classification/pickles_atlas.py +0 -0
  213. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/continuum/__init__.py +0 -0
  214. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/corrections/__init__.py +0 -0
  215. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/corrections/air_vacuum.py +0 -0
  216. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/corrections/barycentric.py +0 -0
  217. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/corrections/doppler_shift.py +0 -0
  218. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/corrections/extinction_correct_easyspec.py +0 -0
  219. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/corrections/fit_telluric_scaling.py +0 -0
  220. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/corrections/flux_calibrate_easyspec.py +0 -0
  221. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/corrections/remove_telluric.py +0 -0
  222. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/corrections/response_from_standard.py +0 -0
  223. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/corrections/synth_telluric.py +0 -0
  224. {spectro_kernel-0.6.2/src/spectro_kernel/algorithms/kinematics → spectro_kernel-0.8.0/src/spectro_kernel/algorithms/embedding}/__init__.py +0 -0
  225. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/exports/__init__.py +0 -0
  226. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/exports/_bess_contract.py +0 -0
  227. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/exports/export_csv.py +0 -0
  228. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/exports/export_fits.py +0 -0
  229. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/exports/export_fits_bess.py +0 -0
  230. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/exports/export_hdf5.py +0 -0
  231. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/exports/export_votable.py +0 -0
  232. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/extraction/__init__.py +0 -0
  233. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/extraction/detect_trace.py +0 -0
  234. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/extraction/easyspec_extract.py +0 -0
  235. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/extraction/sky_lateral_bands.py +0 -0
  236. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/io/__init__.py +0 -0
  237. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/io/read_ascii.py +0 -0
  238. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/io/read_echelle.py +0 -0
  239. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/io/read_sdss.py +0 -0
  240. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/io/read_votable.py +0 -0
  241. {spectro_kernel-0.6.2/src/spectro_kernel/algorithms/nebular → spectro_kernel-0.8.0/src/spectro_kernel/algorithms/kinematics}/__init__.py +0 -0
  242. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/kinematics/rotation_curve.py +0 -0
  243. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/lines/__init__.py +0 -0
  244. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/lines/catalogs.py +0 -0
  245. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/lines/compare_line_fits.py +0 -0
  246. /spectro_kernel-0.6.2/src/spectro_kernel/py.typed → /spectro_kernel-0.8.0/src/spectro_kernel/algorithms/nebular/__init__.py +0 -0
  247. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/quality/__init__.py +0 -0
  248. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/quality/compare_snr_methods.py +0 -0
  249. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/quality/validate_bess_header.py +0 -0
  250. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/__init__.py +0 -0
  251. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/_easyspec_apply.py +0 -0
  252. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/_easyspec_helpers.py +0 -0
  253. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/bias_combine.py +0 -0
  254. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/clip_cosmic_rays.py +0 -0
  255. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/dark_combine.py +0 -0
  256. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/dark_subtract.py +0 -0
  257. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/denoise_2d.py +0 -0
  258. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/easyspec_bias.py +0 -0
  259. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/easyspec_cosmic_ray.py +0 -0
  260. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/easyspec_dark.py +0 -0
  261. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/easyspec_flat.py +0 -0
  262. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/easyspec_flat_normalize.py +0 -0
  263. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/easyspec_subtract_bias.py +0 -0
  264. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/easyspec_subtract_dark.py +0 -0
  265. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/extract_spectrum_sum.py +0 -0
  266. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/flat_combine.py +0 -0
  267. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/flat_normalize.py +0 -0
  268. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/geometry.py +0 -0
  269. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/subtract_sky_2d.py +0 -0
  270. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/reduction/wavelength_calibrate.py +0 -0
  271. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/rv/__init__.py +0 -0
  272. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/rv/fit_keplerian_orbit.py +0 -0
  273. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/smoothing/__init__.py +0 -0
  274. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/smoothing/_nan_bridge.py +0 -0
  275. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/smoothing/compare_smoothings.py +0 -0
  276. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/stacking/__init__.py +0 -0
  277. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/stacking/merge_echelle_orders.py +0 -0
  278. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/timeseries/__init__.py +0 -0
  279. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/timeseries/lomb_scargle.py +0 -0
  280. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/timeseries/phase_fold.py +0 -0
  281. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/transforms/__init__.py +0 -0
  282. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/transforms/clip_sigma.py +0 -0
  283. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/transforms/extract_region.py +0 -0
  284. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/transforms/mask_range.py +0 -0
  285. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/transforms/resample_flux_conserving.py +0 -0
  286. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/viz/__init__.py +0 -0
  287. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/viz/plot_3d_surface.py +0 -0
  288. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/viz/plot_animation.py +0 -0
  289. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/viz/plot_dynamic_spectrum.py +0 -0
  290. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/viz/plot_plotly.py +0 -0
  291. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/wavelength_calibration/__init__.py +0 -0
  292. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/wavelength_calibration/arc_geometry.py +0 -0
  293. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/wavelength_calibration/easyspec_wavelength.py +0 -0
  294. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/wavelength_calibration/in_situ.py +0 -0
  295. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/wavelength_calibration/lamp_atlas.py +0 -0
  296. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/wavelength_calibration/match_lamp.py +0 -0
  297. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/wavelength_calibration/reidentify.py +0 -0
  298. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/algorithms/wavelength_calibration/solar.py +0 -0
  299. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/base.py +0 -0
  300. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/io/__init__.py +0 -0
  301. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/io/ascii.py +0 -0
  302. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/io/votable.py +0 -0
  303. {spectro_kernel-0.6.2/src/spectro_mcp → spectro_kernel-0.8.0/src/spectro_kernel}/py.typed +0 -0
  304. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/registry.py +0 -0
  305. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/types/__init__.py +0 -0
  306. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/types/catalog.py +0 -0
  307. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/types/context.py +0 -0
  308. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/types/history.py +0 -0
  309. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/types/image.py +0 -0
  310. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/types/line.py +0 -0
  311. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/types/timeseries.py +0 -0
  312. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_kernel/url_safety.py +0 -0
  313. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_mcp/__init__.py +0 -0
  314. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_mcp/__main__.py +0 -0
  315. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_mcp/auth.py +0 -0
  316. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_mcp/observability.py +0 -0
  317. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_mcp/session.py +0 -0
  318. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/src/spectro_mcp/url_safety.py +0 -0
  319. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/conftest.py +0 -0
  320. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/reference/conftest.py +0 -0
  321. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/reference/test_known_answers.py +0 -0
  322. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/reference/test_sun.py +0 -0
  323. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/reference/test_vega.py +0 -0
  324. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_aperture_photometry.py +0 -0
  325. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_barycentric_bjd.py +0 -0
  326. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_base.py +0 -0
  327. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_catalog_queries_mocked.py +0 -0
  328. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_classify_template_chi2.py +0 -0
  329. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_cli.py +0 -0
  330. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_combine_arithmetic.py +0 -0
  331. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_continuum.py +0 -0
  332. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_corrections.py +0 -0
  333. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_dark_flat_combine.py +0 -0
  334. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_denoise_2d.py +0 -0
  335. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_detect_lines_blind.py +0 -0
  336. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_detect_trace.py +0 -0
  337. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_disentangle_sb2.py +0 -0
  338. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_doppler_tomogram.py +0 -0
  339. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_easyspec_apply_staging.py +0 -0
  340. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_easyspec_sessions.py +0 -0
  341. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_easyspec_wrappers.py +0 -0
  342. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_embedding.py +0 -0
  343. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_embedding_pretrained.py +0 -0
  344. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_embedding_remote_lick.py +0 -0
  345. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_embedding_tier1.py +0 -0
  346. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_export_fits_bess.py +0 -0
  347. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_export_hdf5.py +0 -0
  348. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_extract_spectrum_sum.py +0 -0
  349. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_flux_calibrate_easyspec.py +0 -0
  350. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_geometry_corrections.py +0 -0
  351. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_lamp_atlas_match.py +0 -0
  352. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_line_profiles.py +0 -0
  353. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_lines.py +0 -0
  354. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_mcp.py +0 -0
  355. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_mcp_http_entry.py +0 -0
  356. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_mcp_param_guard.py +0 -0
  357. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_mcp_production.py +0 -0
  358. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_mcp_security.py +0 -0
  359. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_mcp_tools_extra.py +0 -0
  360. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_measure_arc_geometry.py +0 -0
  361. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_misc_algorithms.py +0 -0
  362. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_nebular_diagnostics.py +0 -0
  363. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_no_circular_imports.py +0 -0
  364. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_normalize_to_region.py +0 -0
  365. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_output_produces_contract.py +0 -0
  366. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_pipeline.py +0 -0
  367. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_quality.py +0 -0
  368. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_read_sdss.py +0 -0
  369. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_redshift_lines.py +0 -0
  370. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_registry.py +0 -0
  371. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_reidentify.py +0 -0
  372. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_resample_flux_conserving.py +0 -0
  373. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_response_from_standard.py +0 -0
  374. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_rotation_curve.py +0 -0
  375. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_rv_precision_bouchy.py +0 -0
  376. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_sky_lateral_bands.py +0 -0
  377. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_smoothing.py +0 -0
  378. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_timeseries.py +0 -0
  379. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_transforms.py +0 -0
  380. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_types.py +0 -0
  381. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_url_safety_kernel.py +0 -0
  382. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_validate_bess_header.py +0 -0
  383. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_viz.py +0 -0
  384. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_vr_ratio.py +0 -0
  385. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_wavelength_calibration_in_situ.py +0 -0
  386. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tests/unit/test_wavelength_calibration_solar.py +0 -0
  387. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tools/docs/__init__.py +0 -0
  388. {spectro_kernel-0.6.2 → spectro_kernel-0.8.0}/tools/docs/netlify.toml +0 -0
@@ -166,8 +166,12 @@ venv.bak/
166
166
 
167
167
  # documentation - generated by tools/docs/generate.py
168
168
  docs/algorithms/
169
+ docs/recipes/catalogue/
170
+ docs/validation/catalogue/
169
171
  docs/ai/
170
172
  docs/llms.txt
173
+ docs/reference/cli.md
174
+ docs/reference/mcp.md
171
175
 
172
176
  # mkdocs documentation
173
177
  /site
@@ -0,0 +1,419 @@
1
+ # AGENTS.md — guidance for AI-assisted contributors
2
+
3
+ > Read this file end-to-end before adding code or proposing changes.
4
+ > It is the standing brief for **coding agents that modify spectro-kernel**
5
+ > (Claude Code loads it through `CLAUDE.md`; other agents read it directly).
6
+ > It supplements [CONTRIBUTING.md](CONTRIBUTING.md) (the human-oriented
7
+ > contributor guide) with the guard-rails that matter most when an AI is at
8
+ > the keyboard. The complementary file for agents that *use* the library is
9
+ > `docs/llms.txt` (generated, published at https://docs.spectrokernel.io/llms.txt):
10
+ > `AGENTS.md` says how an AI modifies spectro-kernel, `llms.txt` how an AI
11
+ > understands and uses it.
12
+
13
+ ---
14
+
15
+ ## 1. What the project is
16
+
17
+ `spectro-kernel` is a shared catalogue of **astronomical spectroscopy
18
+ algorithms grounded in the published literature**. The whole library
19
+ exists so that the *N*-th project that needs continuum normalisation
20
+ doesn't write a slightly-different *N*-th version. Every contribution
21
+ must keep that invariant true.
22
+
23
+ One catalogue, three doors: the Python library, the `spectro` CLI and the
24
+ `spectro-mcp` MCP server all read the same registry. **Functional parity
25
+ between the three is an invariant**, and the documentation for all three is
26
+ generated from the code (see §7).
27
+
28
+ ---
29
+
30
+ ## 2. The non-negotiables
31
+
32
+ **Before** writing or proposing an algorithm :
33
+
34
+ 1. **Is it already in the catalogue?** Run :
35
+ ```bash
36
+ .venv/bin/python -c "from spectro_kernel.registry import ensure_discovered, list_algorithms; \
37
+ ensure_discovered(); \
38
+ print('\n'.join(sorted(a['name'] for a in list_algorithms())))"
39
+ ```
40
+ Search the printed list with grep for related keywords *and* for the
41
+ nearest astronomical idiom (`bpt`, `nebular`, `redshift`,
42
+ `template`, `tomogr`, etc.). When in doubt, ask. **Duplicates are
43
+ rejected.**
44
+
45
+ 2. **Is it in the literature?** Every algorithm must cite at least
46
+ **one peer-reviewed reference** (paper, textbook, IRAF / specutils
47
+ / pPXF documentation) in its `references = […]` class attribute.
48
+ Reproduce the published formula / coefficients **verbatim** when
49
+ possible — `stuff/spectro_kernel_spec_25_06_26.md` is a worked
50
+ example. If you have to derive a coefficient yourself, that's a
51
+ research project, not a kernel contribution.
52
+
53
+ 3. **Are the references real?** Verify each citation against the
54
+ paper's abstract (arXiv / ADS / publisher DOI). A reference that
55
+ doesn't exist (or that doesn't say what you claim it says) is an
56
+ immediate revert.
57
+
58
+ 4. **Is it overlapping with astropy / specutils / pPXF / pypeit?** If
59
+ one of those tools already does the job in importable form, prefer
60
+ to **wrap** rather than re-implement. Set `backend = "astropy"` /
61
+ `"specutils"` / `"easyspec"` and forward — the catalogue layer
62
+ makes the wrap the *one* canonical entry point.
63
+
64
+ 5. **Will the implementation fit on a shelf?** The library's contract
65
+ is "one algorithm = one Python file = one `BaseAlgorithm`
66
+ subclass". If the design needs new context fields, a new pipeline
67
+ primitive, or new MCP plumbing, stop and discuss — those changes
68
+ ripple through every other algorithm and need separate review.
69
+
70
+ If you cannot answer **yes** to all five questions, do not push code.
71
+
72
+ ### Anti-patterns (rejected on sight)
73
+
74
+ - **Fabricated references.** "Smith et al. 2021" that nobody can find
75
+ in ADS is an automatic revert. Verify before citing.
76
+ - **Domain hand-waving.** "Standard astronomy practice" is not a
77
+ reference. Cite the paper that establishes the formula.
78
+ - **Duplicates.** "It's slightly different" is rarely true. If the
79
+ result is genuinely different, *why* — and is that documented as a
80
+ caveat in both bricks' `long_description`? (Example of valid
81
+ coexistence : `extract_spectrum_boxcar` vs `extract_spectrum_optimal`
82
+ — both are Horne-flavoured but the optimal variant adds variance +
83
+ cosmic rejection. The two `long_description`s cross-reference each
84
+ other so users can pick.)
85
+ - **API drift.** Don't introduce a new `ctx.something` field, a new
86
+ return-type shape, or a new registration mechanism. The triple
87
+ surface (Python library, CLI, MCP) is generated from the registry —
88
+ any drift breaks one of them silently.
89
+ - **ML-flashy reinvention.** A "Bayesian-deep-something" wrapper of a
90
+ classical algorithm is not a new algorithm if it doesn't change the
91
+ published method. Keep the kernel boring on purpose.
92
+ - **Inventing parameter names that don't match the literature.** If
93
+ the paper says ``R = F(6716)/F(6731)``, your variable is `R` and
94
+ your param is `lambda_6716` — not `lhs_line_a`.
95
+ - **Hardcoded paths to home directories, network fetches at import
96
+ time, secret tokens.** None of those belong in a kernel algorithm.
97
+
98
+ ### The kernel philosophy (the "why")
99
+
100
+ If you have to pick between two options, the right one is usually the
101
+ one closest to these principles :
102
+
103
+ - **Literature over invention.** The kernel is a curated archive of
104
+ *published* recipes. We do not invent algorithms here.
105
+ - **One algorithm = one shelf brick.** Composability comes from
106
+ pipelines composing bricks, not from monolithic super-algorithms.
107
+ - **No surprise.** Every algorithm declares its `backend`, its
108
+ `references`, its `default_params` and its `output_produces`. The
109
+ registry is a contract — code without metadata is rejected.
110
+ - **Provenance is a feature.** Each `BaseAlgorithm.execute` writes a
111
+ `ProcessingStep` into `ctx.history` (parameters, input hash, output
112
+ hash, duration, success). Don't bypass it.
113
+ - **Determinism by default.** Random sources are explicit (seeded
114
+ from `params`), file I/O is explicit, network calls are explicit
115
+ and lazy (inside `run()`, never at module import).
116
+ - **Triple surface.** Every algorithm becomes a Python function, a
117
+ `spectro run` CLI command **and** an MCP tool — for free. Don't write
118
+ per-surface code.
119
+ - **No data in the wheel.** Catalogues / atlases / templates are
120
+ loaded on demand from disk (see
121
+ [`algorithms/wavelength_calibration/lamp_atlas.py`](src/spectro_kernel/algorithms/wavelength_calibration/lamp_atlas.py)
122
+ for a small bundled one, and
123
+ [`algorithms/classification/pickles_atlas.py`](src/spectro_kernel/algorithms/classification/pickles_atlas.py)
124
+ for the externally-fetched variant). Keep the install size honest.
125
+
126
+ ---
127
+
128
+ ## 3. Architecture (memorise this)
129
+
130
+ ```
131
+ src/spectro_kernel/ the importable library — the catalogue
132
+ types/ Spectrum1D, WorkContext, ProcessingStep, LineFitResult, enums
133
+ base.py BaseAlgorithm + AlgorithmOutput (the algorithm contract)
134
+ registry.py @register_algorithm, discovery, list/describe/run_algorithm
135
+ registry_export.py the ONE builder of the catalogue JSON (algorithms + recipes)
136
+ pipeline.py Pipeline, PipelineBuilder (from_preset), PipelineResult
137
+ presets/ recipe loader, variables, validation, bundled catalog/*.yaml
138
+ io/ FITS / ASCII / VOTable readers and writers
139
+ algorithms/<category>/ one file per algorithm — auto-discovered
140
+ cli.py the `spectro` command (argparse, build_parser())
141
+ src/spectro_mcp/ the MCP server over the same registry
142
+ server.py build_server(): FastMCP + tools + resources + /health, /metrics
143
+ auto_tools.py 13 session/discovery tools + one tool per algorithm, path/URL guards
144
+ resources.py spectro://algorithms, spectro://recipes, spectro://llms.txt
145
+ tools/docs/ documentation generators (§7), build.py = what CI runs
146
+ docs/ the documentation site source (Markdown, Zensical / MkDocs)
147
+ examples/ executable, deterministic examples run by CI
148
+ tests/unit/ the test suite (one test file per brick or feature)
149
+ website/ the public landing page (React) — separate from docs/
150
+ ```
151
+
152
+ ### The algorithm pattern
153
+
154
+ Every algorithm follows this pattern (see e.g.
155
+ [`src/spectro_kernel/algorithms/continuum/normalize_polynomial.py`](src/spectro_kernel/algorithms/continuum/normalize_polynomial.py),
156
+ [`src/spectro_kernel/algorithms/nebular/oiii_electron_temperature.py`](src/spectro_kernel/algorithms/nebular/oiii_electron_temperature.py)) :
157
+
158
+ ```python
159
+ from __future__ import annotations
160
+ from typing import Any
161
+
162
+ import numpy as np
163
+
164
+ from ...base import AlgorithmOutput, BaseAlgorithm
165
+ from ...errors import InvalidParameterError
166
+ from ...registry import register_algorithm
167
+ from ...types import AlgorithmCategory, WorkContext
168
+
169
+
170
+ @register_algorithm("name", category=AlgorithmCategory.SOMETHING, version="1.0.0")
171
+ class MyAlgorithm(BaseAlgorithm):
172
+ """One-line summary (becomes the registry description)."""
173
+
174
+ backend = "numpy" # numpy | scipy | astropy | specutils | …
175
+ references = ["Author YYYY, Journal vol, page — short note."]
176
+ long_description = "Optional richer paragraph with caveats / regime of validity."
177
+ default_params = {"threshold": 3.0}
178
+ required_params = ["threshold"] # only when there is no sensible default
179
+ param_descriptions = {"threshold": "…"}
180
+ input_requirements = ["spectrum"] # "image" | "spectrum" | "spectra" | "images"
181
+ output_produces = ["metrics.x"] # documentation only
182
+
183
+ def run(self, ctx: WorkContext, params: dict[str, Any]) -> AlgorithmOutput:
184
+ spec = ctx.spectrum
185
+ if spec is None:
186
+ return AlgorithmOutput.fail("…")
187
+ # …
188
+ return AlgorithmOutput.ok(metrics={...}, message="…")
189
+ ```
190
+
191
+ **Auto-discovery** picks the file up from its category directory at
192
+ import time — no registry edit required. The metadata is the contract:
193
+ it feeds `spectro describe`, the MCP tool description, the catalogue
194
+ page and the machine-readable JSON, all generated.
195
+
196
+ ### Context conventions (do NOT add new fields)
197
+
198
+ | Data | Slot | Type |
199
+ |---|---|---|
200
+ | current 2-D frame | `ctx.image` | `ImageFrame` |
201
+ | current 1-D spectrum | `ctx.spectrum` | `Spectrum1D` |
202
+ | list of 2-D frames | `ctx.images` | `list[ImageFrame]` |
203
+ | list of 1-D spectra | `ctx.spectra` | `list[Spectrum1D]` |
204
+ | **second spectrum** (template, reference, sky, std) | `ctx.extras["<key>"]` | `Spectrum1D` |
205
+ | scalar metrics (JSON-safe) | `ctx.metrics` | `dict[str, float]` |
206
+ | line fits | `ctx.line_fits` | `dict[str, LineFitResult]` |
207
+ | anything else (artefacts, intermediate state) | `ctx.extras["<key>"]` | any JSON-safe |
208
+
209
+ **The "second spectrum lives in `ctx.extras`" rule is invariant.**
210
+ Examples: `remove_telluric_division` reads
211
+ `ctx.extras["telluric_spectrum"]`,
212
+ `combine_spectra_arithmetic` reads `ctx.extras["reference_spectrum"]`,
213
+ `response_from_standard` writes `ctx.extras["reference_spectrum"]`,
214
+ `extract_sky_lateral_bands` writes `ctx.extras["sky_spectrum"]`. If
215
+ your algorithm needs another spectrum, follow the same convention with
216
+ a self-documenting key.
217
+
218
+ ### Categories
219
+
220
+ `AlgorithmCategory` is the curated taxonomy
221
+ ([`src/spectro_kernel/types/enums.py`](src/spectro_kernel/types/enums.py)).
222
+ Use an existing member when possible. New categories require :
223
+
224
+ 1. a real use case (3+ algorithms or a clear domain gap),
225
+ 2. an enum entry,
226
+ 3. a friendly title in `CATEGORY_TITLES` of
227
+ [`src/spectro_kernel/registry_export.py`](src/spectro_kernel/registry_export.py)
228
+ (shared by the docs generators and the MCP resources),
229
+ 4. an update to the website catalogue group if the brick is
230
+ user-facing (see
231
+ [`website/components/sections.jsx`](website/components/sections.jsx)).
232
+
233
+ Adding a category is fine — the v0.4.0 release added `nebular`,
234
+ `kinematics` and `classification`. Don't add a category for one algo
235
+ unless the domain really is new.
236
+
237
+ ### The MCP layer
238
+
239
+ `spectro_mcp` depends on `spectro_kernel`, never the reverse. Tools are
240
+ generated from the registry in
241
+ [`src/spectro_mcp/auto_tools.py`](src/spectro_mcp/auto_tools.py) (one tool
242
+ per algorithm, plus 13 session / discovery tools); the catalogue is also
243
+ readable as resources in
244
+ [`src/spectro_mcp/resources.py`](src/spectro_mcp/resources.py)
245
+ (`spectro://algorithms`, `spectro://algorithms/{name}`, `spectro://recipes`,
246
+ `spectro://recipes/{name}`, `spectro://llms.txt`), backed by
247
+ `registry_export.py`. Safety (path / URL guards, masking, deny mode) lives
248
+ at the MCP layer; kernel algorithms stay policy-free. In HTTP deny mode
249
+ nothing may disclose an install path.
250
+
251
+ ---
252
+
253
+ ## 4. Recipes (presets) and profiles
254
+
255
+ A **recipe** (`src/spectro_kernel/presets/catalog/*.yaml`, or an installed
256
+ collection) composes bricks with the scientific conventions fixed;
257
+ everything that depends on an instrument or an observer is a declared
258
+ **variable**, bound at run time by a **profile** (`--profile`, `--set`,
259
+ `variables=`). The loader lives in
260
+ [`src/spectro_kernel/presets/`](src/spectro_kernel/presets/) (variables,
261
+ discovery through `SPECTRO_PRESET_PATH` and the `spectro_kernel.presets`
262
+ entry-point group, validation, `requires` range), the engine records a
263
+ `pipeline:<name>` provenance step at the end of every named recipe run.
264
+ Rules: a recipe never hard-codes an instrument value, never introduces a
265
+ brick, and campaign recipes cite references. The kernel bundles only
266
+ generic recipes; campaign recipes belong to
267
+ [spectro-kernel-recipes](https://github.com/matthieulel/spectro-kernel-recipes).
268
+ `spectro preset validate` is the gate.
269
+
270
+ ---
271
+
272
+ ## 5. Commands and environment
273
+
274
+ - Project root: `/Users/matthieu/lab/meta-spectro/spectro-kernel`
275
+ - Python : 3.12 (managed via `pyenv` ; project venv at `.venv/`).
276
+ - Run any tool via `.venv/bin/<tool>` (e.g. `.venv/bin/pytest`).
277
+ - Install for development: `uv pip install -e ".[dev,mcp]"` (add `docs`
278
+ to build the site, `all` for every optional extra).
279
+ - Lint / format: `.venv/bin/python -m ruff check src tests tools examples`
280
+ and `.venv/bin/python -m ruff format <files>` (line length 100, rules
281
+ `E F I UP B W`, see `pyproject.toml`). CI runs `ruff check src tests`.
282
+ - Docs : `.venv/bin/python tools/docs/generate.py && .venv/bin/zensical serve`
283
+ then open http://127.0.0.1:8000. Published at https://docs.spectrokernel.io/.
284
+ - MCP server stdio mode : `.venv/bin/spectro-mcp` (cloud HTTP variant
285
+ deployed on DigitalOcean).
286
+ - Examples : `.venv/bin/python examples/<file>.py` (each is
287
+ self-contained, deterministic, offline).
288
+
289
+ If you are inside Claude Code, your tools are : `Read`, `Edit`,
290
+ `Write`, `Bash`, `Agent`. Stay inside the project working directory ;
291
+ never run commands that touch `~` or `/etc`.
292
+
293
+ ---
294
+
295
+ ## 6. Tests (required for every contribution)
296
+
297
+ Each new algorithm ships with **at least one** test in `tests/unit/`.
298
+ The test must :
299
+
300
+ 1. Build a synthetic input where the right answer is **known
301
+ analytically from the cited literature** (e.g.
302
+ `tests/unit/test_nebular_diagnostics.py::test_oiii_inversion_acceptance_values`
303
+ exercises Eq. 1 from Aller 1984 directly).
304
+ 2. Assert on the numerical result with a tolerance that reflects the
305
+ method's known precision — not blindly tight, not generously loose.
306
+ 3. Cover at least one failure path (parameter validation, missing
307
+ input, regime out of validity).
308
+
309
+ When the spec we are porting from already lists *acceptance values*
310
+ (STAROS-style spec docs), put them in the test docstring verbatim.
311
+
312
+ Scientific validation against real data lives in `tests/reference/`
313
+ (known-answer tests on reference spectra); a brick that claims a published
314
+ precision should be checked there when reference data exists.
315
+
316
+ Run before pushing :
317
+
318
+ ```bash
319
+ .venv/bin/python -m pytest tests/ # the whole suite must pass
320
+ .venv/bin/python -m ruff check src tests tools examples # clean
321
+ .venv/bin/python tools/docs/build.py # generators + zensical build --strict, clean
322
+ .venv/bin/python -m build && .venv/bin/python -m twine check --strict dist/*
323
+ ```
324
+
325
+ ---
326
+
327
+ ## 7. Documentation requirements and how the generated docs work
328
+
329
+ The documentation is generated from the code wherever a source of truth
330
+ exists; **never edit a generated file**, edit the generator or the metadata
331
+ it reads. Generated outputs are git-ignored (`.gitignore`, "documentation"
332
+ block) and rebuilt by `tools/docs/generate.py` (called by `build.py`, by
333
+ CI and by Netlify):
334
+
335
+ | Generator | Reads | Writes |
336
+ |---|---|---|
337
+ | `tools/docs/generate_catalogue.py` | the registry | `docs/algorithms/**`, `docs/ai/algorithms.json` + schema |
338
+ | `tools/docs/generate_recipes.py` | the presets loader | `docs/recipes/catalogue/**`, `docs/ai/presets.json` |
339
+ | `tools/docs/generate_cli.py` | `spectro_kernel.cli.build_parser()` | `docs/reference/cli.md` |
340
+ | `tools/docs/generate_mcp.py` | `spectro_mcp.server.build_server()` | `docs/reference/mcp.md`, `docs/ai/mcp-tools.json` |
341
+ | `tools/docs/generate_llms.py` | `mkdocs.yml` nav + page descriptions | `docs/llms.txt` |
342
+
343
+ The JSON builders live in `src/spectro_kernel/registry_export.py` so the
344
+ published JSON and the MCP resources are one implementation. Hand-written
345
+ pages (`docs/concepts`, `docs/usage`, `docs/tutorials`, `docs/reference/python.md`)
346
+ link to the generated ones; the nav is in `mkdocs.yml`. `build.py` runs
347
+ Zensical in `--strict` mode: a broken link or a missing page fails CI.
348
+
349
+ A new algorithm needs **no** documentation edit: its docstring and
350
+ metadata become its page, its MCP tool description and its JSON entry. A
351
+ new CLI flag or MCP tool is documented on the next build. A new
352
+ user-facing feature gets a paragraph in the relevant `docs/usage` or
353
+ `docs/concepts` page and, when it can be shown in under 60 lines, an
354
+ example in `examples/` (deterministic, offline, registered in
355
+ `tests/unit/test_examples_run.py`, which CI runs).
356
+
357
+ ---
358
+
359
+ ## 8. Versioning
360
+
361
+ - **PATCH** (`0.x.y → 0.x.(y+1)`) : bug fix + at most one small
362
+ incremental addition (cf. v0.2.1 — uint16 BZERO leak fix + one new
363
+ `extract_spectrum_boxcar` brick).
364
+ - **MINOR** (`0.x → 0.(x+1)`) : substantive feature add (cf. v0.2.0 —
365
+ 13 long-slit bricks ; v0.4.0 — 8 science bricks + 3 new categories).
366
+ - **MAJOR** (`0.x → 1.0+`) : only after a `1.0.0` API freeze decision.
367
+
368
+ Bump the **algorithm's own** `version` attribute on any behaviour
369
+ change so old results stay reproducible. Numerical change → MAJOR
370
+ attribute bump (`1.0.0 → 2.0.0`). Performance / docstring → MINOR /
371
+ PATCH.
372
+
373
+ ---
374
+
375
+ ## 9. Release flow (when asked to ship)
376
+
377
+ 1. Update [CHANGELOG.md](CHANGELOG.md) with full per-algorithm notes
378
+ (every new brick named, every reference cited, numeric impact
379
+ measured when relevant — see the v0.2.1 / v0.3.0 / v0.4.0 entries
380
+ for the expected level of detail).
381
+ 2. Bump [`src/spectro_kernel/version.py`](src/spectro_kernel/version.py).
382
+ 3. Update the website counters / catalogue group entries in
383
+ [`website/app.jsx`](website/app.jsx) and
384
+ [`website/components/sections.jsx`](website/components/sections.jsx).
385
+ 4. Run the pre-flight quartet from section 6.
386
+ 5. Commit, push, tag (`git tag -a vX.Y.Z -m "…"`), push the tag.
387
+ 6. The
388
+ [`release.yml`](.github/workflows/release.yml)
389
+ GitHub Action runs the test matrix, builds the wheel + sdist, and
390
+ publishes to PyPI via Trusted Publisher OIDC (no token in the
391
+ repo). Watch the run ; PyPI propagation usually completes within
392
+ one minute of workflow success.
393
+
394
+ ---
395
+
396
+ ## 10. When to escalate to the user
397
+
398
+ Surface a decision to the user (rather than guessing) when :
399
+
400
+ - A new external dependency would land in the wheel (changes the
401
+ install footprint).
402
+ - A change would affect the public registry contract (renaming an
403
+ algorithm, removing a parameter, changing a return shape).
404
+ - A pipeline's deterministic output would shift numerically (algorithm
405
+ MAJOR bump scenario).
406
+ - A release would skip a version on PyPI (cf. the v0.1.5 re-tag
407
+ scenario).
408
+ - The proposed addition is genuinely on the boundary between "shelf
409
+ brick" and "downstream application" — when in doubt, the kernel
410
+ errs on the side of being smaller.
411
+
412
+ For everything routine — implementing a brick whose spec is unambiguous,
413
+ fixing a clear bug, refreshing docs — proceed and report.
414
+
415
+ ---
416
+
417
+ *This file is the standing brief for AI contributors. Keep it short —
418
+ human contributors read [CONTRIBUTING.md](CONTRIBUTING.md), AI
419
+ contributors read both.*