Skip to content

docs: mark admin-merge policy as transitional solo-owner state (#101) #115

docs: mark admin-merge policy as transitional solo-owner state (#101)

docs: mark admin-merge policy as transitional solo-owner state (#101) #115

Workflow file for this run

name: CI
# Action SHAs are pinned, not floating tags. To bump:
# gh api repos/<owner>/<repo>/commits/<tag> --jq .sha
# (use /commits/<tag>, NOT /git/refs/tags/<tag> — annotated tags would
# return the tag-object SHA, which Actions can't resolve.)
# Update the comment on the right with the new tag for traceability.
on:
push:
branches: [develop, main]
pull_request:
branches: [develop, main]
jobs:
lint:
name: Lint & Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: uv sync --frozen --extra dev
- run: uv run ruff check .
- run: uv run ruff format --check .
typecheck:
name: Type Check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: uv sync --frozen --extra dev
- run: uv run mypy --strict src/ tests/
test-unit:
name: Unit tests
runs-on: ubuntu-latest
# Pure in-process tests — completes fast so PR authors get quick feedback.
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: uv sync --frozen --extra dev
- run: uv run pytest tests/ -v -m "not integration" -o "addopts="
coverage:
name: Coverage
runs-on: ubuntu-latest
# Enforces [tool.coverage.report].fail_under from pyproject.toml (75%).
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: uv sync --frozen --extra dev
- run: uv run pytest tests/ --cov=src --cov-report=term-missing
architecture:
name: Architecture (import-linter)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: uv sync --frozen --extra dev
- run: uv run lint-imports
pre-commit:
name: Pre-commit
runs-on: ubuntu-latest
# Runs every hook against all files — ensures a developer who forgot
# `uv run pre-commit install` can't leak unformatted code or a stray
# secret past the first defence layer.
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: uv sync --frozen --extra dev
- run: uv run pre-commit run --all-files --show-diff-on-failure
file-length:
name: File length
runs-on: ubuntu-latest
# CLAUDE.md: "no file over 300 lines, no function over ~50 lines". Ruff
# PLR0915 / PLR0912 enforce the function-half (run by `Lint & Format`);
# this job enforces the file-half. No exemption mechanism — pre-existing
# offenders should be split before this job lands, not allowlisted.
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: python .github/scripts/check_file_length.py
version-bump:
name: Version bump check
runs-on: ubuntu-latest
# Every non-`release:` PR bumps [project] version in pyproject.toml AND
# the matching [[package]] block in uv.lock. Closes the bump-miss class
# that the 75 % coverage gate cannot detect on its own.
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0 # full history so `git show origin/<base>:` resolves
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: python .github/scripts/check_version_bump.py
action-pinning:
name: Action pinning audit
runs-on: ubuntu-latest
# Validates every `uses:` line in .github/workflows/ + .github/actions/
# against the policy in docs/DEVELOPMENT.md#action-pinning-policy.
# First-party = major tag; astral-sh/setup-uv = patch tag; third-party
# = SHA + trailing `# vN.M.P` comment.
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: python .github/scripts/check_action_pins.py
tests-required:
name: Tests required
runs-on: ubuntu-latest
# `feat:` / `fix:` PRs that touch `src/` must touch `tests/` too.
# Per docs/DEVELOPMENT.md Testing Policy. Other prefixes get a warn-only
# `::warning::` if src/ is touched without tests/.
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0 # full history so the diff resolves
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: python .github/scripts/check_tests_present.py
aspirational-tickets:
name: Aspirational ticket cite
runs-on: ubuntu-latest
# docs/INVARIANTS.md: every `*Aspirational` / `**Aspirational**` marker
# line cites a `#NNN` ticket; closed cites warn (or fail under
# ASPIRATIONAL_STRICT=1). GITHUB_TOKEN enables ticket-state lookup.
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: python .github/scripts/check_aspirational_tickets.py
src-readmes:
name: src/ README audit
runs-on: ubuntu-latest
# CLAUDE.md: every `src/` package documents its purpose + key
# interfaces. The audit checks shape (presence + min 200 bytes) and
# structure (`## Key interfaces` heading). No exemption mechanism.
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: python .github/scripts/check_src_readmes.py
frontend-build:
name: Frontend Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: "24"
cache: npm
cache-dependency-path: frontend/package-lock.json
- run: cd frontend && npm ci && npm run build
frontend-quality:
name: Frontend Quality
runs-on: ubuntu-latest
# Lint + format + tsc + vitest. Mirrors the strict posture the backend
# enjoys (ruff + mypy + pytest); the Frontend Build job above validates
# the bundler output, this one validates source quality.
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
with:
node-version: "24"
cache: npm
cache-dependency-path: frontend/package-lock.json
- run: cd frontend && npm ci
- run: cd frontend && npm run lint
- run: cd frontend && npm run format:check
- run: cd frontend && npm run check
- run: cd frontend && npm run test
branch-protection-sync:
name: Branch-protection contexts sync
runs-on: ubuntu-latest
# Guards against the "new CI job silently not required" drift. Fails when
# .github/branch-protection/*.json contexts arrays disagree with the
# actual workflow jobs on disk.
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: uv sync --frozen --extra dev
- run: uv run python .github/scripts/check_required_contexts.py
commit-type-sync:
name: Commit-type sync
runs-on: ubuntu-latest
# Guards against [tool.commitizen].customize.schema_pattern in pyproject
# drifting from the `types` list in .github/workflows/pr-title.yml.
# Adding a type in one but not the other would mean commits pass locally
# while PR titles fail in CI (or vice versa).
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.14"
- run: uv sync --frozen --extra dev
- run: uv run python .github/scripts/check_commit_types.py
# Frontend jobs (Frontend Build, Frontend Quality) are added by ticket #21
# when frontend/package.json lands.