Skip to content

Annotate src/ for real: enable basedpyright type-strictness on source #397

Annotate src/ for real: enable basedpyright type-strictness on source

Annotate src/ for real: enable basedpyright type-strictness on source #397

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
# On-demand visual-smoke run. With update_baselines=true the visual job
# regenerates the screenshot baselines ON THE CI RUNNER (so they match
# GitHub's font render) and commits them back to the triggering branch.
workflow_dispatch:
inputs:
update_baselines:
description: "Regenerate screenshot baselines on the CI runner and commit them back to this branch"
type: boolean
default: false
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install ruff
run: pip install ruff
- name: Run ruff check
run: ruff check src/ tests/
- name: Run ruff format check
run: ruff format --check src/ tests/
test-web:
name: Web unit tests (vitest)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "22"
- uses: pnpm/action-setup@v6
with:
version: "11"
- name: Install web deps
working-directory: web
run: pnpm install --frozen-lockfile
- name: Run vitest
working-directory: web
run: pnpm test
test-e2e:
name: E2E (Playwright scenarios)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "22"
- uses: pnpm/action-setup@v6
with:
version: "11"
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install web deps
working-directory: web
run: pnpm install --frozen-lockfile
- name: Build web UI
working-directory: web
run: pnpm build
# Editable install puts the `claude-comms` console script on PATH; the
# Playwright daemon fixture spawns it (CC_E2E_DAEMON_CMD defaults to it).
- name: Install package
run: pip install -e ".[all]"
- name: Install Playwright Chromium
working-directory: web
run: pnpm exec playwright install --with-deps chromium
# e2e gates on BEHAVIOR (real daemon + testid assertions + console-error
# spies). Screenshots are skipped (--ignore-snapshots): on this CI they
# flake run-to-run -- icon/font anti-aliasing plus larger nondeterministic
# redraws (audit W-6/W-7; observed ~1% and ~4% diffs on identical code
# across consecutive runs). Baselines stay committed for local visual
# checks (`playwright test --update-snapshots`); blocking on visuals needs
# deterministic-render work first.
- name: Run Playwright scenarios (behavioral; snapshots non-blocking)
working-directory: web
# The editable install already exposes claude_comms + all deps via the
# runner's site-packages. Pin the daemon's PYTHONPATH to just the repo
# src; the fixture's default prepends /usr/lib/python3/dist-packages,
# whose old typing_extensions otherwise shadows the pip-installed one and
# crashes the daemon on startup (pydantic-core needs Sentinel).
env:
CC_E2E_PYTHONPATH: ${{ github.workspace }}/src
run: pnpm exec playwright test --ignore-snapshots
- name: Upload e2e results on failure
if: failure()
uses: actions/upload-artifact@v7
with:
name: e2e-results
path: web/test-results/
retention-days: 7
# On-demand visual smoke. This does NOT run on push/PR: screenshot baselines
# are font-render-sensitive, so baselines committed off-CI flake run-to-run on
# GitHub's runner (audit W-6/W-7) and the job was perpetually red while never
# blocking merge. The blocking gate is the behavioral test-e2e job above
# (which runs with --ignore-snapshots). Trigger this via the Actions
# "Run workflow" button (workflow_dispatch):
# - update_baselines=false → compare against committed baselines (uniform 2%
# tolerance) and upload diffs for review.
# - update_baselines=true → regenerate the *-linux.png baselines ON THE CI
# RUNNER and commit them back to the triggering branch, so they match
# GitHub's font render. See web/e2e/README.md "CI-matching baselines".
test-e2e-visual:
name: E2E visual smoke (on-demand)
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "22"
- uses: pnpm/action-setup@v6
with:
version: "11"
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install web deps
working-directory: web
run: pnpm install --frozen-lockfile
- name: Build web UI
working-directory: web
run: pnpm build
- name: Install package
run: pip install -e ".[all]"
- name: Install Playwright Chromium
working-directory: web
run: pnpm exec playwright install --with-deps chromium
- name: Compare screenshots (visual smoke)
if: ${{ !inputs.update_baselines }}
working-directory: web
env:
CC_E2E_PYTHONPATH: ${{ github.workspace }}/src
run: pnpm exec playwright test --grep "screenshot:"
- name: Regenerate baselines on the CI runner
if: ${{ inputs.update_baselines }}
working-directory: web
env:
CC_E2E_PYTHONPATH: ${{ github.workspace }}/src
run: pnpm exec playwright test --grep "screenshot:" --update-snapshots
- name: Commit regenerated baselines
if: ${{ inputs.update_baselines }}
run: |
set -euo pipefail
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add web/e2e/__screenshots__
if git diff --cached --quiet; then
echo "No baseline changes to commit."
else
git commit -m "Regenerate E2E screenshot baselines on CI runner [skip ci]"
git push origin HEAD:${{ github.ref_name }}
fi
- name: Upload visual diffs
if: always()
uses: actions/upload-artifact@v7
with:
name: e2e-visual-diffs
path: web/test-results/
retention-days: 7
test:
name: Test (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "22"
- uses: pnpm/action-setup@v6
with:
version: "11"
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
cache: pip
# Build the web UI BEFORE the editable install so the Hatch build hook
# (hatch_build.py) sees src/claude_comms/web/dist/ already populated and
# short-circuits. Without this, `pip install -e` would invoke pnpm
# inside Python's tooling pipeline.
- name: Install web deps
working-directory: web
run: pnpm install --frozen-lockfile
- name: Build web UI
working-directory: web
run: pnpm build
- name: Install package with dev dependencies
run: pip install -e ".[all,dev]"
- name: Run tests
run: pytest --tb=short --junitxml=test-results/results.xml
- name: Upload test results
uses: actions/upload-artifact@v7
if: always()
with:
name: test-results-py${{ matrix.python-version }}
path: test-results/
retention-days: 30
build-wheel:
name: Build wheel
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "22"
- uses: pnpm/action-setup@v6
with:
version: "11"
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install build frontend
run: pip install build
# `python -m build` invokes the Hatch backend in an isolated env,
# which in turn runs hatch_build.py. The hook discovers pnpm on PATH
# and produces src/claude_comms/web/dist/ before sealing the wheel.
- name: Build wheel + sdist
run: python -m build
- name: Verify wheel contains web/dist
run: |
set -euo pipefail
wheel=$(ls dist/*.whl)
if ! python -m zipfile -l "$wheel" | grep -q 'claude_comms/web/dist/index.html'; then
echo "FAIL: $wheel is missing claude_comms/web/dist/index.html"
python -m zipfile -l "$wheel" | head -40
exit 1
fi
echo "OK: $wheel ships claude_comms/web/dist/index.html"
- name: Upload build artifacts
uses: actions/upload-artifact@v7
with:
name: dist
path: dist/
retention-days: 30