Roadmap¶
SpecMod is being rebuilt in stages, each one independently usable. This page says what has shipped, in which version, what is being worked on, and what 1.0 will mean.
No dates. The order is by dependency, not by calendar, and what comes after
the current milestone can still change. Shipped work names the version that
carries it, so it can be installed and checked rather than taken on trust;
unreleased work says so plainly.
REFACTOR_PLAN.md
is the working document behind this one and carries the reasoning, the
measurements and the open questions.
Where it is now¶
SpecMod is on PyPI, with a Zenodo DOI per release
and its own documentation version
for each. Install it with pip install specmod; v0.2.0 was the first release
of the rebuilt package.
This page was built from version 0.3.0.post1.dev12+gc7497e8. On stable that is the
release you are reading about; on latest it is a development build ahead of
it, which is the honest answer to which code the milestones below describe.
Still alpha, still pre-1.0: names and signatures move between 0.x releases
without a deprecation cycle. Everything below marked shipped is released,
tested against golden references, and usable — but pin an exact version for
anything you intend to publish. See
Releasing the software for what a version number means here.
Shipped in v0.2.0¶
The version before this one, 0.1.1, is the pre-refactor code that produced
the published Magna results. It is preserved unchanged on the
master branch, which is
protected and frozen — it was never tagged or published to PyPI, so that
branch is the only reference to it. Its tip,
453c77c, is the commit
the paper cites as v0.1.1; cite that rather than the branch name, which is a
moving target in principle even though this one will not move. Everything below is the delta between it
and v0.2.0, which is why the first changelog is enormous and correctly so.
An installable package¶
A real pyproject.toml, src/ layout, snake_case modules, linting, type
checking and a test suite on CI. Before this, the package could not be
installed or imported without editing paths by hand.
Configuration without globals¶
Settings live in a config/ package with semantic sections and layered
overrides, instead of module-level constants read at import time. Every output
records the configuration that produced it, so a locally-overridden run is
reproducible from its own outputs.
Publishing: docs, PyPI, DOI¶
This site, built from the repository on every merge; automated changelog and version derivation from tags; PyPI upload through Trusted Publishing; a Zenodo DOI per release. Deliberately built early, while the package was small enough that debugging the pipeline was cheap — and v0.2.0 is the release that proved every leg of it end to end.
A fresh clone still needs the one-time repository settings listed in Releasing the software; they are account and repository state, not something a commit can carry.
The transform layer¶
One SpectralEstimator protocol with interchangeable implementations —
FFTEstimator, WelchEstimator, MultitaperEstimator and Prieto’s — plus
Konno–Ohmachi smoothing and log-binning as separate, composable steps. The
mtspec Fortran dependency, which no longer builds on current toolchains, is
dropped rather than being the only path: multitaper is implemented natively on
SciPy’s DPSS tapers, and Prieto’s multitaper package is available through the
optional [multitaper] extra as the same-lineage substitute. Asking the
pipeline for mtspec by name raises, and says which two to use instead.
What each estimator does to real data is measured in Choosing a transform; the differences are large enough to matter to a magnitude.
Wavelets¶
A continuous wavelet transform alongside the Fourier estimators:
CWTEstimator, a Scalogram that tracks its cone of influence, quality
checks over it, and time-averaging back to a spectrum with ground-motion units
preserved.
Typed, portable persistence¶
HDF5 for arrays and Parquet for tables, replacing pickle everywhere — nothing in the package can write a pickle any more, so a saved result is readable without the code that wrote it and cannot execute anything on load.
A stable import surface¶
specmod.api — a path-free, deterministic, non-mutating import surface with
typed errors, for downstream packages that need something narrower than the
whole package and less volatile than its internals.
Shipped in v0.2.2¶
The tutorial, executed¶
The tutorial is published as part of this site and re-executed on every build, so every figure and number on the page came from running the code being documented. A notebook that stops working fails the build rather than going quietly stale, which is why it was a 1.0 requirement.
Shipped in v0.3.0¶
The decomposition, finished¶
This was the last item 1.0 was waiting on.
io.py and plotting.py are now packages, alongside the spectral core, the
fitting layer and the pick readers; the type-checking backlog is empty. The
split is by responsibility rather than line count — for io/, what a file
contains against how one is written against where the optional dependency
lives.
specmod.preprocess no longer modifies the stream it is given. Every
function returns a new one, which is the package-wide rule the containers have
always followed and the only place it did not hold. Ten functions were renamed
to say so — cut_s is s_window, set_picks is with_picks — because a
function that starts returning instead of mutating while keeping its name
leaves every existing call running and silently doing nothing.
Upgrading is the table.
The documentation 1.0 asked for¶
The conventions are stated explicitly and can be found: the amplitude
convention, the Parseval contract, and now the moment and magnitude equations
with their constants, in
How a spectrum is processed — in the sections that apply them,
signposted from Guides rather than split onto a page of their own.
Upgrading covers moving code off the pre-refactor
master.
Planned¶
1.0 — the API stops moving¶
Everything this was waiting on shipped in v0.3.0 — the documentation, and the decomposition above with the signature changes it implied. What remains is the release itself, which says that names and signatures stop moving without a deprecation cycle.
That promise is the whole content of the number, which is why it has to be a decision rather than something a breaking commit does on its way past. Until it is made, breaking changes bump the minor. The honest test before making it is whether a release goes by without one — the API is not settled because the backlog is empty, it is settled when it stops moving.
By that test, 1.0 is not ready. v0.3.0 is the release that emptied the
backlog and it carried two breaking changes itself: the ten renamed
preprocess functions, and the tutorial’s page moving. So what 1.0 now waits
on is the next release going out without one — which is a thing that has to be
observed rather than declared, and cannot be brought forward by finishing
anything.
After 1.0¶
Designed but deliberately not on the path to 1.0, because each is blocked on an input rather than on effort — mostly a real file from a real tool, which a guess written from documentation cannot substitute for:
Presets for picker output (PhaseNet, EQTransformer, SeisBench), so those users write no column mapping. The configurable reader already exists; a preset is a mapping and a test against one real file.
Confirming two more pick formats (NonLinLoc
.hyp, IMS/GSE bulletins) that cannot be round-tripped through ObsPy and so are listed as unconfirmed rather than claimed.SeisComP picks, which ObsPy’s SCML reader currently discards. A test fails when that starts working upstream.
Recording pick-resolution policy in the configuration, alongside the provenance stamp.
A fuller
specmod fetch --verifythat re-fetches and diffs against the manifest, rather than only detecting local tampering.
How this page works¶
Each shipped entry names the version that carries it, so a reader can install that version and check the claim. Work that is merged but unreleased sits under In progress and gets its version when a release goes out — merged is not shipped, and this page does not blur the two. There is no such section right now, because nothing is merged and unreleased; that is the state the page should be in between releases, not a section that went missing.
The move at release time is the step this page got wrong once. The v0.3.0 work
sat under In progress — not yet released for a week after v0.3.0 was
released, because release-please writes the changelog and the manifest and
knows nothing about this file. tests/test_release_config.py now fails when
the released minor version is ahead of every version this page names, which is
the check that was missing rather than a rule that was.
Before v0.2.0 this was a list of stages, because there was no released version
to point at and “done” could only mean merged. The full changelog for every
release is in
CHANGELOG.md.