Skip to content
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- **`.github/workflows/uv-lock-refresh.yml`** new scheduled workflow runs `uv lock --upgrade` every Thursday 12:00 UTC as a backstop for transitive dependency freshness — picks up minor/patch bumps that Dependabot's advisory- and cascade-driven flow hasn't yet surfaced. Skip-gate defers the run if a `dependencies` + `python`-labeled PR is already open (Dependabot mid-cycle or prior cron PR pending QA), so PRs don't overlap. Test gate (`uv sync --frozen --extra dev && uv run pytest`) blocks PR creation if the new lockfile breaks the suite. PR is opened via the existing `cmeans-claude-dev[bot]` App token (same path as `dependabot-changelog.yml`) so downstream CI checks (lint, typecheck, test, deploy-smoke) fire on the bot's push and don't leave the merge gate stuck. Most weeks: no PR (Dependabot already covered transitives via cascade). Spec: `docs/superpowers/specs/2026-04-29-uv-lock-refresh-cron-design.md`.

- **Per-OS badge files (v3 OS distribution feature).** The collector now emits three additional shields.io endpoint badge JSON files per package per window: `os-linux-<N>d-non-ci.json`, `os-macos-<N>d-non-ci.json`, `os-windows-<N>d-non-ci.json`. The badge label format mirrors v2's parameterized `(Nd)` style — e.g., `linux (30d)`, `macos (30d)`, `windows (30d)`. Color logic (`blue` if count ≥ 10 else `lightgrey`) is unchanged. Pypinfo group-by extends from `ci installer` to `ci installer system` so a single BigQuery call returns both per-installer and per-system breakdowns; BigQuery cost is unchanged (same source table, marginal column). `run_pypinfo()`'s return type changes from `dict[str, int]` to a TypedDict carrying `by_installer` and `by_system` aggregates. `_health.json` per-package successful entries gain a `counts_by_system` field. `PackageOutcome` gains a `counts_by_system` attribute. Filename slug and badge label use `macos` (user-friendly); the internal allowlist key is `Darwin` to match pypinfo's raw emission. No `pyproject.toml` range changes. The v0.2.0 hero-stability invariant is preserved: hero count remains `sum(by_installer.values())` regardless of system_name; per-system aggregation applies an independent allowlist filter so rows with missing or non-allowlisted system_name drop out of the per-OS aggregates but still count toward the hero. Backwards-compat: `downloads-<N>d-non-ci.json` and the seven `installer-*` files unchanged in filename, schema, and value for any given pypinfo response. README dogfood blocks gain a "By OS" paragraph parallel to the existing "By installer" paragraph; "What these badges actually count" gains a "By OS breakdown" paragraph; "Use this service for your own package" table grows three rows. Spec: `docs/superpowers/specs/2026-04-29-os-distribution-badge-design.md`.

### Changed

- **`.gitignore`** ignores a private operator-tooling directory `.deploy/` at the repo root so maintainer-specific deploy scripts and design docs stay out of public history. The directory holds tooling like `update-collector.sh` (drives the CT 112 deployment via `WINNOW_REMOTE_RUN`) plus matching design / plan documents — parameterized in principle but maintainer-shaped in practice (SSH-to-Holodeck, `pct exec`, journald awareness). Other self-hosters can use plain `uv pip install --upgrade pypi-winnow-downloads`; this tooling does not need a public contract or maintenance burden. Rule is unanchored (`.deploy/`) to match the convention of the rest of the file (`.venv/`, `dist/`, `__pycache__/` etc. are all unanchored). Internal-only; no user-facing behavior change.
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ any existing alternative for small or young Python packages.
[![poetry downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2Fpypi-winnow-downloads%2Finstaller-poetry-30d-non-ci.json)](https://pypi.org/project/pypi-winnow-downloads/)
[![pdm downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2Fpypi-winnow-downloads%2Finstaller-pdm-30d-non-ci.json)](https://pypi.org/project/pypi-winnow-downloads/)

**By OS** (30d, non-CI):

[![linux downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2Fpypi-winnow-downloads%2Fos-linux-30d-non-ci.json)](https://pypi.org/project/pypi-winnow-downloads/)
[![macos downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2Fpypi-winnow-downloads%2Fos-macos-30d-non-ci.json)](https://pypi.org/project/pypi-winnow-downloads/)
[![windows downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fpypi-badges.intfar.com%2Fpypi-winnow-downloads%2Fos-windows-30d-non-ci.json)](https://pypi.org/project/pypi-winnow-downloads/)

## What these badges actually count

The hero badge — labelled `pip*/uv/poetry/pdm (Nd)` (N=30 in the reference
Expand Down Expand Up @@ -67,6 +73,8 @@ Useful for spotting installer-mix shifts (e.g., uv overtaking pip on a young
package). See [Use this service for your own package](#use-this-service-for-your-own-package)
below for the per-installer URL pattern.

**By OS breakdown.** Each per-OS badge applies the same `details.ci != True` filter as the hero — they answer "non-CI downloads on that OS." `Darwin` is pypinfo's emission for what users call macOS; the badge filename and label use `macos`. The per-OS sum can be less than the hero count: rows whose user-agent didn't expose a system_name (or exposed one outside Linux/Darwin/Windows) drop out of the per-OS aggregation but still count toward the hero — same pattern as the per-installer-sum ≤ hero gap.

## Install

```bash
Expand Down Expand Up @@ -121,6 +129,9 @@ JSON files per configured package per window, all under
| `installer-poetry-30d-non-ci.json` | `poetry (30d)` | `poetry` only |
| `installer-pdm-30d-non-ci.json` | `pdm (30d)` | `pdm` only |
| `installer-pip-family-30d-non-ci.json` | `pip* (30d)` | `pip + pipenv + pipx` aggregate |
| `os-linux-30d-non-ci.json` | `linux (30d)` | Per-OS, Linux |
| `os-macos-30d-non-ci.json` | `macos (30d)` | Per-OS, macOS (Darwin) |
| `os-windows-30d-non-ci.json` | `windows (30d)` | Per-OS, Windows |

All files exclude CI traffic (BigQuery's `details.ci != True`). Each is a
[shields.io endpoint badge](https://shields.io/badges/endpoint-badge) JSON.
Expand Down
Loading