Ctrl K
ComunidadGuías…

scripts/check-toolchain-freshness.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
#!/usr/bin/env python3
"""Fail while a declared or pinned toolchain version is EOL, or has fallen out of the N-1 band.

``pnpm audit`` and ``pip-audit`` see published *packages*. They are blind to the
toolchain binaries FlintTrade pins itself - the Node runtime and pnpm release the
desktop bootstrap downloads, the uv build that provisions Python, and the floors
and targets ``flint.toml`` declares. Those go stale silently: nothing in CI
noticed that the pinned Node release key had expired, and nothing today notices
when a pinned runtime line reaches end of life.

This check reads ``flint.toml`` as the source of truth and compares every version
it finds against upstream release data:

* ``https://nodejs.org/dist/index.json``               - every published Node release
* ``.../nodejs/Release/main/schedule.json``            - the Node LTS/EOL calendar
* ``https://registry.npmjs.org/-/package/pnpm/dist-tags`` - the pnpm release tags
* ``https://api.github.com/repos/astral-sh/uv/releases/latest`` - the current uv
* ``https://api.github.com/repos/ollama/ollama/releases/latest`` - the current stable Ollama
* ``https://endoflife.date/api/python.json``           - the CPython EOL calendar

Two severities, and the distinction mirrors the one ``flint.toml`` itself draws:

**Floors** (``python_requires``, ``node_requires``) are set by what the dependency
tree genuinely needs, so they are judged on end of life alone. A floor that trails
the newest release is correct behaviour, not drift.

**Targets and pins** (``python_target``, ``node_target``, the bootstrap
``tool-manifest.json`` entries, ``packageManager``) are meant to track current
stable, so they fail when the line is EOL *or* has slipped further back than one
release line (the N-1 band). Being behind on the patch inside an in-band line is a
warning, because a pin like Node's travels with a mirrored signing key and cannot
move on its own.

For Node, released and supported Current lines count alongside LTS lines inside
the same N-1 band. A scheduled future line or prerelease does not count. Floors
still follow end of life only; choosing a Current target does not raise them.

The managed Ollama pin (``_OLLAMA_VERSION`` in ``ollama_runtime.py``) is advisory
only: it carries per-platform hashes that are regenerated by hand, so falling more
than ``_OLLAMA_MINOR_LINES_BEHIND_WARN`` minor versions behind the latest stable
release is a warning and never a failure.

Network failures never fail the run: each source is fetched independently and a
source that cannot be reached is reported as skipped. A blip upstream must not
redden an unrelated pull request::

    python scripts/check-toolchain-freshness.py
    python scripts/check-toolchain-freshness.py --offline   # parse the pins, fetch nothing
    python scripts/check-toolchain-freshness.py --json      # machine-readable findings
"""

from __future__ import annotations

import argparse
import dataclasses
import datetime as dt
import json
import pathlib
import re
import sys
import tomllib
import urllib.error
import urllib.request
from typing import Any

_REPO_ROOT = pathlib.Path(__file__).resolve().parents[1]
_FLINT_TOML = _REPO_ROOT / "flint.toml"
_TOOL_MANIFEST = _REPO_ROOT / "packages/apps/desktop/resources/bootstrap/tool-manifest.json"
_ROOT_PACKAGE_JSON = _REPO_ROOT / "package.json"
_OLLAMA_RUNTIME = _REPO_ROOT / "packages/core/core/src/flinttrade_core/ollama_runtime.py"

_NODE_DIST_URL = "https://nodejs.org/dist/index.json"
_NODE_SCHEDULE_URL = "https://raw.githubusercontent.com/nodejs/Release/main/schedule.json"
_PNPM_DIST_TAGS_URL = "https://registry.npmjs.org/-/package/pnpm/dist-tags"
_UV_LATEST_RELEASE_URL = "https://api.github.com/repos/astral-sh/uv/releases/latest"
_PYTHON_CYCLES_URL = "https://endoflife.date/api/python.json"
# ``/releases/latest`` never returns a draft or a pre-release, so it is the stable channel.
_OLLAMA_LATEST_RELEASE_URL = "https://api.github.com/repos/ollama/ollama/releases/latest"

