release: v0.1.1 — patch release with collector reliability fixes#39
Conversation
Three mechanical edits: - pyproject.toml: version "0.1.0" -> "0.1.1" - CHANGELOG.md: insert `## [0.1.1] - 2026-04-26` directly under the (still empty) `## [Unreleased]` header so all 12 PRs' worth of bullets that have been accumulating since v0.1.0 ship are now categorized under the 0.1.1 release. Updated the link refs at the bottom: [Unreleased] now compares from v0.1.1, and a new [0.1.1] entry compares v0.1.0...v0.1.1. - uv.lock: refreshed by `uv lock` so the locked pypi-winnow-downloads version (0.1.1) matches pyproject.toml. What ships in v0.1.1 (highlights — full changelog under ## [0.1.1]): Library fixes (operator-visible): - collector: _write_health OSError no longer escapes per-package isolation. Disk-full / perm errors now produce structured `winnow-collect: ...; health file write failed: [Errno 28] No space left on device` exit instead of a raw traceback. Closes #32. - collector: stale_threshold_days is now actually consulted — the "warn if previous run is older than N days" feature documented in config.example.yaml since v0.1.0 finally fires. Log-only per the documented v1 contract; degrades silently on first-run / unreadable / malformed / future- timestamped previous _health.json. Closes #33. Documentation: - README acknowledgments / license / BigQuery dataset link refresh (PR #15) - README shields.io URL canonicalization (PR #27, closes #16) - deploy/README.md Tailscale Funnel as alternative HTTPS exposure (PR #22) - deploy/README.md "Pick an approach" table updated to reflect the new Caddy logging shape (in PR #30) CI / project infrastructure (no PyPI consumer impact, but hardens future releases): - Community health files: CONTRIBUTING / CoC / SECURITY / issue templates (PR #20) - .github/dependabot.yml across pip + github-actions + docker ecosystems (PR #21) - Dependabot PR hygiene cascade from cmeans/mcp-synology: PULL_REQUEST_TEMPLATE.md + auto-CHANGELOG workflow (App- token authenticated so required CI re-fires on the bot's HEAD SHA) + dependabot.yml prefix fix (PR #25). Validated end-to-end via the first two real Dependabot bumps PR #23 (codecov-action 5->6) and PR #24 (python 3.13-slim -> 3.14-slim). - deploy-smoke CI job that builds the Dockerfile, smokes the entrypoint, validates compose+Caddyfile against caddy:2 (PR #29, closes #7). Promoted to required status check on the main-protection ruleset 2026-04-26 22:43 (issue #31 closed via operator action). - deploy/caddy/Caddyfile.example gains global error logger + per-site access logger with built-in lumberjack rotation, documents the validate-as-root gotcha (PR #30). Live CT 112 deployment fixed in the same change. - 100% coverage on src/ via real tests (no `# pragma: no cover`), with `fail_under = 100` gate in pyproject.toml so future regressions trip CI (PR #38, closes #37). Verified locally: 71/71 pytest pass, ruff/format/mypy clean, coverage gate green at 100.00%. After this merges: 1. Tag the squash-merge commit as v0.1.1 and push the tag — publish.yml fires and uploads to PyPI via the existing trusted-publisher OIDC flow. 2. Update the live CT 112 deployment to install pypi-winnow-downloads==0.1.1 from PyPI (currently runs a wheel built from main, but pinning to the released version keeps deploy reproducible). 3. Close any post-release follow-ups Chris wants tracked.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
cmeans
left a comment
There was a problem hiding this comment.
QA round 1 — clean, signing off
Per CLAUDE.md: "Release PRs do not need QA sections — the code was already tested in feature PRs." So this is a release-mechanics check rather than a re-QA pass.
Mechanical correctness on head aba6522:
| Check | Result |
|---|---|
pyproject.toml version |
0.1.0 → 0.1.1 (single line) |
uv.lock change scope |
exactly two lines (one +/one - on the pypi-winnow-downloads version field). No incidental dep churn — Dev didn't accidentally bump anything else by running uv lock with stale upstreams. |
pypi_winnow_downloads.__version__ after install |
0.1.1 (verified via uv run python -c "import pypi_winnow_downloads; print(pypi_winnow_downloads.__version__)") — confirms pyproject.toml is the single source of truth and the importlib.metadata lookup wires through |
## [Unreleased] after the insertion |
empty (heading immediately followed by ## [0.1.1] - 2026-04-26, no orphaned bullets) |
## [0.1.1] section |
14 bullets across ### Added / ### Changed / ### Fixed — only the canonical Keep-a-Changelog categories (no rule-violating subsections) |
Date 2026-04-26 |
matches today |
| Link refs | [Unreleased]: …compare/v0.1.1...HEAD, [0.1.1]: …compare/v0.1.0...v0.1.1, [0.1.0]: …releases/tag/v0.1.0 — all three resolve to the right targets |
| SemVer fit | patch bump appropriate. Public-API delta vs v0.1.0: CollectorResult.health_write_error: str | None = None (additive, default-None backward-compat); _check_staleness is internal (_-prefixed); everything else is CI/deploy/docs. No breaking changes. |
| Final local sweep | 71/71 pytest, ruff/format/mypy clean |
| CI on PR head | all SUCCESS (test 3.11/3.12/3.13, lint, typecheck, deploy-smoke, qa-approved, on-push) |
Cross-reference of [0.1.1] scope vs PRs merged since v0.1.0:
gh pr list --base main --search "merged:>=2026-04-25" returns 18 merged PRs since the v0.1.0 release PR (#13). Spot-checked each:
- The two operator-visible fixes (#32 / PR #35, #33 / PR #36) — represented under
### Fixed✓ - All deploy/CI/docs/dependabot/coverage work (#15, #16, #20, #21, #22, #23, #24, #25, #27, #29, #30, #37, #38) — represented or explicitly excluded by their own decision (#20, #21 chose to omit per "repo infrastructure, not user-visible product change")
- The release PR body's "CI / project infrastructure" section honestly distinguishes "not in CHANGELOG by design" from "in CHANGELOG"
No orphaned PRs, no missing categories.
Note (not a finding): .github/ISSUE_TEMPLATE/bug_report.yml:14 has placeholder "0.1.0 or abc1234". After v0.1.1 ships, the example version in the placeholder lags by one release. This is placeholder text (clear from the surrounding form), not a claim — analogous to BADGE_HOST=badges.example.com in compose. Users putting their own version follow the format. Bumping it on every release is an indefinite ratchet; could instead refactor to "e.g., 0.1.x or commit SHA" to make it durable. Operator's call, not a release-mechanic blocker.
No findings. Transitioning label to Ready for QA Signoff. Per feedback_no_qa_label, not applying QA Approved — that's the maintainer's act, after which the post-merge tag/push sequence in your PR body fires publish.yml → PyPI.
|
Applying |
Summary
Promotes the project to v0.1.1 — first patch release. Three mechanical edits:
pyproject.toml:version = "0.1.0"→version = "0.1.1"CHANGELOG.md: insert## [0.1.1] - 2026-04-26directly under the (still-empty)## [Unreleased]so all 12 PRs' worth of bullets that have accumulated since v0.1.0 are now categorized under the 0.1.1 release. Updated link refs at the bottom:[Unreleased]now compares fromv0.1.1, and a new[0.1.1]entry comparesv0.1.0...v0.1.1.uv.lock: refreshed byuv lockso the lockedpypi-winnow-downloadsversion (0.1.1) matchespyproject.toml.What ships in v0.1.1
Library fixes (operator-visible, the reason for the patch release):
_write_healthOSErrorno longer escapes per-package isolation (#32)winnow-collect: …; health file write failed: [Errno 28] No space left on deviceexit instead of a raw traceback. NewCollectorResult.health_write_error: str | Nonefield surfaces the failure structurally.stale_threshold_daysis now actually consulted (#33)config.example.yamlsince v0.1.0 finally fires. Log-only per the documented v1 contract; degrades silently on first-run / unreadable / malformed / future-timestamped previous_health.json.Documentation:
deploy/README.mdTailscale Funnel as alternative HTTPS exposure (PR docs(deploy): document Tailscale Funnel as an alternative HTTPS exposure #22)deploy/README.md"Pick an approach" table reflects the new Caddy logging shape (PR deploy(caddy): split error + access logs to rotated files (validates against live CT 112) #30)CI / project infrastructure (no PyPI consumer impact, but hardens future releases):
.github/dependabot.ymlacross pip + github-actions + docker (PR chore: add dependabot.yml (pip / github-actions / docker) #21)deploy-smokeCI job, now a required status check onmain-protection(PR ci: add deploy-smoke job for Dockerfile + Compose + Caddyfile examples (#7) #29, Add Docker image smoke test to CI #7, Promote deploy-smoke to required status check (soak window post-#29) #31)deploy/caddy/Caddyfile.examplegains global error logger + per-site access logger with built-in lumberjack rotation (PR deploy(caddy): split error + access logs to rotated files (validates against live CT 112) #30) — also fixed live on CT 112src/via real tests, withfail_under = 100gate (PR test: 100% coverage on src/ via real tests + fail_under gate (#37) #38, Push coverage from 99% → 100% on src/ #37)Verification
uv run pytest --cov— 71/71 passed, 100% coverage gate greenuv run ruff check src/ tests/— cleanuv run ruff format --check src/ tests/— cleanuv run mypy src/pypi_winnow_downloads/— cleanuv.lockmatchespyproject.toml—pypi-winnow-downloads v0.1.0 -> v0.1.1After this merges
Then:
pypi-winnow-downloads==0.1.1from PyPI (currently runs a wheel built from main; pinning keeps deploy reproducible).Skip TestPyPI this time?
The v0.1.0 release used the
test-v0.1.0→ TestPyPI → verify →v0.1.0→ PyPI sequence to validate the OIDC handshake. v0.1.1 has the same trusted-publisher config and the samepublish.ymlworkflow; if you want belt-and-suspenders, the sametest-v0.1.1step is available, otherwise direct-to-PyPI is reasonable now that the publisher path is known-good. Maintainer call.Closes the v0.1.1 release cycle.