specmod 0.3.0__tar.gz → 0.5.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 (272) hide show
  1. specmod-0.5.0/.release-please-manifest.json +3 -0
  2. {specmod-0.3.0 → specmod-0.5.0}/CHANGELOG.md +61 -0
  3. {specmod-0.3.0 → specmod-0.5.0}/PKG-INFO +1 -1
  4. {specmod-0.3.0 → specmod-0.5.0}/datasets/magna_2020.toml +6 -0
  5. {specmod-0.3.0 → specmod-0.5.0}/docs/REFACTOR_PLAN.md +108 -20
  6. {specmod-0.3.0 → specmod-0.5.0}/docs/choosing-a-transform.md +84 -0
  7. {specmod-0.3.0 → specmod-0.5.0}/docs/development.md +2 -1
  8. {specmod-0.3.0 → specmod-0.5.0}/docs/releasing-data.md +47 -0
  9. {specmod-0.3.0 → specmod-0.5.0}/docs/roadmap.md +89 -8
  10. {specmod-0.3.0 → specmod-0.5.0}/docs/upgrading.md +42 -3
  11. specmod-0.5.0/src/specmod/acquire.py +643 -0
  12. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/config/sections.py +32 -4
  13. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/core/collection.py +103 -17
  14. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/pipeline.py +41 -0
  15. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/smoothing/__init__.py +14 -2
  16. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/smoothing/base.py +16 -1
  17. specmod-0.5.0/src/specmod/smoothing/log_window.py +215 -0
  18. specmod-0.5.0/src/specmod/smoothing/savitzky_golay.py +127 -0
  19. {specmod-0.3.0 → specmod-0.5.0}/tests/golden/motion_reference.json +140 -0
  20. {specmod-0.3.0 → specmod-0.5.0}/tests/golden/pipeline_reference.json +140 -0
  21. {specmod-0.3.0 → specmod-0.5.0}/tests/golden/window_reference.json +140 -0
  22. specmod-0.5.0/tests/test_acquire.py +865 -0
  23. {specmod-0.3.0 → specmod-0.5.0}/tests/test_config.py +99 -1
  24. {specmod-0.3.0 → specmod-0.5.0}/tests/test_golden_reference.py +70 -0
  25. {specmod-0.3.0 → specmod-0.5.0}/tests/test_pipeline.py +123 -1
  26. {specmod-0.3.0 → specmod-0.5.0}/tests/test_release_config.py +88 -0
  27. specmod-0.5.0/tests/test_smoothing.py +431 -0
  28. specmod-0.5.0/tests/test_tools_track_the_api.py +125 -0
  29. {specmod-0.3.0 → specmod-0.5.0}/tools/make_golden.py +34 -4
  30. {specmod-0.3.0 → specmod-0.5.0}/tools/measure_docs.py +106 -6
  31. specmod-0.3.0/.release-please-manifest.json +0 -3
  32. specmod-0.3.0/src/specmod/acquire.py +0 -358
  33. specmod-0.3.0/tests/test_acquire.py +0 -375
  34. specmod-0.3.0/tests/test_smoothing.py +0 -226
  35. {specmod-0.3.0 → specmod-0.5.0}/.git-blame-ignore-revs +0 -0
  36. {specmod-0.3.0 → specmod-0.5.0}/.github/workflows/build.yml +0 -0
  37. {specmod-0.3.0 → specmod-0.5.0}/.github/workflows/docs.yml +0 -0
  38. {specmod-0.3.0 → specmod-0.5.0}/.github/workflows/release.yml +0 -0
  39. {specmod-0.3.0 → specmod-0.5.0}/.github/workflows/test.yml +0 -0
  40. {specmod-0.3.0 → specmod-0.5.0}/.gitignore +0 -0
  41. {specmod-0.3.0 → specmod-0.5.0}/.pre-commit-config.yaml +0 -0
  42. {specmod-0.3.0 → specmod-0.5.0}/.readthedocs.yaml +0 -0
  43. {specmod-0.3.0 → specmod-0.5.0}/AGENTS.md +0 -0
  44. {specmod-0.3.0 → specmod-0.5.0}/CITATION.cff +0 -0
  45. {specmod-0.3.0 → specmod-0.5.0}/CLAUDE.md +0 -0
  46. {specmod-0.3.0 → specmod-0.5.0}/CONTRIBUTING.md +0 -0
  47. {specmod-0.3.0 → specmod-0.5.0}/LICENSE +0 -0
  48. {specmod-0.3.0 → specmod-0.5.0}/README.md +0 -0
  49. {specmod-0.3.0 → specmod-0.5.0}/datasets/pnr_2019.toml +0 -0
  50. {specmod-0.3.0 → specmod-0.5.0}/docs/_builders/_notebook.py +0 -0
  51. {specmod-0.3.0 → specmod-0.5.0}/docs/_builders/choosing_a_transform.py +0 -0
  52. {specmod-0.3.0 → specmod-0.5.0}/docs/_builders/specmod_tutorial.py +0 -0
  53. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/academic.css +0 -0
  54. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts/OFL-fira-code.txt +0 -0
  55. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts/OFL-merriweather.txt +0 -0
  56. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts/OFL-open-sans.txt +0 -0
  57. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts/README.md +0 -0
  58. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts/fira-code-400-greek.woff2 +0 -0
  59. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts/fira-code-400-latin-ext.woff2 +0 -0
  60. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts/fira-code-400-latin.woff2 +0 -0
  61. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts/merriweather-latin-ext.woff2 +0 -0
  62. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts/merriweather-latin.woff2 +0 -0
  63. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts/open-sans-greek.woff2 +0 -0
  64. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts/open-sans-latin-ext.woff2 +0 -0
  65. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts/open-sans-latin.woff2 +0 -0
  66. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/fonts.css +0 -0
  67. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/LICENSE +0 -0
  68. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/README.md +0 -0
  69. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  70. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  71. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  72. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  73. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  74. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  75. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  76. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  77. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  78. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  79. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  80. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  81. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  82. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  83. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  84. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  85. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  86. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  87. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  88. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  89. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/katex/katex.min.css +0 -0
  90. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/specmod-logo-academic-dark-mark.svg +0 -0
  91. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/specmod-logo-academic-dark.svg +0 -0
  92. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/specmod-logo-academic-mark.svg +0 -0
  93. {specmod-0.3.0 → specmod-0.5.0}/docs/_static/specmod-logo-academic.svg +0 -0
  94. {specmod-0.3.0 → specmod-0.5.0}/docs/api.md +0 -0
  95. {specmod-0.3.0 → specmod-0.5.0}/docs/branding.md +0 -0
  96. {specmod-0.3.0 → specmod-0.5.0}/docs/conf.py +0 -0
  97. {specmod-0.3.0 → specmod-0.5.0}/docs/contributing.md +0 -0
  98. {specmod-0.3.0 → specmod-0.5.0}/docs/documentation.md +0 -0
  99. {specmod-0.3.0 → specmod-0.5.0}/docs/getting-started.md +0 -0
  100. {specmod-0.3.0 → specmod-0.5.0}/docs/guides.md +0 -0
  101. {specmod-0.3.0 → specmod-0.5.0}/docs/index.md +0 -0
  102. {specmod-0.3.0 → specmod-0.5.0}/docs/notebooks/choosing-a-transform.ipynb +0 -0
  103. {specmod-0.3.0 → specmod-0.5.0}/docs/notes/api-audit.md +0 -0
  104. {specmod-0.3.0 → specmod-0.5.0}/docs/notes/window-position.md +0 -0
  105. {specmod-0.3.0 → specmod-0.5.0}/docs/pick-formats.md +0 -0
  106. {specmod-0.3.0 → specmod-0.5.0}/docs/processing.md +0 -0
  107. {specmod-0.3.0 → specmod-0.5.0}/docs/releasing.md +0 -0
  108. {specmod-0.3.0 → specmod-0.5.0}/pyproject.toml +0 -0
  109. {specmod-0.3.0 → specmod-0.5.0}/release-please-config.json +0 -0
  110. {specmod-0.3.0 → specmod-0.5.0}/requirements.txt +0 -0
  111. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/__init__.py +0 -0
  112. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/_vendor/__init__.py +0 -0
  113. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/_vendor/qiinv.py +0 -0
  114. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/api.py +0 -0
  115. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/cli.py +0 -0
  116. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/config/__init__.py +0 -0
  117. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/config/layers.py +0 -0
  118. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/config/provenance.py +0 -0
  119. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/config/serialize.py +0 -0
  120. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/core/__init__.py +0 -0
  121. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/core/bandwidth.py +0 -0
  122. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/core/noise.py +0 -0
  123. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/core/scalogram.py +0 -0
  124. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/core/spectrum.py +0 -0
  125. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/core/units.py +0 -0
  126. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/datasets.py +0 -0
  127. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/distance.py +0 -0
  128. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/exceptions.py +0 -0
  129. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/fitting/__init__.py +0 -0
  130. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/fitting/base.py +0 -0
  131. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/fitting/event.py +0 -0
  132. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/fitting/guess.py +0 -0
  133. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/fitting/spectrum.py +0 -0
  134. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/io/__init__.py +0 -0
  135. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/io/backend.py +0 -0
  136. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/io/hdf5.py +0 -0
  137. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/io/layout.py +0 -0
  138. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/magnitude.py +0 -0
  139. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/picks/__init__.py +0 -0
  140. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/picks/base.py +0 -0
  141. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/picks/delimited.py +0 -0
  142. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/picks/events.py +0 -0
  143. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/picks/resolution.py +0 -0
  144. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/picks/snuffler.py +0 -0
  145. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/plotting/__init__.py +0 -0
  146. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/plotting/grid.py +0 -0
  147. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/plotting/pair.py +0 -0
  148. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/plotting/style.py +0 -0
  149. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/preprocess.py +0 -0
  150. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/smoothing/konno_ohmachi.py +0 -0
  151. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/smoothing/log_bins.py +0 -0
  152. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/sources/__init__.py +0 -0
  153. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/sources/attenuation.py +0 -0
  154. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/sources/composite.py +0 -0
  155. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/sources/motion.py +0 -0
  156. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/sources/source.py +0 -0
  157. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/spreading.py +0 -0
  158. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/staged.py +0 -0
  159. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/tables.py +0 -0
  160. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/transforms/__init__.py +0 -0
  161. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/transforms/base.py +0 -0
  162. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/transforms/cwt.py +0 -0
  163. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/transforms/fft.py +0 -0
  164. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/transforms/multitaper.py +0 -0
  165. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/transforms/prieto.py +0 -0
  166. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/transforms/quadratic.py +0 -0
  167. {specmod-0.3.0 → specmod-0.5.0}/src/specmod/utils.py +0 -0
  168. {specmod-0.3.0 → specmod-0.5.0}/stubs/README.md +0 -0
  169. {specmod-0.3.0 → specmod-0.5.0}/stubs/lmfit/__init__.pyi +0 -0
  170. {specmod-0.3.0 → specmod-0.5.0}/stubs/lmfit/model.pyi +0 -0
  171. {specmod-0.3.0 → specmod-0.5.0}/stubs/lmfit/parameter.pyi +0 -0
  172. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/__init__.pyi +0 -0
  173. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/clients/__init__.pyi +0 -0
  174. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/clients/fdsn/__init__.pyi +0 -0
  175. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/core/__init__.pyi +0 -0
  176. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/core/event.pyi +0 -0
  177. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/core/inventory.pyi +0 -0
  178. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/core/stream.pyi +0 -0
  179. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/core/trace.pyi +0 -0
  180. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/core/utcdatetime.pyi +0 -0
  181. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/core/util/__init__.pyi +0 -0
  182. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/core/util/base.pyi +0 -0
  183. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/geodetics/__init__.pyi +0 -0
  184. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/signal/__init__.pyi +0 -0
  185. {specmod-0.3.0 → specmod-0.5.0}/stubs/obspy/signal/konnoohmachismoothing.pyi +0 -0
  186. {specmod-0.3.0 → specmod-0.5.0}/studies/magna_2020_paper.toml +0 -0
  187. {specmod-0.3.0 → specmod-0.5.0}/tests/__init__.py +0 -0
  188. {specmod-0.3.0 → specmod-0.5.0}/tests/conftest.py +0 -0
  189. {specmod-0.3.0 → specmod-0.5.0}/tests/test_ambient_state.py +0 -0
  190. {specmod-0.3.0 → specmod-0.5.0}/tests/test_api_surface.py +0 -0
  191. {specmod-0.3.0 → specmod-0.5.0}/tests/test_collection.py +0 -0
  192. {specmod-0.3.0 → specmod-0.5.0}/tests/test_cwt.py +0 -0
  193. {specmod-0.3.0 → specmod-0.5.0}/tests/test_datasets.py +0 -0
  194. {specmod-0.3.0 → specmod-0.5.0}/tests/test_docs_are_current.py +0 -0
  195. {specmod-0.3.0 → specmod-0.5.0}/tests/test_end_to_end.py +0 -0
  196. {specmod-0.3.0 → specmod-0.5.0}/tests/test_fitting_defaults.py +0 -0
  197. {specmod-0.3.0 → specmod-0.5.0}/tests/test_import.py +0 -0
  198. {specmod-0.3.0 → specmod-0.5.0}/tests/test_io_and_plotting.py +0 -0
  199. {specmod-0.3.0 → specmod-0.5.0}/tests/test_legacy_fixes.py +0 -0
  200. {specmod-0.3.0 → specmod-0.5.0}/tests/test_magnitude.py +0 -0
  201. {specmod-0.3.0 → specmod-0.5.0}/tests/test_make_golden.py +0 -0
  202. {specmod-0.3.0 → specmod-0.5.0}/tests/test_pick_plugins.py +0 -0
  203. {specmod-0.3.0 → specmod-0.5.0}/tests/test_pick_readers.py +0 -0
  204. {specmod-0.3.0 → specmod-0.5.0}/tests/test_picks.py +0 -0
  205. {specmod-0.3.0 → specmod-0.5.0}/tests/test_pipeline_smoke.py +0 -0
  206. {specmod-0.3.0 → specmod-0.5.0}/tests/test_preprocess.py +0 -0
  207. {specmod-0.3.0 → specmod-0.5.0}/tests/test_prieto.py +0 -0
  208. {specmod-0.3.0 → specmod-0.5.0}/tests/test_quadratic.py +0 -0
  209. {specmod-0.3.0 → specmod-0.5.0}/tests/test_sources.py +0 -0
  210. {specmod-0.3.0 → specmod-0.5.0}/tests/test_spectral_wiring.py +0 -0
  211. {specmod-0.3.0 → specmod-0.5.0}/tests/test_staged.py +0 -0
  212. {specmod-0.3.0 → specmod-0.5.0}/tests/test_stubs.py +0 -0
  213. {specmod-0.3.0 → specmod-0.5.0}/tests/test_transforms.py +0 -0
  214. {specmod-0.3.0 → specmod-0.5.0}/tests/test_tutorial.py +0 -0
  215. {specmod-0.3.0 → specmod-0.5.0}/tests/test_typing_backlog.py +0 -0
  216. {specmod-0.3.0 → specmod-0.5.0}/tests/test_utils.py +0 -0
  217. {specmod-0.3.0 → specmod-0.5.0}/tests/test_versioning.py +0 -0
  218. {specmod-0.3.0 → specmod-0.5.0}/tools/check_built_version.py +0 -0
  219. {specmod-0.3.0 → specmod-0.5.0}/tools/check_floors.py +0 -0
  220. {specmod-0.3.0 → specmod-0.5.0}/tools/make_logo.py +0 -0
  221. {specmod-0.3.0 → specmod-0.5.0}/tools/vendor_fonts.py +0 -0
  222. {specmod-0.3.0 → specmod-0.5.0}/tools/vendor_katex.py +0 -0
  223. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/picks/2019-08-26T07:30:47.000000Z.picks +0 -0
  224. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/picks/2019-08-26T07:30:47.000000Z.xml +0 -0
  225. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/stations/inventory.xml +0 -0
  226. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHE_2019-08-26T07:30:47.000000Z +0 -0
  227. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHN_2019-08-26T07:30:47.000000Z +0 -0
  228. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  229. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHE_2019-08-26T07:30:47.000000Z +0 -0
  230. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHN_2019-08-26T07:30:47.000000Z +0 -0
  231. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  232. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHE_2019-08-26T07:30:47.000000Z +0 -0
  233. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHN_2019-08-26T07:30:47.000000Z +0 -0
  234. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  235. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHE_2019-08-26T07:30:47.000000Z +0 -0
  236. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHN_2019-08-26T07:30:47.000000Z +0 -0
  237. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  238. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHE_2019-08-26T07:30:47.000000Z +0 -0
  239. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHN_2019-08-26T07:30:47.000000Z +0 -0
  240. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  241. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHE_2019-08-26T07:30:47.000000Z +0 -0
  242. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHN_2019-08-26T07:30:47.000000Z +0 -0
  243. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  244. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH1_2019-08-26T07:30:47.000000Z +0 -0
  245. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH2_2019-08-26T07:30:47.000000Z +0 -0
  246. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH3_2019-08-26T07:30:47.000000Z +0 -0
  247. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  248. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  249. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  250. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ02.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  251. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  252. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  253. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  254. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  255. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  256. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  257. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  258. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  259. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  260. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  261. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  262. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  263. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  264. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  265. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  266. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  267. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  268. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  269. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  270. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  271. {specmod-0.3.0 → specmod-0.5.0}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  272. {specmod-0.3.0 → specmod-0.5.0}/tutorial/specmod-tutorial.ipynb +0 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.5.0"