_FETCH_TIMEOUT_SECONDS = 20
# The npm registry and the GitHub API both want a User-Agent; the default
# urllib one is rejected by some CDN edges.
_USER_AGENT = "flinttrade-toolchain-freshness/1 (+https://github.com/navaneeshnagarajan/FlintTrade)"

# How many release lines back from current still counts as supported here. 1 means
# "the newest line and the one before it" - the N-1 band.
_LINES_BACK_ALLOWED = 1

# The managed Ollama pin is warn-only. Ollama is pre-1.0, so its release line is the
# minor; warn once the pin trails the latest stable release by more than this many.
_OLLAMA_MINOR_LINES_BEHIND_WARN = 2
_OLLAMA_PIN_PATTERN = re.compile(
    r'^_OLLAMA_VERSION(?:\s*:\s*[^=\n]+)?\s*=\s*"(?P<version>v\d+\.\d+\.\d+)"\s*$',
    re.MULTILINE,
)


@dataclasses.dataclass(frozen=True)
class Waiver:
    """A knowingly-out-of-band pin, with a date the waiver stops working.

    Attributes:
        subject: The subject string the finding is raised against.
        reason: Why the pin cannot move yet, in one sentence.
        review_by: ISO date after which the waiver expires and the finding fails.
    """

    subject: str
    reason: str
    review_by: str


# Waivers are deliberately dated. An undated suppression is indistinguishable
# from a bug, so every entry expires and the finding turns fatal again on its own.
#
# Empty on purpose. The previous entry covered the pnpm 9 to 11 migration and
# expired on 2026-10-31. That migration has landed: the pin is pnpm 12, the
# current release line, so the out-of-band finding no longer applies. A patch
# behind ``latest-12`` stays a warning. Add a Waiver only for a pin that is
# knowingly outside the N-1 band, with a future ``review_by`` and a reason
# that says why an upgrade cannot land yet.
_WAIVERS: tuple[Waiver, ...] = ()


@dataclasses.dataclass(frozen=True)
class Finding:
    """One thing this check has to say about a version.

    Attributes:
        level: ``fail``, ``warn`` or ``note``.
        subject: What the finding is about, e.g. ``node_target (flint.toml)``.
        message: The operator-facing explanation.
    """

    level: str
    subject: str
    message: str


class Report:
    """Collected findings plus the sources that could not be reached."""

    def __init__(self) -> None:
        self.findings: list[Finding] = []
        self.skipped: list[str] = []

    def add(self, level: str, subject: str, message: str) -> None:
        """Record a finding, applying any live waiver.

        Args:
            level: ``fail``, ``warn`` or ``note``.
            subject: What the finding is about.
            message: The operator-facing explanation.
        """
        if level == "fail":
            waiver = _live_waiver(subject)
            if waiver is not None:
                self.findings.append(
                    Finding(
                        "warn",
                        subject,
                        f"{message} WAIVED until {waiver.review_by}: {waiver.reason}.",
                    )
                )
                return
        self.findings.append(Finding(level, subject, message))

    def skip(self, source: str, error: str) -> None:
        """Record an unreachable data source.

        Args:
            source: The URL that could not be read.
            error: The failure text.
        """
        self.skipped.append(f"{source} ({error})")

    @property
    def failed(self) -> bool:
        """Whether any finding is fatal."""
        return any(finding.level == "fail" for finding in self.findings)


def _live_waiver(subject: str) -> Waiver | None:
    """Return the unexpired waiver covering *subject*, if any.

    Args:
        subject: The finding subject.

    Returns:
        The waiver, or ``None`` when there is none or it has expired.
    """
    today = dt.date.today()
    for waiver in _WAIVERS:
        if waiver.subject != subject:
            continue
        if dt.date.fromisoformat(waiver.review_by) >= today:
            return waiver
    return None


