specmod 0.2.0__tar.gz → 0.2.1__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 (213) hide show
  1. {specmod-0.2.0 → specmod-0.2.1}/.github/workflows/release.yml +33 -9
  2. specmod-0.2.1/.release-please-manifest.json +3 -0
  3. {specmod-0.2.0 → specmod-0.2.1}/CHANGELOG.md +21 -1
  4. {specmod-0.2.0 → specmod-0.2.1}/CITATION.cff +7 -0
  5. {specmod-0.2.0 → specmod-0.2.1}/PKG-INFO +34 -5
  6. {specmod-0.2.0 → specmod-0.2.1}/README.md +33 -4
  7. {specmod-0.2.0 → specmod-0.2.1}/docs/index.md +4 -4
  8. {specmod-0.2.0 → specmod-0.2.1}/docs/releasing.md +80 -23
  9. specmod-0.2.1/docs/roadmap.md +148 -0
  10. specmod-0.2.0/.release-please-manifest.json +0 -3
  11. specmod-0.2.0/docs/roadmap.md +0 -109
  12. {specmod-0.2.0 → specmod-0.2.1}/.git-blame-ignore-revs +0 -0
  13. {specmod-0.2.0 → specmod-0.2.1}/.github/workflows/build.yml +0 -0
  14. {specmod-0.2.0 → specmod-0.2.1}/.github/workflows/docs.yml +0 -0
  15. {specmod-0.2.0 → specmod-0.2.1}/.github/workflows/test.yml +0 -0
  16. {specmod-0.2.0 → specmod-0.2.1}/.gitignore +0 -0
  17. {specmod-0.2.0 → specmod-0.2.1}/.pre-commit-config.yaml +0 -0
  18. {specmod-0.2.0 → specmod-0.2.1}/.readthedocs.yaml +0 -0
  19. {specmod-0.2.0 → specmod-0.2.1}/AGENTS.md +0 -0
  20. {specmod-0.2.0 → specmod-0.2.1}/CLAUDE.md +0 -0
  21. {specmod-0.2.0 → specmod-0.2.1}/CONTRIBUTING.md +0 -0
  22. {specmod-0.2.0 → specmod-0.2.1}/LICENSE +0 -0
  23. {specmod-0.2.0 → specmod-0.2.1}/datasets/magna_2020.toml +0 -0
  24. {specmod-0.2.0 → specmod-0.2.1}/datasets/pnr_2019.toml +0 -0
  25. {specmod-0.2.0 → specmod-0.2.1}/docs/REFACTOR_PLAN.md +0 -0
  26. {specmod-0.2.0 → specmod-0.2.1}/docs/api.md +0 -0
  27. {specmod-0.2.0 → specmod-0.2.1}/docs/choosing-a-transform.md +0 -0
  28. {specmod-0.2.0 → specmod-0.2.1}/docs/conf.py +0 -0
  29. {specmod-0.2.0 → specmod-0.2.1}/docs/development.md +0 -0
  30. {specmod-0.2.0 → specmod-0.2.1}/docs/documentation.md +0 -0
  31. {specmod-0.2.0 → specmod-0.2.1}/docs/notebooks/_build_notebook.py +0 -0
  32. {specmod-0.2.0 → specmod-0.2.1}/docs/notebooks/choosing-a-transform.ipynb +0 -0
  33. {specmod-0.2.0 → specmod-0.2.1}/docs/notes/api-audit.md +0 -0
  34. {specmod-0.2.0 → specmod-0.2.1}/docs/notes/window-position.md +0 -0
  35. {specmod-0.2.0 → specmod-0.2.1}/docs/pick-formats.md +0 -0
  36. {specmod-0.2.0 → specmod-0.2.1}/docs/processing.md +0 -0
  37. {specmod-0.2.0 → specmod-0.2.1}/docs/releasing-data.md +0 -0
  38. {specmod-0.2.0 → specmod-0.2.1}/pyproject.toml +0 -0
  39. {specmod-0.2.0 → specmod-0.2.1}/release-please-config.json +0 -0
  40. {specmod-0.2.0 → specmod-0.2.1}/requirements.txt +0 -0
  41. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/__init__.py +0 -0
  42. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/_vendor/__init__.py +0 -0
  43. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/_vendor/qiinv.py +0 -0
  44. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/acquire.py +0 -0
  45. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/api.py +0 -0
  46. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/cli.py +0 -0
  47. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/config/__init__.py +0 -0
  48. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/config/layers.py +0 -0
  49. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/config/provenance.py +0 -0
  50. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/config/sections.py +0 -0
  51. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/config/serialize.py +0 -0
  52. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/core/__init__.py +0 -0
  53. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/core/bandwidth.py +0 -0
  54. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/core/collection.py +0 -0
  55. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/core/noise.py +0 -0
  56. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/core/scalogram.py +0 -0
  57. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/core/spectrum.py +0 -0
  58. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/core/units.py +0 -0
  59. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/datasets.py +0 -0
  60. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/distance.py +0 -0
  61. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/exceptions.py +0 -0
  62. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/fitting/__init__.py +0 -0
  63. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/fitting/base.py +0 -0
  64. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/fitting/event.py +0 -0
  65. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/fitting/guess.py +0 -0
  66. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/fitting/spectrum.py +0 -0
  67. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/io.py +0 -0
  68. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/magnitude.py +0 -0
  69. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/picks/__init__.py +0 -0
  70. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/picks/base.py +0 -0
  71. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/picks/delimited.py +0 -0
  72. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/picks/events.py +0 -0
  73. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/picks/resolution.py +0 -0
  74. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/picks/snuffler.py +0 -0
  75. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/pipeline.py +0 -0
  76. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/plotting.py +0 -0
  77. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/preprocess.py +0 -0
  78. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/smoothing/__init__.py +0 -0
  79. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/smoothing/base.py +0 -0
  80. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/smoothing/konno_ohmachi.py +0 -0
  81. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/smoothing/log_bins.py +0 -0
  82. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/sources/__init__.py +0 -0
  83. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/sources/attenuation.py +0 -0
  84. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/sources/composite.py +0 -0
  85. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/sources/motion.py +0 -0
  86. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/sources/source.py +0 -0
  87. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/spreading.py +0 -0
  88. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/staged.py +0 -0
  89. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/tables.py +0 -0
  90. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/transforms/__init__.py +0 -0
  91. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/transforms/base.py +0 -0
  92. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/transforms/cwt.py +0 -0
  93. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/transforms/fft.py +0 -0
  94. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/transforms/multitaper.py +0 -0
  95. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/transforms/prieto.py +0 -0
  96. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/transforms/quadratic.py +0 -0
  97. {specmod-0.2.0 → specmod-0.2.1}/src/specmod/utils.py +0 -0
  98. {specmod-0.2.0 → specmod-0.2.1}/stubs/README.md +0 -0
  99. {specmod-0.2.0 → specmod-0.2.1}/stubs/lmfit/__init__.pyi +0 -0
  100. {specmod-0.2.0 → specmod-0.2.1}/stubs/lmfit/model.pyi +0 -0
  101. {specmod-0.2.0 → specmod-0.2.1}/stubs/lmfit/parameter.pyi +0 -0
  102. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/__init__.pyi +0 -0
  103. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/clients/__init__.pyi +0 -0
  104. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/clients/fdsn/__init__.pyi +0 -0
  105. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/core/__init__.pyi +0 -0
  106. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/core/event.pyi +0 -0
  107. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/core/inventory.pyi +0 -0
  108. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/core/stream.pyi +0 -0
  109. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/core/trace.pyi +0 -0
  110. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/core/utcdatetime.pyi +0 -0
  111. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/core/util/__init__.pyi +0 -0
  112. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/core/util/base.pyi +0 -0
  113. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/geodetics/__init__.pyi +0 -0
  114. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/signal/__init__.pyi +0 -0
  115. {specmod-0.2.0 → specmod-0.2.1}/stubs/obspy/signal/konnoohmachismoothing.pyi +0 -0
  116. {specmod-0.2.0 → specmod-0.2.1}/studies/magna_2020_paper.toml +0 -0
  117. {specmod-0.2.0 → specmod-0.2.1}/tests/__init__.py +0 -0
  118. {specmod-0.2.0 → specmod-0.2.1}/tests/conftest.py +0 -0
  119. {specmod-0.2.0 → specmod-0.2.1}/tests/golden/motion_reference.json +0 -0
  120. {specmod-0.2.0 → specmod-0.2.1}/tests/golden/pipeline_reference.json +0 -0
  121. {specmod-0.2.0 → specmod-0.2.1}/tests/golden/window_reference.json +0 -0
  122. {specmod-0.2.0 → specmod-0.2.1}/tests/test_acquire.py +0 -0
  123. {specmod-0.2.0 → specmod-0.2.1}/tests/test_ambient_state.py +0 -0
  124. {specmod-0.2.0 → specmod-0.2.1}/tests/test_api_surface.py +0 -0
  125. {specmod-0.2.0 → specmod-0.2.1}/tests/test_collection.py +0 -0
  126. {specmod-0.2.0 → specmod-0.2.1}/tests/test_config.py +0 -0
  127. {specmod-0.2.0 → specmod-0.2.1}/tests/test_cwt.py +0 -0
  128. {specmod-0.2.0 → specmod-0.2.1}/tests/test_datasets.py +0 -0
  129. {specmod-0.2.0 → specmod-0.2.1}/tests/test_docs_are_current.py +0 -0
  130. {specmod-0.2.0 → specmod-0.2.1}/tests/test_end_to_end.py +0 -0
  131. {specmod-0.2.0 → specmod-0.2.1}/tests/test_fitting_defaults.py +0 -0
  132. {specmod-0.2.0 → specmod-0.2.1}/tests/test_golden_reference.py +0 -0
  133. {specmod-0.2.0 → specmod-0.2.1}/tests/test_import.py +0 -0
  134. {specmod-0.2.0 → specmod-0.2.1}/tests/test_io_and_plotting.py +0 -0
  135. {specmod-0.2.0 → specmod-0.2.1}/tests/test_legacy_fixes.py +0 -0
  136. {specmod-0.2.0 → specmod-0.2.1}/tests/test_magnitude.py +0 -0
  137. {specmod-0.2.0 → specmod-0.2.1}/tests/test_make_golden.py +0 -0
  138. {specmod-0.2.0 → specmod-0.2.1}/tests/test_pick_plugins.py +0 -0
  139. {specmod-0.2.0 → specmod-0.2.1}/tests/test_pick_readers.py +0 -0
  140. {specmod-0.2.0 → specmod-0.2.1}/tests/test_picks.py +0 -0
  141. {specmod-0.2.0 → specmod-0.2.1}/tests/test_pipeline.py +0 -0
  142. {specmod-0.2.0 → specmod-0.2.1}/tests/test_pipeline_smoke.py +0 -0
  143. {specmod-0.2.0 → specmod-0.2.1}/tests/test_preprocess.py +0 -0
  144. {specmod-0.2.0 → specmod-0.2.1}/tests/test_prieto.py +0 -0
  145. {specmod-0.2.0 → specmod-0.2.1}/tests/test_quadratic.py +0 -0
  146. {specmod-0.2.0 → specmod-0.2.1}/tests/test_release_config.py +0 -0
  147. {specmod-0.2.0 → specmod-0.2.1}/tests/test_smoothing.py +0 -0
  148. {specmod-0.2.0 → specmod-0.2.1}/tests/test_sources.py +0 -0
  149. {specmod-0.2.0 → specmod-0.2.1}/tests/test_spectral_wiring.py +0 -0
  150. {specmod-0.2.0 → specmod-0.2.1}/tests/test_staged.py +0 -0
  151. {specmod-0.2.0 → specmod-0.2.1}/tests/test_stubs.py +0 -0
  152. {specmod-0.2.0 → specmod-0.2.1}/tests/test_transforms.py +0 -0
  153. {specmod-0.2.0 → specmod-0.2.1}/tests/test_tutorial.py +0 -0
  154. {specmod-0.2.0 → specmod-0.2.1}/tests/test_typing_backlog.py +0 -0
  155. {specmod-0.2.0 → specmod-0.2.1}/tests/test_utils.py +0 -0
  156. {specmod-0.2.0 → specmod-0.2.1}/tests/test_versioning.py +0 -0
  157. {specmod-0.2.0 → specmod-0.2.1}/tools/check_built_version.py +0 -0
  158. {specmod-0.2.0 → specmod-0.2.1}/tools/check_floors.py +0 -0
  159. {specmod-0.2.0 → specmod-0.2.1}/tools/make_golden.py +0 -0
  160. {specmod-0.2.0 → specmod-0.2.1}/tools/measure_docs.py +0 -0
  161. {specmod-0.2.0 → specmod-0.2.1}/tutorial/SpecModTutorial.ipynb +0 -0
  162. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/picks/2019-08-26T07:30:47.000000Z.picks +0 -0
  163. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/picks/2019-08-26T07:30:47.000000Z.xml +0 -0
  164. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/spectra/2019-08-26T07:30:47.000000Z.h5 +0 -0
  165. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/spectra/flatfiles/2019-08-26T07:30:47.000000Z.csv +0 -0
  166. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/spectra/flatfiles/2019-08-26T07:30:47.000000Z.parquet +0 -0
  167. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/stations/inventory.xml +0 -0
  168. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHE_2019-08-26T07:30:47.000000Z +0 -0
  169. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHN_2019-08-26T07:30:47.000000Z +0 -0
  170. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L001..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  171. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHE_2019-08-26T07:30:47.000000Z +0 -0
  172. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHN_2019-08-26T07:30:47.000000Z +0 -0
  173. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L002..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  174. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHE_2019-08-26T07:30:47.000000Z +0 -0
  175. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHN_2019-08-26T07:30:47.000000Z +0 -0
  176. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L006..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  177. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHE_2019-08-26T07:30:47.000000Z +0 -0
  178. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHN_2019-08-26T07:30:47.000000Z +0 -0
  179. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L007..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  180. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHE_2019-08-26T07:30:47.000000Z +0 -0
  181. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHN_2019-08-26T07:30:47.000000Z +0 -0
  182. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L008..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  183. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHE_2019-08-26T07:30:47.000000Z +0 -0
  184. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHN_2019-08-26T07:30:47.000000Z +0 -0
  185. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.L009..HHZ_2019-08-26T07:30:47.000000Z +0 -0
  186. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH1_2019-08-26T07:30:47.000000Z +0 -0
  187. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH2_2019-08-26T07:30:47.000000Z +0 -0
  188. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/LV.LD06..HH3_2019-08-26T07:30:47.000000Z +0 -0
  189. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  190. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  191. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ01.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  192. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ02.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  193. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  194. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  195. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ03.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  196. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  197. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  198. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ04.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  199. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  200. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  201. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ05.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  202. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  203. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  204. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ06.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  205. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  206. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  207. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ07.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  208. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  209. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  210. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ09.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
  211. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHE_2019-08-26T07:30:47.000000Z +0 -0
  212. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHN_2019-08-26T07:30:47.000000Z +0 -0
  213. {specmod-0.2.0 → specmod-0.2.1}/tutorial/data/events/2019-08-26T07:30:47.000000Z/waveforms/UR.AQ10.00.HHZ_2019-08-26T07:30:47.000000Z +0 -0
@@ -28,20 +28,44 @@ jobs:
28
28
  - uses: googleapis/release-please-action@v4
29
29
  id: release
30
30
  with:
31
+ # A pull request opened with the default GITHUB_TOKEN starts no
32
+ # workflow runs at all — "events triggered by the GITHUB_TOKEN will
33
+ # not create a new workflow run". The release PR therefore arrived
34
+ # with *zero* checks, and since `ci`, `docs` and `build` are required
35
+ # on main, it could never satisfy them: permanently blocked, with no
36
+ # failure to point at. v0.2.0 shipped only because the PR was closed
37
+ # and reopened by hand, which re-fires the event from a real account.
38
+ #
39
+ # RELEASE_PLEASE_TOKEN_SPECMOD is a fine-grained PAT (contents + pull
40
+ # requests, write) so the PR is opened by a user and CI runs on it
41
+ # normally. It is *not* a PyPI credential — the upload below still
42
+ # authenticates by OIDC, so the number of publishing secrets is
43
+ # still zero. See docs/releasing.md for how to mint and renew it.
44
+ #
45
+ # The fallback keeps the workflow working in a fork or before the
46
+ # secret exists; it degrades to the blocked-PR behaviour, not to a
47
+ # broken run.
48
+ token: ${{ secrets.RELEASE_PLEASE_TOKEN_SPECMOD || secrets.GITHUB_TOKEN }}
31
49
  config-file: release-please-config.json