3
+ }
@@ -9,6 +9,67 @@ release could have this problem — every later one has a real predecessor tag
9
9
  so leave subsequent headings as generated. release-please only prepends to this
10
10
  file, so this edit survives. -->
11
11
 
12
+ ## [0.5.0](https://github.com/sgjholt/SpecMod/compare/v0.4.0...v0.5.0) (2026-09-19)
13
+
14
+ <!-- The `acquire` entries below are edited by hand, and are the second entry
15
+ in this file that is. The work shipped in 2af57e8, the squash merge of #45,
16
+ whose subject is not a Conventional Commit — release-please could not parse it
17
+ ("unexpected token ' ' at 1:5") and generated nothing for it. What it did
18
+ generate was the later commit that restored the record, which is documentation
19
+ describing the change rather than the change. These name the change and point
20
+ at the commit that carries it. release-please only prepends to this file, so
21
+ the edit survives. -->
22
+
23
+ ### Features
24
+
25
+ * **acquire:** rank co-sited instruments with `channel_priorities` and
26
+ `location_priorities`, so a station carrying a broadband and an
27
+ accelerometer contributes one record rather than two
28
+ ([2af57e8](https://github.com/sgjholt/SpecMod/commit/2af57e8e958d474a25e34b9065f9e54d1a1a42fa))
29
+
30
+
31
+ ### Bug Fixes
32
+
33
+ * **acquire:** ask for waveforms by name, so `max_radius_km` applies to the
34
+ download and not only to the station query — FDSN dataselect takes no
35
+ geographic parameters, so a wildcard request was unbounded
36
+ ([2af57e8](https://github.com/sgjholt/SpecMod/commit/2af57e8e958d474a25e34b9065f9e54d1a1a42fa))
37
+ * **acquire:** cut the radius against true WGS84 distance rather than a fixed
38
+ 111.195 km per degree, which moved the boundary by up to half a percent with
39
+ latitude; `min_radius_km` now applies on its own, and a non-positive radius
40
+ or an inverted annulus is refused
41
+ ([2af57e8](https://github.com/sgjholt/SpecMod/commit/2af57e8e958d474a25e34b9065f9e54d1a1a42fa))
42
+
43
+
44
+ ### Documentation
45
+
46
+ * **acquire:** upgrading notes for the station selection, and for the
47
+ `[smoothing] method` behaviour change in 0.4.0 ([b460d19](https://github.com/sgjholt/SpecMod/commit/b460d1922c21822a81b6aeb06aa6d5f7193d92e1))
48
+ * **roadmap:** file v0.4.0 as shipped, and the acquire work as merged ([e113abb](https://github.com/sgjholt/SpecMod/commit/e113abb97d80737a2c4a791a6543d945bdb7ba9c))
49
+
50
+ ## [0.4.0](https://github.com/sgjholt/SpecMod/compare/v0.3.0...v0.4.0) (2026-09-16)
51
+
52
+
53
+ ### Features
54
+
55
+ * **smoothing:** wire [smoothing] method up, and add three more methods ([fff3ab1](https://github.com/sgjholt/SpecMod/commit/fff3ab1ef01a7f4d942fd776821d0418a0642a55))
56
+
57
+
58
+ ### Bug Fixes
59
+
60
+ * **config:** refuse a [smoothing] method the pipeline does not apply ([1f18c68](https://github.com/sgjholt/SpecMod/commit/1f18c68a71794c2b1612a7cf0feedcfef39b625b))
61
+ * **test:** compare the roadmap against the published minor, not the proposed one ([1e34b4e](https://github.com/sgjholt/SpecMod/commit/1e34b4e5ab2bdef5d65f6fc0d620a42b9c3891eb))
62
+ * **tools:** call the preprocess API that 0.3.0 left behind ([8501c8e](https://github.com/sgjholt/SpecMod/commit/8501c8ed618e5d652b9eeffc36893115a58fd7d5))
63
+
64
+
65
+ ### Documentation
66
+
67
+ * keep the reasoning out of the docstrings, in comments where it belongs ([2684ec9](https://github.com/sgjholt/SpecMod/commit/2684ec923c8dcf59e882b2d11e9dc11ccbcf3766))
68
+ * say what tagging the frozen commit does and does not trigger ([2273219](https://github.com/sgjholt/SpecMod/commit/2273219e2a78ac1c1562118c2a1b3bce4df597dd))
69
+ * state what the smoothers are, not how they were arrived at ([4c97491](https://github.com/sgjholt/SpecMod/commit/4c97491d50aba5a1468304072ab3c6ed2904f2e0))
70
+ * the 0.3.0 work shipped a week ago, so stop calling it unreleased ([e2aaced](https://github.com/sgjholt/SpecMod/commit/e2aaced546a247b2c5967f01586c19928bcfe297))
71
+ * v0.1.1 is master's tip, which is what freezing it was for ([db50972](https://github.com/sgjholt/SpecMod/commit/db509729f3b7877a20b5691dddec8a6e139fb466))
72
+
12
73
  ## [0.3.0](https://github.com/sgjholt/SpecMod/compare/v0.2.3...v0.3.0) (2026-09-06)
13
74
 
14
75
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: specmod
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: A Python toolbox for processing and modelling seismic spectra
5
5
  Project-URL: Homepage, https://github.com/sgjholt/SpecMod
6
6
  Project-URL: Repository, https://github.com/sgjholt/SpecMod
@@ -35,6 +35,12 @@ location = "*"
35
35
  # fetched too: the workflow rotates horizontals to R/T, and rotation is not a
36
36
  # reason to discard Z from the archive.
37
37
  channel = "HH*,BH*,HN*,EN*"
38
+ # Deliberately unranked. `channel_priorities` would keep one instrument per
39
+ # station — the right default for a regional dataset, and what silences the
40
+ # co-sited warning this fetch prints — but here the near-source broadbands are
41
+ # the records most likely to clip, and the accelerometer beside them is the
42
+ # reason the paper covers that distance range at all. Both are kept and the
43
+ # choice is made at processing time.
38
44
  max_radius_km = 400.0
39
45
 
40
46
  [window]
@@ -1087,7 +1087,7 @@ and there are presumably more in your working directories.
1087
1087
  Two ways out, and the first is much better:
1088
1088
 
1089
1089
  1. **Convert in the old environment.** Phase 0 is already building a Docker image
1090
- where the 0.1.0 code runs (§6.7). Add a small
1090
+ where the 0.1.1 code runs (§6.7). Add a small
1091
1091
  `scripts/convert_legacy_spec.py` to it that loads `.spec` files with the old
1092
1092
  classes present and writes the new HDF5 format. This is a one-shot migration
1093
1093
  with no lasting cost to the codebase.
@@ -2434,6 +2434,15 @@ Two design constraints worth fixing now:
2434
2434
  reimplementation of `MassDownloader`, which is built for large restricted-data
2435
2435
  campaigns and is more machinery than this needs.
2436
2436
 
2437
+ What that choice costs, recorded as it is paid: `MassDownloader` supplies
2438
+ `CircularDomain`, `sanitize=True` and `channel_priorities` for free, and each
2439
+ has had to be built by hand here after its absence showed up in a live fetch.
2440
+ The radius reaching only the station query, an archive holding waveforms with
2441
+ no metadata beside them, and 507 channels for 88 stations were all one
2442
+ property of `Restrictions` each. The wrapper stays thin, but "ObsPy already
2443
+ does it" is an argument for reading what ObsPy does before writing the thin
2444
+ version.
2445
+
2437
2446
  TOML is suggested for the config, read by stdlib `tomllib` on 3.11+ and
2438
2447
  consistent with `pyproject.toml`. YAML is equally fine if it reads better for
2439
2448
  nested station rules; it costs one small dependency.
@@ -2742,13 +2751,30 @@ Two further problems with reproducing the published run from this repository:
2742
2751
  manuscript filename (`...SRL3`) suggests a third revision, which would also
2743
2752
  explain a 2021 code state behind a 2020 access date.
2744
2753
 
2745
- Practical consequence: **the candidate is `ba3f7ec` or later, not the
2754
+ The evidence narrows it: **the candidate is `ba3f7ec` or later, not the
2746
2755
  pre-November-2020 commits**, because the earlier code cannot perform the
2747
2756
  workflow the paper describes. Only `09f57b9` (removed cython) changes
2748
2757
  `specmod/` after that, so the realistic candidates are `ba3f7ec` and
2749
- `453c77c`. Pick one, record the reasoning, and move on — this is the
2750
- strongest possible argument for the `v0.1.0` tag (§6.7) and for `hatch-vcs`
2751
- (§6.4): it must never be this hard again.
2758
+ `453c77c`.
2759
+
2760
+ **Answered: `453c77c`** — the tip of `master`, 2021-08-12. On the author's
2761
+ word, and it is why `master` was frozen at that commit rather than at any
2762
+ other: the branch *is* the v0.1.1 record (§6.7). Which of the two the
2763
+ evidence above prefers was never the question it looked like.
2764
+
2765
+ What that settles and what it does not: the code is identified, so §5.2.6
2766
+ step 2 can be run against a known commit. The dating oddity is unchanged —
2767
+ the manuscript's access date still precedes the commit it cites, which the
2768
+ third revision (`...SRL3`) explains without needing the code to have moved.
2769
+ It is recorded rather than resolved, because nothing in the repository can
2770
+ resolve it.
2771
+
2772
+ This is still the strongest possible argument for tagging that commit (§6.7)
2773
+ and for `hatch-vcs` (§6.4): a version that takes a page of archaeology to
2774
+ identify must never happen again. **No `v0.1.1` tag exists yet.** Creating
2775
+ one is safe — `453c77c` is an ancestor of `main`, and every later release
2776
+ tag outranks it for `hatch-vcs`, so nothing derives a version from it — but
2777
+ it is repository state, not something a commit here can carry.
2752
2778
  2. **The full published pipeline is not in this repository.** The two-stage
2753
2779
  inversion (fit Ω/`f_c`/`t*` free, then fix event `f_c` to the
2754
2780
  inverse-hypocentral-distance-weighted mean of station `f_c` and refit) and the
@@ -3414,6 +3440,31 @@ been audited once is worth more than one that reads confidently throughout.
3414
3440
  | "`commitlint`-enforced" again, in §6.4 | The §7 instance was corrected and this one was left standing, in the same document. §6.4 corrected. |
3415
3441
  | `publish.yml` "GitHub Release published → PyPI" | It would never have run. release-please creates the release with the default `GITHUB_TOKEN`, and events triggered by that token do not start a workflow. The publish job moved into `release.yml`, gated on `release_created`. §6.5 corrected. |
3416
3442
 
3443
+ **A fourth of the same shape, found later** — the three above were corrected in
3444
+ the prose; this one was a live setting:
3445
+
3446
+ > `[smoothing] method` — "Name -> smoother, for resolving `SmoothingConfig.method`"
3447
+
3448
+ `SMOOTHERS` existed, `method` validated against its `Literal`, and **no code
3449
+ anywhere read it**. The comparison binned with `log_bin` unconditionally.
3450
+ Measured on the 28 PNR windows, `log_bins`, `konno_ohmachi` and `none` produced
3451
+ bit-identical output — `none` included, which reads as "leave my spectra
3452
+ unsmoothed" while every spectrum went on being binned exactly as before.
3453
+
3454
+ **Fixed rather than documented.** `SpectrumPair.compare` now takes a `smoother`,
3455
+ `[smoothing] method` resolves to one, and the registry gained `log_window`
3456
+ (constant-relative-bandwidth smoothing with a selectable window shape, and a
3457
+ median option) and `savitzky_golay` beside the two that were there.
3458
+ `tests/test_config.py::TestEverySmoothingMethodIsWiredUp` and
3459
+ `tests/test_pipeline.py::TestTheConfiguredSmootherReachesTheComparison` are the
3460
+ mechanism the comment claimed: each accepted value resolves, carries its
3461
+ section's parameters, and survives the whole path on real windows.
3462
+
3463
+ `log_bins` stays `core.collection.log_bin` rather than `smoothing.LogBinner` —
3464
+ the two differ in clamping and in what `n_bins` counts, and the difference is
3465
+ every committed golden number. The default path is unchanged, which the golden
3466
+ suite asserts and which is why this could land without moving a number.
3467
+
3417
3468
  **A claim whose mechanism is absent but whose property holds — for a different
3418
3469
  reason, which matters:**
3419
3470
 
@@ -3460,7 +3511,8 @@ of §5.2, and the two-stage fit API of §5.2.5.
3460
3511
  **`master` is frozen; `main` is the trunk.** `main` was branched from `master` at
3461
3512
  `453c77c` and is where all refactor work lands. `master` is never committed to
3462
3513
  again — it becomes the permanent, named record of the pre-refactor code, doing
3463
- the job a `v0.1.0` tag would have done.
3514
+ the job a `v0.1.1` tag would have done. Its tip, `453c77c`, **is** the v0.1.1
3515
+ the Magna paper cites (§5.2.5, §8).
3464
3516
 
3465
3517
  **Every pull request must target `sgjholt/SpecMod`, never `uofuseismo/SpecMod`.**
3466
3518
  This is not a matter of care — it is a GitHub default working against you.
@@ -3498,7 +3550,7 @@ Two consequences worth acting on:
3498
3550
  - [ ] Settings → Actions → confirm workflows are enabled
3499
3551
  - [ ] Settings → Branches → protect `master` (no pushes, no deletion) so the
3500
3552
  frozen record stays frozen
3501
- - [ ] `git tag -a v0.1.0 453c77c -m "pre-refactor snapshot" && git push origin v0.1.0`
3553
+ - [ ] `git tag -a v0.1.1 453c77c -m "the version the Magna paper cites" && git push origin v0.1.1`
3502
3554
 
3503
3555
  **No Claude session URLs in commit messages, PR bodies, or any other published
3504
3556
  artifact.** The repository is public and those links are private session state. A
@@ -3516,12 +3568,20 @@ needed and neither can be made from a git client:
3516
3568
  convention rather than a guarantee — one absent-minded `git push origin
3517
3569
  master` and the record is gone.
3518
3570
 
3519
- Optionally also tag `453c77c` as `v0.1.0` for good measure; belt and braces, and
3520
- it gives release-please an explicit floor to generate the first changelog from.
3521
- The two are complementary — the tag is immutable, the branch is discoverable.
3571
+ Also tag `453c77c` as `v0.1.1` — no longer optional now that §8 records it as
3572
+ the commit the paper cites. A branch is discoverable and a tag is immutable,
3573
+ and a citation should resolve to the immutable one.
3574
+
3575
+ Tagging it publishes nothing. No workflow triggers on tags; the PyPI upload is
3576
+ gated on release-please's `release_created`, which only a merged release PR on
3577
+ `main` can set; and `git describe` takes the nearest tag, which is a release
3578
+ far ahead of this one. **Do not create a GitHub Release from the tag**, which
3579
+ is the one action that would publish: Zenodo listens to the release webhook and
3580
+ would mint a DOI for the pre-refactor code. The commit has no `pyproject.toml`
3581
+ and is not packageable.
3522
3582
 
3523
3583
  > Note on tooling limits: tag pushes are blocked in the automation environment
3524
- > this plan was written in (HTTP 403 on `push origin v0.1.0`, while branch
3584
+ > this plan was written in (HTTP 403 on `push origin v0.1.1`, while branch
3525
3585
  > pushes to the same remote succeed), which is why `main` exists as a branch
3526
3586
  > rather than the state being pinned by a tag. **This does not affect the release
3527
3587
  > automation in §6.4** — release-please creates tags from inside GitHub Actions
@@ -3531,10 +3591,10 @@ The two are complementary — the tag is immutable, the branch is discoverable.
3531
3591
 
3532
3592
  Worth being precise about what any of this does and does not preserve: it
3533
3593
  preserves the **code**, but the code is not **runnable** — `mtspec` no longer
3534
- builds on any current toolchain (§2.1). Reproducing a 0.1.0 result needs three
3594
+ builds on any current toolchain (§2.1). Reproducing a 0.1.1 result needs three
3535
3595
  things, which is what Phase 0 delivers:
3536
3596
 
3537
- 1. `master` (and optionally `v0.1.0`) — the source.
3597
+ 1. `master` (and the `v0.1.1` tag on its tip) — the source.
3538
3598
  2. A `Dockerfile` pinning `gfortran`, `python 3.9`, `numpy<2` — the environment
3539
3599
  that can still build `mtspec`. Also the only place existing `.spec` pickles
3540
3600
  can be read (§4.6).
@@ -3565,7 +3625,7 @@ Each phase ends green on CI and is independently mergeable.
3565
3625
 
3566
3626
  | Phase | Work | Depends on | Rough size |
3567
3627
  |---|---|---|---|
3568
- | **0. Safety net** | Freeze `master`, default branch → `main`, optional `v0.1.0` tag (§6.7); reproducible legacy env (`Dockerfile`: gfortran + ObsPy 1.2.0 / SciPy 1.4.1 / NumPy 1.18 / pandas 1.0.0 (§5.2.6)); write `datasets/magna_2020.toml` and a first cut of `specmod.acquire`, publish the artifact as a `data-v1` release asset (§5.2); capture golden outputs for PNR **and** Magna; reproduce Table S2 / Figure 2 with 0.1.1 (§5.2.6 step 2); convert any `.spec` files (§4.6) | — | 1.5–2 days |
3628
+ | **0. Safety net** | Freeze `master`, default branch → `main`, optional `v0.1.1` tag (§6.7); reproducible legacy env (`Dockerfile`: gfortran + ObsPy 1.2.0 / SciPy 1.4.1 / NumPy 1.18 / pandas 1.0.0 (§5.2.6)); write `datasets/magna_2020.toml` and a first cut of `specmod.acquire`, publish the artifact as a `data-v1` release asset (§5.2); capture golden outputs for PNR **and** Magna; reproduce Table S2 / Figure 2 with 0.1.1 (§5.2.6 step 2); convert any `.spec` files (§4.6) | — | 1.5–2 days |
3569
3629
  | **1. Make it installable** | `pyproject.toml` + hatch-vcs, `src/` layout, `__init__.py`; ruff config, one-shot `ruff format` + `.git-blame-ignore-revs`, module renames to snake_case; mypy skeleton; pre-commit; `test`/`build` CI; `.gitignore`, `CITATION.cff`; fix the three hard breakages (§1) and the four `F821` bugs ruff finds (§2.5); delete `Tests/Tutorial/`, strip notebook outputs, subset the inventory (§5.1) | 0 | 3–4 days |
3570
3630
  | **2. De-globalise** | `config/` package per §4.8 — semantic groups, layer resolution, `config show`/`freeze`, provenance stamping; remove all module-level config reads (tracked by `PLW0603`); `Motion`/`AmplitudeKind` enums; `Spectrum` as a frozen dataclass with `duration`; mutable class attrs (`RUF012`); `isinstance` checks; `logging`. **Tag `v0.2.0`** | 1 | 3–4 days |
3571
3631
  | **2b. Release plumbing** ✅ | ~~Sphinx skeleton + `pydata-sphinx-theme` + autodoc/napoleon/intersphinx~~ ✅; ~~`docs.yml` → a published site~~ ✅ — Read the Docs rather than GH Pages, for versions (§6.3); ~~release-please + PyPI Trusted Publishing~~ ✅ — one `release.yml`, not two workflows (§6.5); ~~Zenodo webhook~~ ✅ documented. Five repository settings have to be turned on by hand: `docs/releasing.md` lists them. The `ci/` mirror that staged workflow files for hand-copying is gone — it existed because an agent token could not push `.github/workflows/`, and that permission is now granted. Parallel with 2 | 1 | 1–2 days |
@@ -3658,20 +3718,48 @@ changes anything shipped.
3658
3718
  ### Still open
3659
3719
 
3660
3720
  1. **Default estimator.** Multitaper (matching current behaviour) or FFT +
3661
- Konno–Ohmachi (faster, more conventional in engineering seismology)?
3721
+ Konno–Ohmachi (more conventional in engineering seismology)? **No longer
3722
+ blocked** — §6.6's dead `[smoothing] method` is wired up, so the second
3723
+ option is selectable — and now measured, on the 28 PNR windows with each
3724
+ station fitted freely:
3725
+
3726
+ | Against the shipped multitaper + `log_bins` | Median ΔMw | Per-station range | `fc` ratio |
3727
+ |---|---|---|---|
3728
+ | `fft` + `log_bins` | −0.039 | −0.85 to +1.90 | 0.003 to 5.0 |
3729
+ | `fft` + `konno_ohmachi` | +0.027 | −0.52 to +0.51 | 0.038 to 3.2 |
3730
+
3731
+ **The smoothing is what makes the switch defensible, not the estimator.**
3732
+ FFT with the shipped binner moves a station by up to 1.9 magnitude units,
3733
+ because `log_bins` reduces the axis without reducing the variance — 151 log
3734
+ bins over a few hundred Fourier samples is roughly one sample per bin.
3735
+ Pairing it with a real smoother halves the worst excursion and pulls the
3736
+ `fc` range in by a third. The median station barely moves either way.
3737
+
3738
+ What this event cannot settle: the *event* corner is unconstrained under all
3739
+ three (stage-one spread 895% to 1042% of the event value), so the ensemble
3740
+ number is not evidence. Deciding on the ensemble needs an event where it is
3741
+ constrained.
3742
+
3743
+ Speed, measured rather than assumed and far too small to decide on: the
3744
+ transform is 0.209 s against 0.323 s for the 28 windows, and the smoothing
3745
+ adds 0.14 s (`log_bins`) to 0.83 s (`konno_ohmachi`) on top.
3746
+
3662
3747
  2. **Python floor.** 3.11 is proposed. Any users stuck on 3.9/3.10?
3663
3748
  3. **History rewrite.** Deleting the 9.9 MB catalog and stripping the notebook
3664
3749
  (§5.1) shrinks the *working tree* but leaves both in history, so a fresh clone
3665
3750
  still pulls ~15 MiB. Rewriting history with `git-filter-repo` would recover it
3666
3751
  — but it rewrites every SHA, which moves what `master` and `main` currently
3667
- point at and invalidates any `v0.1.0` tag. Given the end state is a ~1 MB repo
3752
+ point at and invalidates any `v0.1.1` tag. Given the end state is a ~1 MB repo
3668
3753
  either way, **the recommendation is to leave history alone**: a one-time 15 MiB
3669
3754
  clone is a much smaller cost than an unrecoverable pre-refactor record. Only
3670
3755
  worth revisiting if the history genuinely becomes a burden.
3671
- 4. **Which commit is "v0.1.1"?** The paper cites SpecMod v0.1.1; no such tag
3672
- exists and the source carries no version string (§5.2.5). Reproducing the
3673
- published run needs that commit identified — by submission date against the
3674
- history, if nothing better is available. Only you can make that call.
3756
+ 4. ~~**Which commit is "v0.1.1"?**~~ **Resolved: `453c77c`**, the tip of
3757
+ `master`, 2021-08-12 — which is what freezing `master` at that commit was
3758
+ for (§6.7). The archaeology in §5.2.5 narrowed it to two candidates and
3759
+ could not choose between them; the answer did not come from the repository
3760
+ and was never going to. §5.2.6 step 2 now has a known commit to run. No
3761
+ `v0.1.1` tag exists yet, and creating one is repository state rather than
3762
+ something a commit can carry.
3675
3763
  5. ~~**Was noise rotation on for the published run?**~~ **Assumed on.** Not
3676
3764
  recalled, so `studies/magna_2020_paper.toml` starts from the shipped values —
3677
3765
  `ROTATE_NOISE = true`, `ROT_METHOD = 2`, `ROT_PARS = {inc = 0.05, space =
@@ -582,6 +582,90 @@ narrow at low frequency, wide at high. It preserves the frequency axis, which is
582
582
  what you want before fitting on the original grid. Bandwidth `b` is inverse:
583
583
  smaller smooths harder; 40 is conventional.
584
584
 
585
+ **`LogWindow`** is the same idea with the window shape exposed: a fixed width in
586
+ octaves, and `boxcar`, `bartlett` (triangular), `hann`, `hamming`, `blackman` or
587
+ `gaussian` across it. Use it when you want the constant-relative-bandwidth
588
+ behaviour of Konno–Ohmachi and a say in how hard the taper is — or simply
589
+ because it is faster, being a sliding window rather than a full weight matrix.
590
+
591
+ Which shape matters less than it looks. On an exact `f**-2` power law, which
592
+ every one of them has to return unchanged, the median residual runs from
593
+ `1.3e-8` dex (`blackman`) to `3.4e-4` dex (`boxcar`) — an ordering that tracks
594
+ the taper's smoothness and a spread far below anything a fit would notice.
595
+ **Pick the width first and the shape second.**
596
+
597
+ `statistic="median"` is the one option that is not an average: the window
598
+ selects the samples and the median decides, so the shape is ignored. It is
599
+ there for spectra carrying spikes — a power-line tone, a dropout, a telemetry
600
+ glitch — which an average spreads across the whole window. With a single 60×
601
+ spike dropped into that power law, the worst residual across the axis is
602
+ `1.7e-2` dex for the median against `3.8e-2` for the geometric mean and
603
+ `3.6e-1` for the arithmetic one. It will discard a genuine narrow peak just as
604
+ happily, which is the trade.
605
+
606
+ One detail in it is worth knowing about, because it is not what the textbook
607
+ description of fractional-octave smoothing gives you. A window symmetric in log
608
+ frequency is **not** a symmetric average over samples: a Fourier grid is uniform
609
+ in Hz, so every window holds more samples above its centre than below in log
610
+ terms, and a plain per-sample mean tilts. Weighting each sample by its share of
611
+ the log axis removes it. Smoothing an exact `f**-2` power law, which has to come
612
+ back unchanged, the median residual is `1.5e-3` dex per-sample against `3.2e-8`
613
+ dex weighted for `hann`. It is on by default; `log_measure=False` gives the
614
+ per-sample behaviour, which is what Konno–Ohmachi does.
615
+
616
+ **`SavitzkyGolay`** fits a sliding polynomial rather than averaging, so it
617
+ flattens a peak far less. It is fitted to `log10(amp)` against `log10(f)` on a
618
+ uniform log-frequency grid — a polynomial in raw amplitude against raw frequency
619
+ spends its degrees of freedom on the falloff and can return a negative
620
+ amplitude. Ringing near the corner and the Nyquist roll-off is what it costs.
621
+
622
+ ### What the choice actually changes
623
+
624
+ Less than it looks, and not where you would expect. **`[fitting] fit_bins` is
625
+ `false` by default, so the fit reads the unsmoothed spectrum.** The smoother's
626
+ whole influence on `Omega` is therefore indirect: it changes the signal-to-noise
627
+ ratio, which changes the band that passes the gate, which changes where the
628
+ plateau is read. The scatter column below is what the choice buys when
629
+ `fit_bins` is on, or when the reduced arrays are what you plot.
630
+
631
+ Measured on the 28 PNR windows, everything relative to the shipped default:
632
+
633
+ <!-- measured: smoothing_table -->
634
+ | Method | Banded | Band low (Hz) | Band (decades) | Δ plateau (dex) | Scatter (dex) |
635
+ |---|---|---|---|---|---|
636
+ | `log_bins` (default) | 28/28 | 0.94 | 1.55 | +0.000 | 0.317 |
637
+ | `konno_ohmachi`, b=40 | 28/28 | 0.93 | 1.68 | +0.067 | 0.093 |
638
+ | `log_window`, hann | 28/28 | 0.93 | 1.66 | +0.067 | 0.111 |
639
+ | `log_window`, bartlett | 28/28 | 0.93 | 1.66 | +0.067 | 0.102 |
640
+ | `log_window`, boxcar | 28/28 | 0.93 | 1.68 | +0.067 | 0.086 |
641
+ | `log_window`, gaussian | 28/28 | 0.93 | 1.65 | +0.067 | 0.147 |
642
+ | `log_window`, median | 28/28 | 0.93 | 1.69 | +0.067 | 0.091 |
643
+ | `savitzky_golay` | 28/28 | 0.93 | 1.67 | +0.067 | 0.063 |
644
+ | `none` | 28/28 | 0.94 | 1.51 | +0.000 | 0.318 |
645
+ <!-- /measured -->
646
+
647
+ Three things in that table are worth reading twice.
648
+
649
+ **The default barely smooths.** `log_bins` leaves the same scatter as `none`,
650
+ because 151 log bins over a window holding a few hundred Fourier samples puts
651
+ roughly one sample in most bins. It reduces the *axis*, not the noise.
652
+
653
+ **Every real smoother widens the band** by about a tenth of a decade. A smoothed
654
+ ratio crosses the threshold later, so more of the high-frequency tail survives
655
+ the gate — which is a gain if the tail is signal and a risk if it is not.
656
+
657
+ **The plateau moves by the same 0.067 dex under every one of them**, which is
658
+ 0.045 in magnitude. That is not seven methods agreeing about amplitudes; it is
659
+ the low band edge moving from 0.94 Hz to 0.93 Hz under all of them, and the
660
+ plateau being read from there. The amplitudes the fit sees never changed.
661
+
662
+ Cost, measured once at best of three for the whole comparison over the 28
663
+ windows: `none` 63 ms,
664
+ `savitzky_golay` 140 ms, `log_bins` 143 ms, `log_window` 313 ms,
665
+ `log_window` with `statistic="median"` 688 ms, `konno_ohmachi` 830 ms. The
666
+ spread is one machine's, and the shape of it — Konno–Ohmachi building a full
667
+ weight matrix where `LogWindow` slides a window — is what generalises.
668
+
585
669
  ---
586
670
 
587
671
  ## Reproducing the published Magna configuration
@@ -114,7 +114,8 @@ with `specmod[multitaper]` installed passes tests that CI, which installs only
114
114
 
115
115
  - **`main`** is the trunk. Everything lands here, and it is the default branch.
116
116
  - **`master`** is frozen: the permanent record of the pre-refactor code, doing
117
- the job a `v0.1.0` tag would have done. Never commit to it.
117
+ the job a `v0.1.1` tag would have done: its tip, `453c77c`, is the commit the
118
+ Magna paper cites. Never commit to it.
118
119
  - Feature branches are short-lived and merge into `main` via pull request.
119
120
 
120
121
  Every pull request must target **`sgjholt/SpecMod`**. See §6.7 of the plan for
@@ -46,6 +46,10 @@ python -m json.tool build/magna_2020/manifest.json | head -40
46
46
  - `channels` — the list *after* wildcard expansion. `HH*` does not tell you
47
47
  what you got; this does. A much shorter list than expected usually means a
48
48
  network was not open at that time, not that the request was malformed.
49
+ - `channels_available`, `channels_requested` — what the station query offered,
50
+ and what was asked for after the priority lists narrowed it. A large gap
51
+ between `channels_requested` and `channels` means the archive did not serve
52
+ what its own metadata advertises.
49
53
  - `data_centre`, `obspy_version`, `specmod_version`, `fetched_at` — the
50
54
  provenance that makes the response reproducible-ish. It cannot be fully
51
55
  reproducible: FDSN is not content-addressed, archives get backfilled and
@@ -54,6 +58,49 @@ python -m json.tool build/magna_2020/manifest.json | head -40
54
58
  If any of that is wrong, fix the config and re-fetch. The artefact is about to
55
59
  become immutable.
56
60
 
61
+ ### Picking one instrument per station
62
+
63
+ A `channel` pattern that names several instruments — `HH*,BH*,HN*,EN*` — returns
64
+ every one of them at every station that has them. Magna's 88 stations return 507
65
+ channels that way, and a station with both a broadband and an accelerometer
66
+ contributes the same ground motion twice: two entries in a `SpectrumSet`,
67
+ weighted as two stations by anything that averages over them.
68
+
69
+ `channel_priorities` ranks them instead. The first pattern that matches anything
70
+ at a station wins, so the list is read as "a broadband if there is one,
71
+ otherwise an accelerometer":
72
+
73
+ ```toml
74
+ [stations]
75
+ channel = "HH*,BH*,HN*,EN*"
76
+ channel_priorities = ["HH[ZNE]", "BH[ZNE]", "HN[ZNE]", "EN[ZNE]"]
77
+ location_priorities = ["", "00", "10"]
78
+ ```
79
+
80
+ `channel` still says what the data centre may offer; the priorities say which of
81
+ what it offers to keep. A station matching no pattern at all is dropped — the
82
+ list is a restriction as well as a ranking — and the written `inventory.xml` is
83
+ pruned to match, so the archive keeps describing exactly what it holds.
84
+
85
+ Patterns are matched case-sensitively against SEED codes, which are upper case.
86
+ `["*"]` keeps everything, which is how a config says it wants both instruments
87
+ and means it; with no list at all, `fetch` warns that it is fetching co-sited
88
+ instruments and names the stations.
89
+
90
+ ### What the radius means
91
+
92
+ `max_radius_km` is cut against the true WGS84 distance from the epicentre, not
93
+ against the degrees FDSN takes. A degree of arc is 110.574 km at the equator and
94
+ 111.691 km at the poles, so converting with a single constant moves the boundary
95
+ by up to half a percent — ±0.3 km on a 50 km radius, ±2 km on 400 km. The
96
+ station query is sent deliberately wide and the exact cut is made locally, which
97
+ costs a few extra stations in the query and makes the radius mean kilometres
98
+ wherever the event is.
99
+
100
+ The radii are epicentral. For a local array the depth is usually the larger
101
+ term: every station of a 500 m array over a 2 km-deep event is at 2 km
102
+ hypocentral distance.
103
+
57
104
  ## 2. Archive and hash
58
105
 
59
106
  ```bash
@@ -35,7 +35,10 @@ The version before this one, `0.1.1`, is the pre-refactor code that produced
35
35
  the published Magna results. It is preserved unchanged on the
36
36
  [`master`](https://github.com/sgjholt/SpecMod/tree/master) branch, which is
37
37
  protected and frozen — it was never tagged or published to PyPI, so that
38
- branch is the only reference to it. Everything below is the delta between it
38
+ branch is the only reference to it. Its tip,
39
+ [`453c77c`](https://github.com/sgjholt/SpecMod/commit/453c77c), is the commit
40
+ the paper cites as v0.1.1; cite that rather than the branch name, which is a
41
+ moving target in principle even though this one will not move. Everything below is the delta between it
39
42
  and v0.2.0, which is why the first changelog is enormous and correctly so.
40
43
 
41
44
  ### An installable package
@@ -106,11 +109,11 @@ build**, so every figure and number on the page came from running the code
106
109
  being documented. A notebook that stops working fails the build rather than
107
110
  going quietly stale, which is why it was a 1.0 requirement.
108
111
 
109
- ## In progress — not yet released
112
+ ## Shipped in v0.3.0
110
113
 
111
- ### Finishing the decomposition
114
+ ### The decomposition, finished
112
115
 
113
- **Done, and unreleased.** This was the last item 1.0 was waiting on.
116
+ This was the last item 1.0 was waiting on.
114
117
 
115
118
  `io.py` and `plotting.py` are now packages, alongside the spectral core, the
116
119
  fitting layer and the pick readers; the type-checking backlog is empty. The
@@ -136,13 +139,67 @@ signposted from [Guides](guides.md) rather than split onto a page of their own.
136
139
  [Upgrading](upgrading.md) covers moving code off the pre-refactor
137
140
  `master`.
138
141
 
142
+ ## Shipped in v0.4.0
143
+
144
+ ### Smoothing became a choice, and the choice is applied
145
+
146
+ `[smoothing] method` selected nothing. The registry mapped the names, the config
147
+ validated against them, and no code read the result: every spectrum was
148
+ log-binned whatever the setting said. Measured on the 28 PNR windows,
149
+ `log_bins`, `konno_ohmachi` and `none` produced bit-identical output — `none`
150
+ included, which reads as "leave my spectra unsmoothed".
151
+
152
+ It is wired now, with three methods beside the two:
153
+
154
+ - **`log_window`** — constant relative bandwidth over a window you name:
155
+ boxcar, Bartlett, Hann, Hamming, Blackman or Gaussian, a fraction of an
156
+ octave wide everywhere. Konno–Ohmachi is this family with its own window.
157
+ `statistic="median"` discards a spike rather than averaging it in, and
158
+ discards a genuine narrow peak with it.
159
+ - **`savitzky_golay`** — a local polynomial fit in log–log, which keeps peak
160
+ amplitude and width where a running mean flattens both.
161
+ - **`none`** — no smoothing, which now means it.
162
+
163
+ Log-binning replaces the frequency axis; the others preserve it. That is the
164
+ distinction the setting had no way to express, and the reason wiring it up was
165
+ a design change rather than a patch.
166
+
167
+ One detail that is easy to get wrong and is worth knowing about: a window
168
+ symmetric in log frequency is not a symmetric average over samples, because a
169
+ Fourier grid is uniform in Hz. Weighting samples equally tilts the result by
170
+ 1.5e-3 dex on an `f**-2` power law; weighting each by its share of the log
171
+ axis brings that to 3.2e-8 dex. The latter is the default. Konno–Ohmachi
172
+ applies the former, by definition, and keeps it.
173
+
174
+ ## In progress — not yet released
175
+
176
+ Merged on `main`, and it will name its version when a release goes out.
177
+
178
+ ### The station selection means what the config says
179
+
180
+ Three ways a fetched dataset did not match the config that asked for it, all
181
+ found by a live fetch rather than by the suite:
182
+
183
+ - `max_radius_km` reached the station query and never the waveform request,
184
+ because FDSN dataselect has no geographic parameters. A 50 km fetch returned
185
+ channels from 225 km out, with no metadata beside them. Waveforms are now
186
+ asked for by name, from the inventory the station query returned.
187
+ - The radius was converted at 111.195 km per degree. A degree of arc is
188
+ 110.574 km at the equator and 111.691 km at the poles, so the boundary moved
189
+ with latitude — ±0.3 km at 50 km, ±2 km at 400 km. The query is now sent
190
+ deliberately wide and the cut made against the true WGS84 distance.
191
+ - A `channel` pattern naming several instruments returned all of them at every
192
+ station, so a broadband and the accelerometer beside it entered the pipeline
193
+ as two independent records of one ground motion. `channel_priorities` and
194
+ `location_priorities` rank them, first match wins per station.
195
+
139
196
  ## Planned
140
197
 
141
198
  ### 1.0 — the API stops moving
142
199
 
143
- **Everything this was waiting on is now done** — the documentation, and the
144
- decomposition above with the signature changes it implied. What remains is the
145
- release itself, which says that names and signatures stop moving without a
200
+ **Everything this was waiting on shipped in v0.3.0** — the documentation, and
201
+ the decomposition above with the signature changes it implied. What remains is
202
+ the release itself, which says that names and signatures stop moving without a
146
203
  deprecation cycle.
147
204
 
148
205
  That promise is the whole content of the number, which is why it has to be a
@@ -151,6 +208,21 @@ is made, breaking changes bump the minor. The honest test before making it is
151
208
  whether a release goes by without one — the API is not settled because the
152
209
  backlog is empty, it is settled when it stops moving.
153
210
 
211
+ **By that test, 1.0 is not ready.** v0.3.0 is the release that emptied the
212
+ backlog and it carried two breaking changes itself: the ten renamed
213
+ `preprocess` functions, and the tutorial's page moving. So what 1.0 now waits
214
+ on is a release going out without one — which is a thing that has to be
215
+ observed rather than declared, and cannot be brought forward by finishing
216
+ anything.
217
+
218
+ **v0.4.0 is the first observation, and it is not clean.** No name or signature
219
+ moved: the smoothing work was additive, and the `SpectrumPair.compare`
220
+ parameter it added is optional. But `[smoothing] method` changed what it does,
221
+ so a config that set `konno_ohmachi` or `none` gets different numbers out of
222
+ the same code path. Nothing breaks at import or at the call; results move. That
223
+ is a weaker promise than the one 1.0 makes and a real one to have broken, so
224
+ the count starts again rather than standing at one.
225
+
154
226
  ## After 1.0
155
227
 
156
228
  Designed but deliberately not on the path to 1.0, because each is blocked on
@@ -175,7 +247,16 @@ guess written from documentation cannot substitute for:
175
247
  Each shipped entry names the version that carries it, so a reader can install
176
248
  that version and check the claim. Work that is merged but unreleased sits under
177
249
  *In progress* and gets its version when a release goes out — merged is not
178
- shipped, and this page does not blur the two.
250
+ shipped, and this page does not blur the two. Between releases there is no such
251
+ section at all, which is a state the page should be in rather than a section
252
+ that went missing.
253
+
254
+ The move at release time is the step this page got wrong once. The v0.3.0 work
255
+ sat under *In progress — not yet released* for a week after v0.3.0 was
256
+ released, because `release-please` writes the changelog and the manifest and
257
+ knows nothing about this file. `tests/test_release_config.py` now fails when
258
+ the released minor version is ahead of every version this page names, which is
259
+ the check that was missing rather than a rule that was.
179
260
 
180
261
  Before v0.2.0 this was a list of stages, because there was no released version
181
262
  to point at and "done" could only mean merged. The full changelog for every