def _fetch_json(url: str, report: Report) -> Any | None:
    """Fetch and parse JSON, recording a skip rather than raising.

    Args:
        url: The source to read.
        report: The report that records unreachable sources.

    Returns:
        The parsed document, or ``None`` when the source could not be read.
    """
    request = urllib.request.Request(url, headers={"User-Agent": _USER_AGENT, "Accept": "application/json"})
    try:
        with urllib.request.urlopen(request, timeout=_FETCH_TIMEOUT_SECONDS) as response:
            return json.loads(response.read().decode("utf-8"))
    except (urllib.error.URLError, TimeoutError, ValueError, OSError) as error:
        report.skip(url, str(error))
        return None


def _requirements() -> dict[str, str]:
    """Return ``flint.toml``'s ``[requirements]`` table.

    Returns:
        The declared floors and targets.
    """
    with _FLINT_TOML.open("rb") as handle:
        return {key: str(value) for key, value in tomllib.load(handle)["requirements"].items()}


def _major(version: str) -> int:
    """Return the leading integer of a version or range string.

    Args:
        version: A value such as ``">=22.22.0"``, ``"24"`` or ``"v22.23.2"``.

    Returns:
        The major component.

    Raises:
        ValueError: When no leading integer can be found.
    """
    match = re.search(r"(\d+)", version)
    if match is None:
        raise ValueError(f"no version number in {version!r}")
    return int(match.group(1))


def _version_tuple(version: str) -> tuple[int, ...]:
    """Return a comparable tuple for a dotted version.

    Args:
        version: A dotted version, optionally ``v``-prefixed.

    Returns:
        The numeric components.
    """
    return tuple(int(part) for part in re.findall(r"\d+", version.lstrip("v")))


def _parse_schedule_date(value: str | None) -> dt.date | None:
    """Parse a Node schedule date, tolerating the ``YYYY-MM`` form.

    Args:
        value: The raw date field, if present.

    Returns:
        The date, or ``None`` when absent or unparseable.
    """
    if not value:
        return None
    for pattern in ("%Y-%m-%d", "%Y-%m"):
        try:
            return dt.datetime.strptime(value, pattern).date()
        except ValueError:
            continue
    return None


def _band_message(subject: str, line: object, allowed: list[str]) -> str:
    """Render the standard out-of-band explanation.

    Args:
        subject: What is out of band.
        line: The release line the subject sits on.
        allowed: The lines inside the N-1 band, newest first.

    Returns:
        The message text.
    """
    rendered = ", ".join(allowed)
    return (
        f"{subject} sits on line {line}, which is further back than N-1. "
        f"Supported lines today are {rendered}. Move the target/pin forward, or widen the band deliberately."
    )


def _check_node(report: Report, requirements: dict[str, str], pinned_node: str | None) -> None:
    """Check the Node floor, target and bootstrap pin against upstream release data.

    Args:
        report: The report to record findings on.
        requirements: ``flint.toml``'s ``[requirements]`` table.
        pinned_node: The bootstrap ``tool-manifest.json`` Node version, if readable.
    """
    schedule = _fetch_json(_NODE_SCHEDULE_URL, report)
    releases = _fetch_json(_NODE_DIST_URL, report)
    if not isinstance(schedule, dict):
        return

    today = dt.date.today()
    lifecycles: dict[int, dict[str, dt.date | None]] = {}
    for raw_line, entry in schedule.items():
        if not isinstance(entry, dict):
            continue
        try:
            major = _major(raw_line)
        except ValueError:
            continue
        lifecycles[major] = {
            "start": _parse_schedule_date(entry.get("start")),
            "lts": _parse_schedule_date(entry.get("lts")),
            "maintenance": _parse_schedule_date(entry.get("maintenance")),
            "end": _parse_schedule_date(entry.get("end")),
        }

    # Current is stable before it enters LTS. Count it only after both its
    # scheduled start and an actual stable publication, never from the future
    # LTS date alone. Keep the same two-line N-1 band, not LTS plus an exception.
    published_lines = (
        {
            _major(entry["version"])
            for entry in releases
            if isinstance(entry, dict)
            and isinstance(entry.get("version"), str)
            and re.fullmatch(r"v\d+\.\d+\.\d+", entry["version"])
            and (published := _parse_schedule_date(entry.get("date"))) is not None
            and published <= today
        }
        if isinstance(releases, list)
        else set()
    )
    supported_lines = sorted(
        major
        for major, dates in lifecycles.items()
        if (dates["end"] is None or dates["end"] > today)
        and (
            (dates["lts"] is not None and dates["lts"] <= today)
            or (dates["start"] is not None and dates["start"] <= today and major in published_lines)
        )
    )
    band = supported_lines[-(_LINES_BACK_ALLOWED + 1) :]

    def report_unavailable(subject: str, major: int) -> bool:
        if major not in lifecycles:
            report.add("fail", subject, f"Node {major} is not in the upstream release schedule.")
            return True
        dates = lifecycles[major]
        if dates["start"] is not None and dates["start"] > today:
            report.add("fail", subject, f"Node {major} is not yet released (starts {dates['start']}).")
            return True
        if report_eol(subject, major):
            return True
        if dates["lts"] is None or dates["lts"] > today:
            if not isinstance(releases, list):
                report.skip(_NODE_DIST_URL, f"cannot establish publication of Current Node {major}")
                return True
            if dates["start"] is None or major not in published_lines:
                report.add("fail", subject, f"Node {major} has no published stable release as of {today}.")
                return True
        return False

    def end_of_life(major: int) -> dt.date | None:
        return lifecycles.get(major, {}).get("end")

    def report_eol(subject: str, major: int) -> bool:
        end = end_of_life(major)
        if end is not None and end <= today:
            report.add("fail", subject, f"Node {major} reached end of life on {end:%Y-%m-%d}.")
            return True
        if major not in lifecycles:
            report.add("warn", subject, f"Node {major} is not in the upstream release schedule.")
            return True
        return False

    floor_major = _major(requirements["node_requires"])
    if not report_eol("node_requires (flint.toml)", floor_major):
        dates = lifecycles[floor_major]
        maintenance = dates["maintenance"]
        end = dates["end"]
        phase = "maintenance" if maintenance is not None and maintenance <= today else "active"
        report.add(
            "note",
            "node_requires (flint.toml)",
            f"Node {floor_major} floor is in {phase} support"
            + (f" until {end:%Y-%m-%d}" if end is not None else "")
            + ". A floor is judged on end of life only - it tracks what the dependency tree needs.",
        )

    target_major = _major(requirements["node_target"])
    if not report_unavailable("node_target (flint.toml)", target_major) and band and target_major not in band:
        report.add(
            "fail",
            "node_target (flint.toml)",
            _band_message(f"Node target {target_major}", target_major, [str(item) for item in band[::-1]]),
        )

    if pinned_node is None:
        return

    pinned_major = _major(pinned_node)
    subject = "node (bootstrap tool-manifest.json)"
    if report_unavailable(subject, pinned_major):
        return
    if band and pinned_major not in band:
        report.add(
            "fail",
            subject,
            _band_message(f"The pinned Node {pinned_node}", pinned_major, [str(item) for item in band[::-1]]),
        )
        return
    if not isinstance(releases, list):
        return
    line_releases = [
        entry["version"]
        for entry in releases
        if isinstance(entry, dict)
        and isinstance(entry.get("version"), str)
        and re.fullmatch(r"v\d+\.\d+\.\d+", entry["version"])
        and (
            # Preserve established LTS index handling, but a Current pin must
            # carry its own publication date, not borrow another pin's evidence.
            (
                entry.get("date") is None
                and (lts := lifecycles[pinned_major]["lts"]) is not None
                and lts <= today
            )
            or ((published := _parse_schedule_date(entry.get("date"))) is not None and published <= today)
        )
        and _major(entry["version"]) == pinned_major
    ]
    if not re.fullmatch(r"\d+\.\d+\.\d+", pinned_node) or f"v{pinned_node}" not in line_releases:
        report.add("fail", subject, f"Node {pinned_node} is not a published stable release as of {today}.")
        return
    newest = max(line_releases, key=_version_tuple)
    if _version_tuple(newest) > _version_tuple(pinned_node):
        report.add(
            "warn",
            subject,
            f"The bootstrap pins Node {pinned_node} but {newest.lstrip('v')} is the newest {pinned_major}.x release. "
            "Regenerate the manifest (the mirrored signing key travels with the version, so this is never a "
            "hand edit).",
        )


def _check_pnpm(report: Report, pinned_pnpm: str | None, package_manager: str | None) -> None:
    """Check the pnpm pin against the registry's release tags.

    Args:
        report: The report to record findings on.
        pinned_pnpm: The bootstrap ``tool-manifest.json`` pnpm version, if readable.
        package_manager: The root ``packageManager`` field, if readable.
    """
    if pinned_pnpm is None:
        return
    if package_manager is not None and not package_manager.startswith(f"pnpm@{pinned_pnpm}+"):
        report.add(
            "fail",
            "pnpm (bootstrap pin vs packageManager)",
            f"packageManager is {package_manager!r} but the bootstrap manifest pins pnpm {pinned_pnpm}. "
            "The desktop bootstrap enables the same pnpm the repo does, so the two must agree.",
        )

    subject = "pnpm (release line)"
    tags = _fetch_json(_PNPM_DIST_TAGS_URL, report)
    if not isinstance(tags, dict):
        return
    latest = tags.get("latest")
    if not isinstance(latest, str):
        return
    latest_major = _major(latest)
    pinned_major = _major(pinned_pnpm)
    band = list(range(latest_major - _LINES_BACK_ALLOWED, latest_major + 1))
    if pinned_major not in band:
        report.add(
            "fail",
            subject,
            _band_message(f"pnpm {pinned_pnpm}", pinned_major, [str(item) for item in band[::-1]]),
        )
        return
    newest_in_line = tags.get(f"latest-{pinned_major}")
    if isinstance(newest_in_line, str) and _version_tuple(newest_in_line) > _version_tuple(pinned_pnpm):
        report.add(
            "warn",
            subject,
            f"pnpm {pinned_pnpm} is pinned but {newest_in_line} is the newest {pinned_major}.x release.",
        )


def _check_uv(report: Report, pinned_uv: str | None) -> None:
    """Check the uv pin against the newest published release.

    Args:
        report: The report to record findings on.
        pinned_uv: The bootstrap ``tool-manifest.json`` uv version, if readable.
    """
    if pinned_uv is None:
        return
    subject = "uv (bootstrap tool-manifest.json)"
    release = _fetch_json(_UV_LATEST_RELEASE_URL, report)
    if not isinstance(release, dict):
        return
    tag = release.get("tag_name")
    if not isinstance(tag, str):
        return
    latest = _version_tuple(tag)
    pinned = _version_tuple(pinned_uv)
    if not latest or not pinned:
        return
    # uv is pre-1.0, so its release *line* is the minor, not the major.
    line_index = 1 if latest[0] == 0 else 0
    if pinned[:line_index] != latest[:line_index]:
        report.add("fail", subject, _band_message(f"uv {pinned_uv}", pinned_uv, [tag.lstrip("v")]))
        return
    lines_back = latest[line_index] - pinned[line_index]
    if lines_back > _LINES_BACK_ALLOWED:
        report.add("fail", subject, _band_message(f"uv {pinned_uv}", pinned_uv, [tag.lstrip("v")]))
        return
    if pinned < latest:
        report.add("warn", subject, f"uv {pinned_uv} is pinned but {tag.lstrip('v')} is the newest release.")