32
50
  manifest-file: .release-please-manifest.json
33
51
 
34
52
  # Deliberately in this workflow rather than a separate publish.yml keyed on
35
- # `release: published`, which is what §6.5 of the plan used to describe.
36
- # release-please creates the release with the default GITHUB_TOKEN, and
37
- # per GitHub's docs "events triggered by the GITHUB_TOKEN will not create a
38
- # new workflow run" — so that publish workflow would never fire. The
39
- # alternative is a personal access token in secrets, which is the one thing
40
- # Trusted Publishing exists to avoid. Gating on the action's own output
41
- # keeps the token count at zero.
53
+ # `release: published`, which is what §6.5 of the plan used to describe. That
54
+ # workflow could not fire at all while release-please ran on GITHUB_TOKEN,
55
+ # so this job gates on the action's own `release_created` output instead.
42
56
  #
43
- # Zenodo is unaffected: it listens to the release *webhook*, which is not
44
- # subject to that restriction, so the DOI is still minted from the release.
57
+ # With RELEASE_PLEASE_TOKEN_SPECMOD the release is created by a PAT, which
58
+ # *does* start workflow runs, so a separate publish.yml would now work. Still
59
+ # not worth splitting: one workflow is one concurrency group and one place to
60
+ # read, with no race between two runs when two merges land together. The
61
+ # `release_created` gate is also exact, where an event key would fire on any
62
+ # release — including one created by hand.
63
+ #
64
+ # Note the PAT is not a publishing credential: the upload below authenticates
65
+ # by OIDC, so the number of secrets that can push to PyPI is still zero.
66
+ #
67
+ # Zenodo is unaffected either way: it listens to the release *webhook*, which
68
+ # is not subject to the token restriction, so the DOI is minted regardless.
45
69
  publish:
46
70
  needs: release-please
47
71
  if: needs.release-please.outputs.release_created == 'true'
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.2.1"
3
+ }
@@ -1,6 +1,26 @@
1
1
  # Changelog
2
2
 
3
- ## [0.2.0](https://github.com/sgjholt/SpecMod/compare/v0.1.1...v0.2.0) (2026-08-23)
3
+ <!-- The 0.2.0 heading below is edited by hand, and is the only entry that is.
4
+ release-please generated `compare/v0.1.1...v0.2.0`, which 404s: 0.1.1 predates
5
+ this repository's tagging and was never tagged, so there is nothing at that
6
+ ref. It is preserved on the frozen `master` branch instead, and comparing
7
+ against that branch is the same diff under a name that resolves. Only the first
8
+ release could have this problem — every later one has a real predecessor tag —
9
+ so leave subsequent headings as generated. release-please only prepends to this
10
+ file, so this edit survives. -->
11
+
12
+ ## [0.2.1](https://github.com/sgjholt/SpecMod/compare/v0.2.0...v0.2.1) (2026-08-23)
13
+
14
+
15
+ ### Documentation
16
+
17
+ * add the Zenodo DOI to the README and the citation metadata ([8a89884](https://github.com/sgjholt/SpecMod/commit/8a89884f654b14bf5eb9ed8a32d10dc22d5e5fb4))
18
+ * PyPI and docs badges, and an install section for people who are not us ([d444397](https://github.com/sgjholt/SpecMod/commit/d44439762214b93fd8eef3f64745570b3b8be2b0))
19
+ * repoint the 0.2.0 changelog link, which 404s ([f1bbe31](https://github.com/sgjholt/SpecMod/commit/f1bbe3143ca3ca6dd58f584546e716d2170a790a))
20
+ * say where the code behind the publication lives ([ae7e906](https://github.com/sgjholt/SpecMod/commit/ae7e906209a87844cf2106a826be5111a6ef2036))
21
+ * turn the roadmap's stages into milestones against versions ([b933e69](https://github.com/sgjholt/SpecMod/commit/b933e69d219a54e4a7db894797a507a3bb24e31c))
22
+
23
+ ## [0.2.0](https://github.com/sgjholt/SpecMod/compare/master...v0.2.0) (2026-08-23)
4
24
 
5
25
 
6
26
  ### ⚠ BREAKING CHANGES
@@ -7,6 +7,13 @@ authors:
7
7
  given-names: James
8
8
  repository-code: "https://github.com/sgjholt/SpecMod"
9
9
  license: MIT
10
+ identifiers:
11
+ # The concept DOI, which always resolves to the newest release. Zenodo also
12
+ # mints a version DOI per release; cite that one instead when reproducibility
13
+ # matters and you need the reader to land on the exact version you ran.
14
+ - type: doi
15
+ value: "10.5281/zenodo.22071455"
16
+ description: "Concept DOI — resolves to the latest release."
10
17
  keywords:
11
18
  - seismology
12
19
  - spectral modelling
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: specmod
3
- Version: 0.2.0
3
+ Version: 0.2.1
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
@@ -56,6 +56,10 @@ Description-Content-Type: text/markdown
56
56
 
57
57
  # SpecMod
58
58
 
59
+ [![PyPI](https://img.shields.io/pypi/v/specmod.svg)](https://pypi.org/project/specmod/)
60
+ [![Documentation](https://readthedocs.org/projects/specmod/badge/?version=stable)](https://specmod.readthedocs.io/en/stable/)
61
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22071455.svg)](https://doi.org/10.5281/zenodo.22071455)
62
+
59
63
  A Python toolbox for processing and modelling seismic spectra, following the
60
64
  method of Edwards *et al.* (2010).
61
65
 
@@ -71,26 +75,44 @@ source model to direct-phase spectra.
71
75
  > breaking changes at every `0.x` release until the API settles at 1.0 — they
72
76
  > land in minor bumps by design, with no deprecation cycle. Pin an exact
73
77
  > version for anything you intend to publish.
74
- > [`docs/roadmap.md`](docs/roadmap.md) says which stages are done and what 1.0
75
- > will mean; [`docs/REFACTOR_PLAN.md`](docs/REFACTOR_PLAN.md) is the working
76
- > document behind it.
78
+ > [`docs/roadmap.md`](docs/roadmap.md) says what has shipped, in which version,
79
+ > and what 1.0 will mean; [`docs/REFACTOR_PLAN.md`](docs/REFACTOR_PLAN.md) is
80
+ > the working document behind it.
77
81
 
78
82
  ## Installation
79
83
 
80
84
  Requires Python 3.11 or newer.
81
85
 
86
+ ```sh
87
+ pip install specmod
88
+ ```
89
+
90
+ While this is `0.x`, pin the exact version in anything you intend to publish:
91
+ `pip install specmod==<version>`, taking the current one from the badge above.
92
+ The reason is in the status note — `0.x` releases move names and numbers, and
93
+ the pin plus the configuration stamp each output carries are together what
94
+ make a run reproducible.
95
+
96
+ To work on SpecMod rather than with it, clone the repository and install it
97
+ editable with the test and lint tooling:
98
+
82
99
  ```sh
83
100
  pip install -e ".[dev]"
84
101
  ```
85
102
 
86
- Optional extras:
103
+ Optional extras, installable as `pip install "specmod[multitaper]"` or in
104
+ combination — `pip install "specmod[multitaper,wavelet]"`:
87
105
 
88
106
  | Extra | Adds |
89
107
  |---|---|
108
+ | `io` | `h5py` and `pyarrow` — needed to save or load spectra, as HDF5 for arrays and Parquet for tables |
90
109
  | `multitaper` | Prieto's `multitaper` package — jackknife confidence intervals, F-test for spectral lines |
91
110
  | `wavelet` | PyWavelets, for wavelet families beyond the built-in Morlet |
92
111
  | `mcmc` | `emcee`, for Markov-chain Monte Carlo parameter search |
93
112
 
113
+ `io` is the one most people want: without it SpecMod computes and plots
114
+ normally, but `specmod.io` raises on the first save telling you to install it.
115
+
94
116
  No Fortran compiler is needed. Multitaper estimation is implemented natively on
95
117
  SciPy's DPSS tapers, so the historical `mtspec` dependency — Fortran source with
96
118
  no wheels and no release since 2016 — is no longer required.
@@ -202,6 +224,13 @@ Every output records the configuration that produced it, a hash of it, and the
202
224
  SpecMod version, so a locally-overridden run is still reproducible from its
203
225
  outputs.
204
226
 
227
+ The published Magna results were produced with **0.1.1**, which predates this
228
+ refactor. That code is preserved unchanged on the
229
+ [`master`](https://github.com/sgjholt/SpecMod/tree/master) branch, which is
230
+ protected and frozen; `main` is the trunk now. `0.1.1` was never tagged or
231
+ published to PyPI, so the branch is the reference — there is no release to
232
+ install. Read it there when you need to see exactly what the paper ran.
233
+
205
234
  ## Documentation
206
235
 
207
236
  The full documentation — the pipeline with its equations, the estimator
@@ -1,5 +1,9 @@
1
1
  # SpecMod
2
2
 
3
+ [![PyPI](https://img.shields.io/pypi/v/specmod.svg)](https://pypi.org/project/specmod/)
4
+ [![Documentation](https://readthedocs.org/projects/specmod/badge/?version=stable)](https://specmod.readthedocs.io/en/stable/)
5
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22071455.svg)](https://doi.org/10.5281/zenodo.22071455)
6
+
3
7
  A Python toolbox for processing and modelling seismic spectra, following the
4
8
  method of Edwards *et al.* (2010).
5
9
 
@@ -15,26 +19,44 @@ source model to direct-phase spectra.
15
19
  > breaking changes at every `0.x` release until the API settles at 1.0 — they
16
20
  > land in minor bumps by design, with no deprecation cycle. Pin an exact
17
21
  > version for anything you intend to publish.
18
- > [`docs/roadmap.md`](docs/roadmap.md) says which stages are done and what 1.0
19
- > will mean; [`docs/REFACTOR_PLAN.md`](docs/REFACTOR_PLAN.md) is the working
20
- > document behind it.
22
+ > [`docs/roadmap.md`](docs/roadmap.md) says what has shipped, in which version,
23
+ > and what 1.0 will mean; [`docs/REFACTOR_PLAN.md`](docs/REFACTOR_PLAN.md) is
24
+ > the working document behind it.
21
25
 
22
26
  ## Installation
23
27
 
24
28
  Requires Python 3.11 or newer.
25
29
 
30
+ ```sh
31
+ pip install specmod
32
+ ```
33
+
34
+ While this is `0.x`, pin the exact version in anything you intend to publish:
35
+ `pip install specmod==<version>`, taking the current one from the badge above.
36
+ The reason is in the status note — `0.x` releases move names and numbers, and
37
+ the pin plus the configuration stamp each output carries are together what
38
+ make a run reproducible.
39
+
40
+ To work on SpecMod rather than with it, clone the repository and install it
41
+ editable with the test and lint tooling:
42
+
26
43
  ```sh
27
44
  pip install -e ".[dev]"
28
45
  ```
29
46
 
30
- Optional extras:
47
+ Optional extras, installable as `pip install "specmod[multitaper]"` or in
48
+ combination — `pip install "specmod[multitaper,wavelet]"`:
31
49
 
32
50
  | Extra | Adds |
33
51
  |---|---|
52
+ | `io` | `h5py` and `pyarrow` — needed to save or load spectra, as HDF5 for arrays and Parquet for tables |
34
53
  | `multitaper` | Prieto's `multitaper` package — jackknife confidence intervals, F-test for spectral lines |
35
54
  | `wavelet` | PyWavelets, for wavelet families beyond the built-in Morlet |
36
55
  | `mcmc` | `emcee`, for Markov-chain Monte Carlo parameter search |
37
56
 
57
+ `io` is the one most people want: without it SpecMod computes and plots
58
+ normally, but `specmod.io` raises on the first save telling you to install it.
59
+
38
60
  No Fortran compiler is needed. Multitaper estimation is implemented natively on
39
61
  SciPy's DPSS tapers, so the historical `mtspec` dependency — Fortran source with
40
62
  no wheels and no release since 2016 — is no longer required.
@@ -146,6 +168,13 @@ Every output records the configuration that produced it, a hash of it, and the
146
168
  SpecMod version, so a locally-overridden run is still reproducible from its
147
169
  outputs.
148
170
 
171
+ The published Magna results were produced with **0.1.1**, which predates this
172
+ refactor. That code is preserved unchanged on the
173
+ [`master`](https://github.com/sgjholt/SpecMod/tree/master) branch, which is
174
+ protected and frozen; `main` is the trunk now. `0.1.1` was never tagged or
175
+ published to PyPI, so the branch is the reference — there is no release to
176
+ install. Read it there when you need to see exactly what the paper ran.
177
+
149
178
  ## Documentation
150
179
 
151
180
  The full documentation — the pipeline with its equations, the estimator
@@ -24,8 +24,8 @@ treat everything here as provisional until the API settles at 1.0:
24
24
 
25
25
  What will *not* change silently: the units conventions and the Parseval
26
26
  contract are pinned by tests, and the golden references fail loudly rather
27
- than drifting. The [roadmap](roadmap.md) says which stages are done and what
28
- 1.0 will mean.
27
+ than drifting. The [roadmap](roadmap.md) says what has shipped, in which
28
+ version, and what 1.0 will mean.
29
29
  :::
30
30
 
31
31
  ```python
@@ -67,8 +67,8 @@ print(fits.table[["id", "llpsp", "fc", "ts"]])
67
67
  settings that have to be turned on once.
68
68
 
69
69
  [Roadmap](roadmap.md)
70
- : What is built, what is being worked on, and what 1.0 will mean. Stages, not
71
- dates.
70
+ : What has shipped and in which version, what is being worked on, and what 1.0
71
+ will mean. Milestones, not dates.
72
72
 
73
73
  ## Working on SpecMod
74
74
 
@@ -27,19 +27,52 @@ bump.
27
27
 
28
28
  ## One-time setup
29
29
 
30
- Five things, none of which can be done from a commit. Until they are done the
30
+ Six things, none of which can be done from a commit. Until they are done the
31
31
  release workflow is inert rather than wrong — it opens a release PR and stops.
32
32
 
33
- 1. **Let Actions open pull requests.** Settings → Actions → General →
34
- Workflow permissions → tick *Allow GitHub Actions to create and approve pull
35
- requests*. Without it release-please fails with `GitHub Actions is not
36
- permitted to create or approve pull requests`.
37
-
38
- 2. **Create the `pypi` environment.** Settings → Environments → New
39
- environment → `pypi`. Add required reviewers here if you want a second
40
- human gate on the upload itself.
33
+ 1. **Mint `RELEASE_PLEASE_TOKEN_SPECMOD`.** Settings → Developer settings →
34
+ Personal access tokens → Fine-grained tokens → *Generate new token*.
41
35
 
42
- 3. **Register the trusted publisher on PyPI.** On the project page (or, for
36
+ | Field | Value |
37
+ |---|---|
38
+ | Repository access | Only select repositories → `SpecMod` |
39
+ | Contents | Read and write |
40
+ | Pull requests | Read and write |
41
+ | Expiration | up to 366 days — see the renewal note below |
42
+
43
+ Then Settings → Secrets and variables → Actions → *New repository secret*,
44
+ named exactly `RELEASE_PLEASE_TOKEN_SPECMOD`.
45
+
46
+ This is what makes the release PR run CI. Without it the PR is opened by
47
+ `GITHUB_TOKEN`, which starts no workflow runs at all, so the three required
48
+ checks never report and the PR is blocked with nothing to fix. The token
49
+ never touches PyPI — the upload authenticates by OIDC — so this does not
50
+ reintroduce a publishing secret.
51
+
52
+ **It expires.** When it does, the symptom is the old one returning: a
53
+ release PR with no checks on it. Renew the token and update the secret;
54
+ nothing in the repository changes. A GitHub App token via
55
+ `actions/create-github-app-token` avoids the expiry entirely and is the
56
+ better answer if this becomes annoying.
57
+
58
+ 2. **Let Actions open pull requests.** Settings → Actions → General →
59
+ Workflow permissions → tick *Allow GitHub Actions to create and approve pull
60
+ requests*. Only needed as a fallback — with `RELEASE_PLEASE_TOKEN_SPECMOD`
61
+ set, the PR is opened by a user, not by Actions — but leave it on so the
62
+ workflow still works if the token lapses.
63
+
64
+ 3. **Create the `pypi` environment.** Settings → Environments → New
65
+ environment → `pypi`.
66
+
67
+ Required reviewers here are optional, and worth thinking about before
68
+ adding: they hold the `publish` job at `waiting` until a human approves the
69
+ deployment, and **that approval cannot be given from the GitHub mobile
70
+ app** — the button exists only on the web UI and the REST API. Merging the
71
+ release PR is already a deliberate human act, and
72
+ `tools/check_built_version.py` is what actually prevents a wrong version
73
+ reaching PyPI, so the reviewer gate buys less than it looks like it does.
74
+
75
+ 4. **Register the trusted publisher on PyPI.** On the project page (or, for
43
76
  the first ever upload, under *Publishing* → *Add a new pending publisher*):
44
77
 
45
78
  | Field | Value |
@@ -53,12 +86,12 @@ release workflow is inert rather than wrong — it opens a release PR and stops.
53
86
  that actually runs. If the workflow is ever renamed, this has to be changed
54
87
  in the same sitting or the upload fails authentication.
55
88
 
56
- 4. **Turn on the Zenodo webhook.** Log into Zenodo with GitHub, find `SpecMod`
89
+ 5. **Turn on the Zenodo webhook.** Log into Zenodo with GitHub, find `SpecMod`
57
90
  in the repository list, and flip the switch. It takes effect for releases
58
91
  made *after* it is on, so do it before the first release rather than after.
59
92
  `CITATION.cff` supplies the metadata.
60
93
 
61
- 5. **Require the checks on `main`.** Branch protection → *Require status
94
+ 6. **Require the checks on `main`.** Branch protection → *Require status
62
95
  checks to pass* → add exactly three: **`ci`**, **`docs`**, **`build`**.
63
96
 
64
97
  Those are job names, not workflow names, and only these three are stable:
@@ -68,10 +101,12 @@ release workflow is inert rather than wrong — it opens a release PR and stops.
68
101
  instead matches nothing, and a required check that never reports blocks
69
102
  every merge.
70
103
 
71
- The release pull request is an ordinary pull request and goes through them
72
- like any other — including the approval step, since GitHub holds workflow
73
- runs on pull requests opened by `github-actions[bot]` until a maintainer
74
- approves them.
104
+ The release pull request goes through them like any other — but only
105
+ because of step 1. This page previously said GitHub *holds* the runs on a
106
+ `github-actions[bot]` pull request until a maintainer approves them, and
107
+ that is not what happens: no runs are created, there is nothing to approve,
108
+ and the PR sits blocked with an empty check list.
109
+ `RELEASE_PLEASE_TOKEN_SPECMOD` is what makes this paragraph true.
75
110
 
76
111
  ## What a version number means while this is 0.x
77
112
 
@@ -108,13 +143,20 @@ To skip a release, do not merge the PR. It stays open and keeps accruing.
108
143
  ## Things that are the way they are for a reason
109
144
 
110
145
  **The publish job is in `release.yml`, not a separate `publish.yml`.** The
111
- obvious design — a workflow keyed on `release: published` — never fires.
112
- release-please creates the release with the default `GITHUB_TOKEN`, and
113
- "events triggered by the `GITHUB_TOKEN` will not create a new workflow run".
114
- The workaround is a personal access token in secrets, which is the one thing
115
- Trusted Publishing exists to avoid, so the publish job gates on
116
- release-please's own `release_created` output instead. Zenodo is unaffected:
117
- it listens to the release *webhook*, which is not subject to that restriction.
146
+ obvious design — a workflow keyed on `release: published` — could not fire at
147
+ all when release-please ran on the default `GITHUB_TOKEN`, because "events
148
+ triggered by the `GITHUB_TOKEN` will not create a new workflow run". So the
149
+ publish job gates on release-please's own `release_created` output instead.
150
+
151
+ `RELEASE_PLEASE_TOKEN_SPECMOD` removes that constraint — a release created by
152
+ a PAT *does* start workflow runs — so a separate `publish.yml` would now work.
153
+ It is still not worth splitting: one workflow means one `concurrency` group, one
154
+ place to read, and no dependency on the ordering of two runs that would race
155
+ whenever two merges land together. The `release_created` gate is also exact,
156
+ where an event key would fire on any release including one made by hand.
157
+
158
+ Zenodo was never affected either way: it listens to the release *webhook*,
159
+ which is not subject to the token restriction.
118
160
 
119
161
  **`include-component-in-tag` is `false`.** Left on, the tag is
120
162
  `specmod-v0.2.0`, which `pyproject.toml`'s `--match v[0-9]*` does not describe
@@ -165,3 +207,18 @@ If the `publish` job fails after the release exists — a transient PyPI error,
165
207
  say — re-run that job from the Actions UI. Do not re-run `release-please`
166
208
  expecting a second attempt: `release_created` is only true on the run that
167
209
  created the release.
210
+
211
+ ## When the release PR has no checks on it
212
+
213
+ Not a red check — *no checks at all*, an empty list, and the PR blocked
214
+ because the three required ones never reported. This means release-please fell
215
+ back to `GITHUB_TOKEN`: either `RELEASE_PLEASE_TOKEN_SPECMOD` is unset, or it
216
+ expired, or its repository access no longer covers `SpecMod`. Renew it
217
+ (one-time setup, step 1); nothing in the repository needs changing.
218
+
219
+ To unblock the release PR that is already open, without waiting for a new
220
+ commit: **close it and immediately reopen it.** That re-fires
221
+ `pull_request.reopened` from your account rather than from the token, and the
222
+ checks run. It is the same trick that got `v0.2.0` out, and it is safe — the
223
+ `autorelease: pending` label survives, so release-please still recognises the
224
+ merge as a release, and no history is touched.
@@ -0,0 +1,148 @@
1
+ # Roadmap
2
+
3
+ SpecMod is being rebuilt in stages, each one independently usable. This page
4
+ says what has shipped, in which version, what is being worked on, and what 1.0
5
+ will mean.
6
+
7
+ **No dates.** The order is by dependency, not by calendar, and what comes after
8
+ the current milestone can still change. Shipped work names the version that
9
+ carries it, so it can be installed and checked rather than taken on trust;
10
+ unreleased work says so plainly.
11
+ [`REFACTOR_PLAN.md`](https://github.com/sgjholt/SpecMod/blob/main/docs/REFACTOR_PLAN.md)
12
+ is the working document behind this one and carries the reasoning, the
13
+ measurements and the open questions.
14
+
15
+ ## Where it is now
16
+
17
+ **v0.2.0**, the first release of the rebuilt package —
18
+ [on PyPI](https://pypi.org/p/specmod), with a Zenodo DOI and its own
19
+ [documentation version](https://specmod.readthedocs.io/en/stable/). Install it
20
+ with `pip install specmod`.
21
+
22
+ Still alpha, still pre-1.0: names and signatures move between `0.x` releases
23
+ without a deprecation cycle. Everything below marked shipped is released,
24
+ tested against golden references, and usable — but pin an exact version for
25
+ anything you intend to publish. See
26
+ [Releasing the software](releasing.md) for what a version number means here.
27
+
28
+ ## Shipped in v0.2.0
29
+
30
+ The version before this one, `0.1.1`, is the pre-refactor code that produced
31
+ the published Magna results. It is preserved unchanged on the
32
+ [`master`](https://github.com/sgjholt/SpecMod/tree/master) branch, which is
33
+ protected and frozen — it was never tagged or published to PyPI, so that
34
+ branch is the only reference to it. Everything below is the delta between it
35
+ and v0.2.0, which is why the first changelog is enormous and correctly so.
36
+
37
+ ### An installable package
38
+
39
+ A real `pyproject.toml`, `src/` layout, snake_case modules, linting, type
40
+ checking and a test suite on CI. Before this, the package could not be
41
+ installed or imported without editing paths by hand.
42
+
43
+ ### Configuration without globals
44
+
45
+ Settings live in a `config/` package with semantic sections and layered
46
+ overrides, instead of module-level constants read at import time. Every output
47
+ records the configuration that produced it, so a locally-overridden run is
48
+ reproducible from its own outputs.
49
+
50
+ ### Publishing: docs, PyPI, DOI
51
+
52
+ This site, built from the repository on every merge; automated changelog and
53
+ version derivation from tags; PyPI upload through Trusted Publishing; a Zenodo
54
+ DOI per release. Deliberately built early, while the package was small enough
55
+ that debugging the pipeline was cheap — and v0.2.0 is the release that proved
56
+ every leg of it end to end.
57
+
58
+ A fresh clone still needs the one-time repository settings listed in
59
+ [Releasing the software](releasing.md); they are account and repository state,
60
+ not something a commit can carry.
61
+
62
+ ### The transform layer
63
+
64
+ One `SpectralEstimator` protocol with interchangeable implementations —
65
+ `FFTEstimator`, `WelchEstimator`, `MultitaperEstimator` and Prieto's — plus
66
+ Konno–Ohmachi smoothing and log-binning as separate, composable steps. The
67
+ `mtspec` Fortran dependency, which no longer builds on current toolchains, is
68
+ demoted to an optional legacy backend rather than being the only path.
69
+
70
+ What each estimator does to real data is measured in
71
+ [Choosing a transform](choosing-a-transform.md); the differences are large
72
+ enough to matter to a magnitude.
73
+
74
+ ### Wavelets
75
+
76
+ A continuous wavelet transform alongside the Fourier estimators:
77
+ `CWTEstimator`, a `Scalogram` that tracks its cone of influence, quality
78
+ checks over it, and time-averaging back to a spectrum with ground-motion units
79
+ preserved.
80
+
81
+ ### Typed, portable persistence
82
+
83
+ HDF5 for arrays and Parquet for tables, replacing pickle everywhere — nothing
84
+ in the package can write a pickle any more, so a saved result is readable
85
+ without the code that wrote it and cannot execute anything on load.
86
+
87
+ ### A stable import surface
88
+
89
+ `specmod.api` — a path-free, deterministic, non-mutating import surface with
90
+ typed errors, for downstream packages that need something narrower than the
91
+ whole package and less volatile than its internals.
92
+
93
+ ## In progress — not yet released
94
+
95
+ ### Finishing the decomposition
96
+
97
+ Breaking the remaining large modules into packages with narrow
98
+ responsibilities. The spectral core, the fitting layer and the pick readers
99
+ are already packages, and the type-checking backlog is empty.
100
+
101
+ What is left: `io.py` and `plotting.py` are still single modules, and the
102
+ operations that mutate in place need to return new objects instead. Neither is
103
+ large — the split is about responsibilities, not line count.
104
+
105
+ ## Planned
106
+
107
+ ### 1.0 — the API stops moving
108
+
109
+ The theory page that states the normalisation and units conventions
110
+ explicitly, the tutorial rebuilt as an executed notebook so it cannot rot
111
+ silently, and a "what changed since 0.1" guide for anyone upgrading. Then the
112
+ 1.0 release, which is the promise that names and signatures stop moving
113
+ without a deprecation cycle.
114
+
115
+ That promise is the whole content of the number, which is why it has to be a
116
+ decision rather than something a breaking commit does on its way past. Until
117
+ it is made, breaking changes bump the minor.
118
+
119
+ ## After 1.0
120
+
121
+ Designed but deliberately not on the path to 1.0, because each is blocked on
122
+ an input rather than on effort — mostly a real file from a real tool, which a
123
+ guess written from documentation cannot substitute for:
124
+
125
+ - **Presets for picker output** (PhaseNet, EQTransformer, SeisBench), so those
126
+ users write no column mapping. The configurable reader already exists; a
127
+ preset is a mapping and a test against one real file.
128
+ - **Confirming two more pick formats** (NonLinLoc `.hyp`, IMS/GSE bulletins)
129
+ that cannot be round-tripped through ObsPy and so are listed as unconfirmed
130
+ rather than claimed.
131
+ - **SeisComP picks**, which ObsPy's SCML reader currently discards. A test
132
+ fails when that starts working upstream.
133
+ - **Recording pick-resolution policy in the configuration**, alongside the
134
+ provenance stamp.
135
+ - **A fuller `acquire --verify`** that re-fetches and diffs against the
136
+ manifest, rather than only detecting local tampering.
137
+
138
+ ## How this page works
139
+
140
+ Each shipped entry names the version that carries it, so a reader can install
141
+ that version and check the claim. Work that is merged but unreleased sits under
142
+ *In progress* and gets its version when a release goes out — merged is not
143
+ shipped, and this page does not blur the two.
144
+
145
+ Before v0.2.0 this was a list of stages, because there was no released version
146
+ to point at and "done" could only mean merged. The full changelog for every
147
+ release is in
148
+ [`CHANGELOG.md`](https://github.com/sgjholt/SpecMod/blob/main/CHANGELOG.md).
@@ -1,3 +0,0 @@
1
- {
2
- ".": "0.2.0"
3
- }