Two adversarial reviews of the release. Both said do not ship, and they were
right twice over.
The seven-day view panicked. elide() cut a title at cut.len() / 2, a byte
index into a string it had counted in characters, and every movable feast
title carries an em dash: at fourteen terminal widths, 80 among them, it
aborted with exit 101 on the README's own headline command. tests/elide.rs now
cuts every title the program can print at every width it can be asked to print
at.
The changelog's first Calendar entry was false. It said a vigil or polyeleos
saint reaches fish in the three lesser fasts; the code gives wine and oil to
every rank but great, and caps the Dormition Fast at wine and oil whatever the
rank. A reader in the Dormition Fast was told this release let a saint bring
fish. docs/versioning.md makes that section a contract, so a wrong entry there
is worse than a wrong comment.
The Python bindings read the config file where the CLI reads the environment
first, so TYPIKON_JURISDICTION moved one and not the other and the two
answered for different churches on the same machine. CI now asserts they
agree, and runs the README example checker, which was standing between the
docs and reality with nothing running it.
Three changes to the surface, made now because after 1.0.0 they are a major
version: binds is null rather than the string none where a church legislates
no binding fast at all; iCalendar UIDs carry the tradition and the discipline,
which two feeds of the same day were sharing while saying different things;
and Date's Julian Day Number is behind an accessor rather than a public field.
fastLabel, emoji and reason are documented as presentation. The fields are
stable, the wording is not, and freezing three human-facing strings for a
major version was not the intent.
An adversarial review of the release, and four of its findings were things
PyPI never lets you replace once uploaded.
- rust-version said 1.74. clap has needed 1.85 since 4.6, and cargo
hard-errors rather than warning, so the sdist advertised a floor it could
not build on. docs/releasing.md sends macOS and Windows users to that
sdist.
- The wheel was classified Development Status :: 4 - Beta on a release the
changelog calls stable, with none of the Python version classifiers PyPI
indexes on.
- Six README links were relative. PyPI resolves them against the project
page, so every one 404'd there, as they do on the live 0.2.0 page now.
- in that order packs the wheel into the
sdist. The tarball on disk was 431KB with an x86-64 binary inside it.
Also: twine upload gains --skip-existing, so a retry after a partial upload
finishes rather than dying on a version that cannot be reused; twine check
gains the renderer that makes it parse the description at all, without which
it returns None and reports PASSED; and the README no longer claims a
twenty-year sweep the test did not run, because 366 * 21 / 4 is five years.
The test now runs the twenty-one it was named for.
The crates.io name belongs to an unrelated project, which the README now says
rather than leaving a reader to find out from cargo.
Nobody depends on this yet, which makes now the moment to commit to a surface
rather than later when someone does.
docs/versioning.md says what that surface is. A calendar has a wider one than
a library usually does: the JSON shape, the fasting level names and their
order, the jurisdiction keys, the command line, and the two language APIs are
all things a caller can reasonably build on, and only one of them is a
function signature. The text output, the reason strings and the menologion's
wording are explicitly not.
It also names the category semver has no word for. A correction to a fast rule
or a feast rank breaks no interface, so it is a patch; but it changes what the
program tells someone to eat. Those are called out in the changelog under
Calendar whatever the version does, and CHANGELOG.md starts by listing every
one of them against pre-1.0 behaviour.
daysToPascha is documented as signed, counting to the Pascha of that day's own
civil year, which it always was and nothing said.