def _check_python(report: Report, requirements: dict[str, str]) -> None:
    """Check the Python floor and target against the CPython EOL calendar.

    Args:
        report: The report to record findings on.
        requirements: ``flint.toml``'s ``[requirements]`` table.
    """
    cycles = _fetch_json(_PYTHON_CYCLES_URL, report)
    if not isinstance(cycles, list):
        return
    lifecycles: dict[tuple[int, ...], dt.date | None] = {}
    for entry in cycles:
        if not isinstance(entry, dict) or not isinstance(entry.get("cycle"), str):
            continue
        lifecycles[_version_tuple(entry["cycle"])] = _parse_schedule_date(
            entry["eol"] if isinstance(entry.get("eol"), str) else None
        )
    if not lifecycles:
        return

    today = dt.date.today()
    live = sorted(cycle for cycle, eol in lifecycles.items() if eol is None or eol > today)
    band = live[-(_LINES_BACK_ALLOWED + 1) :]

    def report_eol(subject: str, cycle: tuple[int, ...]) -> bool:
        eol = lifecycles.get(cycle)
        if eol is not None and eol <= today:
            rendered = ".".join(str(part) for part in cycle)
            report.add("fail", subject, f"Python {rendered} reached end of life on {eol:%Y-%m-%d}.")
            return True
        return False

    floor = _version_tuple(requirements["python_requires"])[:2]
    if not report_eol("python_requires (flint.toml)", floor) and floor in lifecycles:
        eol = lifecycles[floor]
        report.add(
            "note",
            "python_requires (flint.toml)",
            f"Python {'.'.join(str(part) for part in floor)} floor is supported"
            + (f" until {eol:%Y-%m-%d}" if eol is not None else "")
            + ". A floor is judged on end of life only.",
        )

    target = _version_tuple(requirements["python_target"])[:2]
    if not report_eol("python_target (flint.toml)", target) and band and target not in band:
        rendered = [".".join(str(part) for part in cycle) for cycle in band[::-1]]
        report.add(
            "fail",
            "python_target (flint.toml)",
            _band_message(f"Python target {'.'.join(str(part) for part in target)}", target, rendered),
        )


def _local_pins(report: Report) -> tuple[str | None, str | None, str | None, str | None]:
    """Read the pins this repo controls.

    Args:
        report: The report to record parse failures on.

    Returns:
        The bootstrap Node, pnpm and uv versions plus the root ``packageManager``.
    """
    node = pnpm = uv = package_manager = None
    try:
        manifest = json.loads(_TOOL_MANIFEST.read_text(encoding="utf-8"))
        node = str(manifest["node"]["version"])
        pnpm = str(manifest["pnpm"]["version"])
        uv = str(manifest["uv"]["version"])
    except (OSError, KeyError, ValueError) as error:
        report.add("fail", "bootstrap tool-manifest.json", f"could not read the pinned versions: {error}")
    try:
        package_manager = str(json.loads(_ROOT_PACKAGE_JSON.read_text(encoding="utf-8"))["packageManager"])
    except (OSError, KeyError, ValueError) as error:
        report.add("fail", "package.json", f"could not read packageManager: {error}")
    return node, pnpm, uv, package_manager


def _ollama_pin(report: Report) -> str | None:
    """Read the managed Ollama pin from the runtime module, as it is on this checkout.

    Args:
        report: The report to record parse failures on.

    Returns:
        The pinned version (for example ``v0.32.0``), or ``None`` when unreadable.
    """
    try:
        text = _OLLAMA_RUNTIME.read_text(encoding="utf-8")
    except OSError as error:
        report.add("fail", "ollama_runtime.py", f"could not read the managed Ollama pin: {error}")
        return None
    match = _OLLAMA_PIN_PATTERN.search(text)
    if match is None:
        report.add(
            "fail",
            "ollama_runtime.py",
            'could not find a literal `_OLLAMA_VERSION = "vX.Y.Z"` assignment. '
            "Renovate's regex manager and this check both read that constant, so keep it a plain string literal.",
        )
        return None
    return match.group("version")


