id: python-dependencies-pinned
name: Python dependencies are pinned to exact versions
description: >
  Python projects must have a locked dependency file with pinned versions.
  A requirements.txt without version pins, or a pyproject.toml without a lockfile,
  resolves to whatever is current at install time — producing environment drift across
  machines, containers, and AI sessions. The exact versions in the lockfile are the
  specification: they are the versions that passed tests, not a range of versions that
  might. Gate passes when: requirements.txt exists with all entries pinned (==), OR
  pyproject.toml exists alongside poetry.lock, uv.lock, or pdm.lock.
property: Executable
tags: [python, any]
phase: development
trigger: pr
blocking: true
check:
  type: script
  command: >
    if [ -f requirements.txt ]; then
      grep -vE "^#|^$|==" requirements.txt && echo "FAIL: unpinned deps in requirements.txt" && exit 1 || exit 0;
    elif [ -f pyproject.toml ]; then
      ([ -f poetry.lock ] || [ -f uv.lock ] || [ -f pdm.lock ]) || { echo "FAIL: no lockfile found"; exit 1; };
    else echo "FAIL: no Python dependency file"; exit 1; fi
