release: cut 0.3.0 — the ranking face exists in no published release - #14
Merged
Conversation
`assay.ranking` merged in #13 after the `v0.2.0` tag, so it ships in nothing. PyPI `avow` 0.2.0 has neither the module nor `ir-measures` in its metadata. **Why this is urgent, not a chore.** The first consumer had to pin `avow` to the git merge commit `1c382ce` by full SHA to reach the module. A URL requirement cannot be resolved to a version, so that consumer's dependency audit now skips `avow` entirely — "URL requirements cannot be pinned to a specific package version". A CVE against `avow` or its transitive deps would go unseen for as long as that pin stands. Cutting the release is what closes it: the consumer moves back to `avow[assay]>=0.3.0` and its audit sees the package again. **Why 0.3.0 and not 0.2.1.** Two independent reasons, either sufficient: the unreleased set adds a new public face (`assay.ranking`, `assay.ranking_score`) plus a new runtime dependency, and it carries a BREAKING rename (`ReplayMismatch` -> `PayloadHashMismatch`, `avow.replay_mismatch` -> `avow.payload_hash_mismatch`). This repo bumps the minor for breaking changes in 0.x — that is what 0.2.0 was. The repo had also already committed to the number in prose: `README.md` and `ts/README.md` both say the rename "ships in 0.3.0". **Claim this PR touches:** none directly — no code, no public API, no guard. It makes the version strings and the changelog tell the truth about what is on `main`. **Version lives in three places, all bumped:** - `src/avow/_version.py` — hatchling's single source, read at build time - `ts/package.json` — `@edgeproc/avow`, pair-versioned; a `v*` tag publishes BOTH registries and npm rejects a re-publish at an unchanged version - `CHANGELOG.md` — `[Unreleased]` -> `[0.3.0] - 2026-08-03` `tests/test_packaging.py::test_python_and_typescript_packages_carry_the_same_version` is the guard that makes the npm half non-optional: bumping `_version.py` alone turns the gate red. **Changelog correction.** The `[Unreleased]` entry claimed the ranking arithmetic was scikit-learn's. It is not, and has not been since the engine swap: it is `trec_eval`'s, reached through `ir_measures` — the reference implementation the IR field validates its own numbers against. The entry now records why, because the reasoning is the reusable part: `ndcg_score` and `label_ranking_average_precision_score` are multilabel-CLASSIFICATION metrics with no notion of a relevant document that was never retrieved, so both had to be talked into retrieval semantics by hand — nDCG by padding empty positions, average precision by rescaling LRAP by |relevant retrieved| / |relevant|, without which retrieving 1 of 4 relevant documents scored 1.0. Two hand-written semantic corrections around a mismatched engine, both now deleted. The adapter code was the tell, not the fix. Maturity was never the question. **Evidence:** - `uv run poe gate` -> exit 0; 184 passed; 100% statement AND branch coverage (803 stmts, 68 branches, none missed) against a 90% floor - `cd ts && pnpm gate` -> exit 0; 40 tests, 2 files (biome, tsc, vitest, build) - Built artifact, which is the actual claim: `avow-0.3.0-py3-none-any.whl` carries `Version: 0.3.0`, `Requires-Dist: ir-measures>=0.4.3; extra == 'assay'`, and `assay/ranking.py`. Base install is unchanged — still the envelope only, so `pip install avow` and micropip in Pyodide do not pull the scientific stack. **Not in this PR (human gates):** no tag, no GitHub release. `git tag v0.3.0 && git push origin v0.3.0` is what fires `publish.yml`. A green publish job is not evidence — verify the registries actually serve it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015o7tjWLFZvzRv4KyNfDukx
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why this is urgent, not a chore
assay.rankingmerged in #13 after thev0.2.0tag, so it ships in no published release. PyPIavow0.2.0 has neither the module norir-measuresin its metadata.The consequence is a live supply-chain hole. The first consumer had to pin
avowto the git merge commit1c382ceby full SHA to reach the module. A URL requirement cannot be resolved to a version, so that consumer's dependency audit now skipsavowentirely — "URL requirements cannot be pinned to a specific package version." A CVE againstavowor its transitive dependencies would go unseen for as long as that pin stands.Cutting the release closes it: the consumer moves back to a PyPI range,
avow[assay]>=0.3.0, and its audit sees the package again.A trap worth naming: the git checkout of
1c382cereports version0.2.0— the same string as the published artifact that does not contain this code. Version strings were never the identity here.Why 0.3.0, not 0.2.1
Two independent reasons, either sufficient on its own:
assay.rankingandassay.ranking_scoreare new API;ir-measuresis a new runtime dep. That is a feature, not a patch.ReplayMismatch→PayloadHashMismatch, and the code stringavow.replay_mismatch→avow.payload_hash_mismatch. This repo bumps the minor for breaking changes in 0.x — that is exactly what 0.2.0 was ("a breaking release that makes three trust claims literally true").The repo had also already committed to the number in prose:
README.md:690says the rename "ships in 0.3.0", andts/README.md:57says "renamed in 0.3.0".0.2.1would have contradicted both.Every place the version lives — all three bumped
src/avow/_version.pyavow.__version__cannot driftts/package.json@edgeproc/avow, pair-versioned. Av*tag publishes PyPI and npm; npm rejects a re-publish at an unchanged versionCHANGELOG.md[Unreleased]→[0.3.0] - 2026-08-03The npm half is not optional, and it is not a judgement call —
tests/test_packaging.py::test_python_and_typescript_packages_carry_the_same_versionassertsts/package.jsonversion== avow.__version__. Bumping_version.pyalone turns the gate red.publish.ymlstates the same thing in its header: "A tag push that re-runs this workflow at an unchanged version will be REJECTED by both registries. Bump the version before tagging."Changelog correction: the entry named the wrong engine
The
[Unreleased]entry claimed the ranking arithmetic was scikit-learn's. It is not, and has not been since the engine swap — it istrec_eval's, reached throughir_measures, the reference implementation the IR field validates its own numbers against.The entry now records why, because the reasoning is the reusable part:
The adapter code was the tell, not the fix. Maturity was never the question — scikit-learn is impeccably mature and was still the wrong engine for this field. It stays in the
assayextra, becausemetrics.pystill uses it for the classification metrics it is actually right for.How
ir-measuresis declaredUnder the
assayextra, not the base install:That is correct and unchanged by this PR — it landed with #13. The base install stays the envelope only (pydantic, pydantic-settings, pynacl, rfc8785) so
pip install avowand micropip in Pyodide never pull the scientific stack.ir-measurescarries exactly one transitive dependency,pytrec-eval-terrier(the C++ binding to trec_eval itself), whose own deps are numpy + scipy — already pinned in the same extra.Claim this PR touches
None directly — no code, no public API, no guard. It makes the version strings and the changelog tell the truth about what is on
main. The guard that protects this change is the packaging parity test, and it is pre-existing and green.Evidence
uv run poe gate→ exit 0; ruff → ruff-format → mypy--strict→ xenon A → pytestcd ts && pnpm gate→ exit 0; 40 tests in 2 files (biome → tsc--noEmit→ vitest → build)avow-0.3.0-py3-none-any.whl→Version: 0.3.0,Requires-Dist: ir-measures>=0.4.3; extra == 'assay', andassay/ranking.pypresent in the wheelRequires-Distoutside the extras is still pydantic / pydantic-settings / pynacl / rfc8785 onlyThe wheel metadata is the load-bearing one — it is precisely what PyPI
avow0.2.0 lacks and what makes the consumer's audit work again.Not in this PR — human gates
No tag and no GitHub release.
git tag v0.3.0 && git push origin v0.3.0is what firespublish.yml.After merge, and remembering that a green publish job is not evidence:
pip index versions avow,npm view @edgeproc/avow@0.3.0), not the workflow conclusion;npm view @edgeproc/avow@0.3.0 dist.attestations --jsonfor an actual value — it prints empty and exits 0 when provenance is missing, so an exit-code check proves nothing;avow[assay]>=0.3.0and confirm its audit stops skipping the package.🤖 Generated with Claude Code
https://claude.ai/code/session_015o7tjWLFZvzRv4KyNfDukx