def _check_ollama(report: Report, pinned_ollama: str | None) -> None:
    """Warn when the managed Ollama pin trails the latest stable release.

    This never fails: the pin carries per-platform hashes that are regenerated by
    hand, so being behind is a work order, not a broken build.

    Args:
        report: The report to record findings on.
        pinned_ollama: The ``_OLLAMA_VERSION`` pin, if readable.
    """
    if pinned_ollama is None:
        return
    subject = "ollama (managed runtime pin)"
    release = _fetch_json(_OLLAMA_LATEST_RELEASE_URL, report)
    if not isinstance(release, dict) or release.get("prerelease") is True or release.get("draft") is True:
        return
    tag = release.get("tag_name")
    if not isinstance(tag, str):
        return
    latest = _version_tuple(tag)
    pinned = _version_tuple(pinned_ollama)
    if len(latest) < 2 or len(pinned) < 2:
        return
    # Ollama is pre-1.0, so its release line is the minor. A major move counts as out of range.
    if pinned[0] < latest[0]:
        lines_back = None
    elif pinned[0] > latest[0]:
        return
    else:
        lines_back = latest[1] - pinned[1]
    if lines_back is None or lines_back > _OLLAMA_MINOR_LINES_BEHIND_WARN:
        behind = "a newer major version" if lines_back is None else f"{lines_back} minor versions"
        report.add(
            "warn",
            subject,
            f"The managed runtime pins Ollama {pinned_ollama} but the latest stable release is {tag} "
            f"({behind} ahead; warning beyond {_OLLAMA_MINOR_LINES_BEHIND_WARN}). "
            "The per-platform hashes in ollama_runtime.py are regenerated by hand, never bumped in place.",
        )


def _render(report: Report, pins: dict[str, str | None]) -> None:
    """Print the human-readable report.

    Args:
        report: The findings to print.
        pins: The local pins, for the header.
    """
    print("Declared and pinned toolchain")
    for label, value in pins.items():
        print(f"  {label:<28} {value or '(unreadable)'}")
    print()

    order = {"fail": 0, "warn": 1, "note": 2}
    icons = {"fail": "FAIL", "warn": "WARN", "note": "note"}
    for finding in sorted(report.findings, key=lambda item: order[item.level]):
        print(f"{icons[finding.level]}: {finding.subject}: {finding.message}")

    if report.skipped:
        print()
        print("Sources not reached (checked skipped, not failed):")
        for source in report.skipped:
            print(f"  - {source}")

    print()
    if report.failed:
        print("RESULT: fail - a declared or pinned toolchain version is EOL or out of band.")
    else:
        print("RESULT: ok - every reachable check passed.")


def main() -> int:
    """Run the freshness checks.

    Returns:
        ``1`` when any finding is fatal, otherwise ``0``.
    """
    parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument("--offline", action="store_true", help="Parse the local pins and fetch nothing.")
    parser.add_argument("--json", action="store_true", help="Emit findings as JSON instead of text.")
    parser.add_argument(
        "--report",
        type=pathlib.Path,
        help="Also write the JSON findings here, so one run can produce both the log and the artefact.",
    )
    args = parser.parse_args()

    report = Report()
    node, pnpm, uv, package_manager = _local_pins(report)
    ollama = _ollama_pin(report)
    requirements = _requirements()
    pins = {
        "python_requires (floor)": requirements.get("python_requires"),
        "python_target": requirements.get("python_target"),
        "node_requires (floor)": requirements.get("node_requires"),
        "node_target": requirements.get("node_target"),
        "node (bootstrap pin)": node,
        "pnpm (bootstrap pin)": pnpm,
        "uv (bootstrap pin)": uv,
        "ollama (managed pin)": ollama,
        "packageManager": package_manager,
    }

    if args.offline:
        report.add(
            "note",
            "network",
            "--offline: the local pins parsed, but no upstream release data was consulted.",
        )
    else:
        _check_node(report, requirements, node)
        _check_pnpm(report, pnpm, package_manager)
        _check_uv(report, uv)
        _check_ollama(report, ollama)
        _check_python(report, requirements)

    document = json.dumps(
        {
            "generated": dt.datetime.now(tz=dt.UTC).isoformat(timespec="seconds"),
            "pins": pins,
            "findings": [dataclasses.asdict(finding) for finding in report.findings],
            "skipped": report.skipped,
            "failed": report.failed,
        },
        indent=2,
    )
    if args.report is not None:
        args.report.write_text(document + "\n", encoding="utf-8")
    if args.json:
        print(document)
    else:
        _render(report, pins)

    return 1 if report.failed else 0


if __name__ == "__main__":
    sys.exit(main())