Skip to content

release: v0.1.1 — patch release with collector reliability fixes#39

Merged
cmeans-claude-dev[bot] merged 1 commit into
mainfrom
release/v0.1.1
Apr 27, 2026
Merged

release: v0.1.1 — patch release with collector reliability fixes#39
cmeans-claude-dev[bot] merged 1 commit into
mainfrom
release/v0.1.1

Conversation

@cmeans-claude-dev

@cmeans-claude-dev cmeans-claude-dev Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

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-26 directly 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 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

Library fixes (operator-visible, the reason for the patch release):

collector: _write_health OSError no longer escapes per-package isolation (#32) 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. New CollectorResult.health_write_error: str | None field surfaces the failure structurally.
collector: stale_threshold_days is now actually consulted (#33) 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.

Documentation:

CI / project infrastructure (no PyPI consumer impact, but hardens future releases):

Verification

  • uv run pytest --cov — 71/71 passed, 100% coverage gate green
  • uv run ruff check src/ tests/ — clean
  • uv run ruff format --check src/ tests/ — clean
  • uv run mypy src/pypi_winnow_downloads/ — clean
  • uv.lock matches pyproject.tomlpypi-winnow-downloads v0.1.0 -> v0.1.1
  • CHANGELOG link refs verified by hand: Unreleased compares from v0.1.1, [0.1.1] compares v0.1.0...v0.1.1, [0.1.0] unchanged
  • CI green on all jobs (lint, typecheck, test 3.11/3.12/3.13, deploy-smoke, codecov)

After this merges

# Tag the squash-merge commit and push — publish.yml fires on tag push
# and uploads to PyPI via the existing trusted-publisher OIDC flow.
git tag v0.1.1 <merge-sha>
git push origin v0.1.1

Then:

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 same publish.yml workflow; if you want belt-and-suspenders, the same test-v0.1.1 step 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.

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.
@cmeans-claude-dev cmeans-claude-dev Bot added the Ready for QA Dev work complete — QA can begin review label Apr 27, 2026
@github-actions github-actions Bot added the Awaiting CI Dev complete, waiting for CI/Codecov to pass before QA label Apr 27, 2026
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions github-actions Bot removed the Awaiting CI Dev complete, waiting for CI/Codecov to pass before QA label Apr 27, 2026

@cmeans cmeans left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@cmeans cmeans added QA Active QA is actively reviewing; Dev should not push changes and removed Ready for QA Dev work complete — QA can begin review labels Apr 27, 2026

@cmeans cmeans left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.00.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.

@cmeans

cmeans commented Apr 27, 2026

Copy link
Copy Markdown
Owner

Applying Ready for QA Signoff — see review above. Release-mechanic checks all pass: pyproject.toml + uv.lock minimal version-bump pair (no incidental dep churn), [Unreleased] empty post-insertion, 14 bullets in [0.1.1] across canonical Keep-a-Changelog categories, link refs correct, date matches today, SemVer patch-bump appropriate (no breaking public-API changes; only additive CollectorResult.health_write_error). Local 71/71 + ruff/format/mypy clean, CI all green. One informational note in the review about a stale placeholder in bug_report.yml — operator's call, not blocking. Not applying QA Approved per the standing rule.

@cmeans cmeans added Ready for QA Signoff QA passed — ready for maintainer final review and merge QA Approved Manual QA testing completed and passed and removed QA Active QA is actively reviewing; Dev should not push changes Ready for QA Signoff QA passed — ready for maintainer final review and merge labels Apr 27, 2026
@cmeans-claude-dev cmeans-claude-dev Bot merged commit 1e110f9 into main Apr 27, 2026
40 checks passed
@cmeans-claude-dev cmeans-claude-dev Bot deleted the release/v0.1.1 branch April 27, 2026 04:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

QA Approved Manual QA testing completed and passed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants