From ac5fcd96843d2c22c16779c16003eaa0fb045a25 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 5 Sep 2026 18:38:00 +0000 Subject: [PATCH 1/3] ci: streamline Python test matrix --- .github/workflows/ci.yml | 82 ++++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89d5ec98b..1ef4bfd15 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,7 @@ jobs: workflow-security: name: Workflow security runs-on: ubuntu-latest + timeout-minutes: 10 permissions: contents: read security-events: write @@ -52,20 +53,20 @@ jobs: advanced-security: false annotations: true - test: - name: Test Python ${{ matrix.python-version }} + static-analysis: + name: Static analysis (Python 3.12) runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10", "3.11", "3.12", "3.13"] + timeout-minutes: 15 steps: - uses: actions/checkout@v6 - - name: Set up Python ${{ matrix.python-version }} + - name: Set up Python 3.12 uses: actions/setup-python@v6 with: - python-version: ${{ matrix.python-version }} + python-version: "3.12" + cache: pip + cache-dependency-path: pyproject.toml - name: Install dependencies run: | @@ -73,28 +74,52 @@ jobs: pip install -e ".[dev]" - name: Run linter - run: | - ruff check src/ + run: ruff check src/ - name: Run type checker - run: | - mypy src/adcp/ + run: mypy src/adcp/ - name: Run adopter type-check suite - run: | - mypy --strict tests/type_checks/ + run: mypy --strict tests/type_checks/ - name: Enforce adopter type-check fixture contract + run: python scripts/check_type_ignore_contract.py + + test: + name: Test Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13"] + + steps: + - uses: actions/checkout@v6 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + cache: pip + cache-dependency-path: pyproject.toml + + - name: Install dependencies run: | - python scripts/check_type_ignore_contract.py + python -m pip install --upgrade pip + pip install -e ".[dev]" - name: Run tests - run: | - pytest tests/ -v --cov=src/adcp --cov-report=term-missing + if: matrix.python-version != '3.12' + run: pytest tests/ -v + + - name: Run tests with coverage + if: matrix.python-version == '3.12' + run: pytest tests/ -v --cov=src/adcp --cov-report=term-missing pg-conformance: name: Postgres conformance tests (Postgres 16) runs-on: ubuntu-latest + timeout-minutes: 15 services: postgres: # CI-local ephemeral database. POSTGRES_HOST_AUTH_METHOD=trust @@ -120,6 +145,8 @@ jobs: uses: actions/setup-python@v6 with: python-version: "3.12" + cache: pip + cache-dependency-path: pyproject.toml - name: Install dependencies (with [pg] extra) run: | @@ -141,6 +168,7 @@ jobs: conventional-commits: name: Validate conventional commit format runs-on: ubuntu-latest + timeout-minutes: 10 if: github.event_name == 'pull_request' steps: @@ -197,6 +225,7 @@ jobs: downstream-imports: name: Downstream import smoke (representative consumer symbols) runs-on: ubuntu-latest + timeout-minutes: 15 steps: - uses: actions/checkout@v6 @@ -205,6 +234,8 @@ jobs: uses: actions/setup-python@v6 with: python-version: "3.11" + cache: pip + cache-dependency-path: pyproject.toml - name: Build sdist and install its wheel run: | @@ -321,6 +352,7 @@ jobs: schema-check: name: Validate schemas are up-to-date runs-on: ubuntu-latest + timeout-minutes: 15 steps: - uses: actions/checkout@v6 @@ -329,6 +361,8 @@ jobs: uses: actions/setup-python@v6 with: python-version: "3.11" + cache: pip + cache-dependency-path: pyproject.toml - name: Install dependencies run: | @@ -426,6 +460,7 @@ jobs: storyboard: name: AdCP storyboard runner — examples/seller_agent.py (@adcp/sdk ${{ matrix.adcp-sdk-tag }}) runs-on: ubuntu-latest + timeout-minutes: 20 # Blocking gate: examples/seller_agent.py is the Python-owned # reference target for bidirectional storyboard interop. The matrix # runs two legs: the sticky ``adcp-3.0`` tag is a fixed, reproducible @@ -443,6 +478,8 @@ jobs: uses: actions/setup-python@v6 with: python-version: "3.12" + cache: pip + cache-dependency-path: pyproject.toml - name: Set up Node 22 uses: actions/setup-node@v6 @@ -480,6 +517,7 @@ jobs: storyboard-required-gate: name: AdCP storyboard runner — examples/seller_agent.py runs-on: ubuntu-latest + timeout-minutes: 5 needs: storyboard if: always() steps: @@ -494,6 +532,7 @@ jobs: v3-reference-seller-tests: name: v3 reference seller — pytest (respx-mocked upstream) runs-on: ubuntu-latest + timeout-minutes: 15 steps: - uses: actions/checkout@v6 @@ -502,6 +541,8 @@ jobs: uses: actions/setup-python@v6 with: python-version: "3.12" + cache: pip + cache-dependency-path: pyproject.toml - name: Install dependencies run: | @@ -523,6 +564,7 @@ jobs: storyboard-v3-reference-seller: name: AdCP storyboard runner — v3 reference seller (translator) runs-on: ubuntu-latest + timeout-minutes: 20 env: # Intentionally non-secret: gates loopback-only debug counters # inside this CI job. @@ -551,6 +593,8 @@ jobs: uses: actions/setup-python@v6 with: python-version: "3.12" + cache: pip + cache-dependency-path: pyproject.toml - name: Set up Node 22 uses: actions/setup-node@v6 @@ -819,6 +863,7 @@ jobs: storyboard-multi-platform-seller: name: AdCP storyboard runner — examples/multi_platform_seller (PlatformRouter) runs-on: ubuntu-latest + timeout-minutes: 20 # Multi-tenant proof: one process, two tenants, one router. Each # tenant's storyboard runs against its own subdomain # (tenant-a.localhost / tenant-b.localhost). Blocking gate — both @@ -834,6 +879,8 @@ jobs: uses: actions/setup-python@v6 with: python-version: "3.12" + cache: pip + cache-dependency-path: pyproject.toml - name: Set up Node 22 uses: actions/setup-node@v6 @@ -928,6 +975,7 @@ jobs: storyboard-sales-proposal-mode: name: AdCP storyboard runner — sales-proposal-mode (proposal_finalize) runs-on: ubuntu-latest + timeout-minutes: 20 # v1.5 ProposalManager finalize lifecycle proof. The mock seller # declares ``finalize=True`` + wires an ``InMemoryProposalStore``; # the framework's dispatch wiring intercepts ``refine[i].action='finalize'`` @@ -942,6 +990,8 @@ jobs: uses: actions/setup-python@v6 with: python-version: "3.12" + cache: pip + cache-dependency-path: pyproject.toml - name: Set up Node 22 uses: actions/setup-node@v6 From efc66674fcdbf2686d16f3655293ef7c326358a6 Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 5 Sep 2026 18:38:42 +0000 Subject: [PATCH 2/3] fix(ci): preserve required static analysis gate --- .github/workflows/ci.yml | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ef4bfd15..0a1f77d18 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,18 +53,21 @@ jobs: advanced-security: false annotations: true - static-analysis: - name: Static analysis (Python 3.12) + test: + name: Test Python ${{ matrix.python-version }} runs-on: ubuntu-latest - timeout-minutes: 15 + timeout-minutes: 30 + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v6 - - name: Set up Python 3.12 + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: - python-version: "3.12" + python-version: ${{ matrix.python-version }} cache: pip cache-dependency-path: pyproject.toml @@ -74,40 +77,21 @@ jobs: pip install -e ".[dev]" - name: Run linter + if: matrix.python-version == '3.12' run: ruff check src/ - name: Run type checker + if: matrix.python-version == '3.12' run: mypy src/adcp/ - name: Run adopter type-check suite + if: matrix.python-version == '3.12' run: mypy --strict tests/type_checks/ - name: Enforce adopter type-check fixture contract + if: matrix.python-version == '3.12' run: python scripts/check_type_ignore_contract.py - test: - name: Test Python ${{ matrix.python-version }} - runs-on: ubuntu-latest - timeout-minutes: 30 - strategy: - matrix: - python-version: ["3.10", "3.11", "3.12", "3.13"] - - steps: - - uses: actions/checkout@v6 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v6 - with: - python-version: ${{ matrix.python-version }} - cache: pip - cache-dependency-path: pyproject.toml - - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -e ".[dev]" - - name: Run tests if: matrix.python-version != '3.12' run: pytest tests/ -v From 0f0dc37cb3b737e6415d176edb25b3910a6ef7ca Mon Sep 17 00:00:00 2001 From: Brian O'Kelley Date: Sat, 5 Sep 2026 18:39:29 +0000 Subject: [PATCH 3/3] fix(ci): let superseded runs terminate --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0a1f77d18..5e952e040 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -503,7 +503,9 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 needs: storyboard - if: always() + # Run after a failed matrix so the aggregate required check fails, but + # do not keep superseded workflow runs alive after concurrency cancels them. + if: ${{ !cancelled() }} steps: - name: Require all reference seller storyboard matrix runs run: |