Skip to content

[HOLD-for-9.0.0][skip-runtime-e2e] docs(decisions): canonical /decisions verdict values #840

[HOLD-for-9.0.0][skip-runtime-e2e] docs(decisions): canonical /decisions verdict values

[HOLD-for-9.0.0][skip-runtime-e2e] docs(decisions): canonical /decisions verdict values #840

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
AXONFLOW_TELEMETRY: 'off'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
cache-dependency-path: 'pyproject.toml'
- name: Install dependencies
run: pip install -e ".[dev]"
- name: Run Ruff linter
run: ruff check .
- name: Run Ruff formatter check
run: ruff format --check .
- name: Run MyPy
run: mypy axonflow
- name: Run falsey-clobber check (no `data.get(...) or X` against pre-existing baseline)
run: python3 scripts/lint_no_falsey_clobber.py axonflow/ --baseline .lint_baselines/falsey_clobber.json
test:
runs-on: ubuntu-latest
strategy:
# PR runs only Python 3.11 (current release toolchain). Push to main and
# workflow_dispatch run the full matrix to catch version-specific drift.
matrix:
python-version: ${{ fromJson(github.event_name == 'pull_request' && '["3.11"]' || '["3.10", "3.11", "3.12"]') }}
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
cache-dependency-path: 'pyproject.toml'
- name: Install dependencies
run: pip install -e ".[dev,all]"
- name: Run tests
run: pytest --cov-report=xml
- name: Upload coverage
if: matrix.python-version == '3.11'
uses: codecov/codecov-action@v4
with:
files: ./coverage.xml
flags: python-sdk
fail_ci_if_error: false
# Aggregator that always reports a single check name regardless of the
# matrix shape (PR-time matrix is `['3.11']`; push/dispatch is full).
# Branch protection requires `Test Summary`, not the per-version names,
# so matrix changes don't strand required checks.
test-summary:
name: Test Summary
needs: [test]
if: always()
runs-on: ubuntu-latest
steps:
- name: Aggregate test matrix result
run: |
result="${{ needs.test.result }}"
echo "test matrix result: $result"
if [ "$result" != "success" ] && [ "$result" != "skipped" ]; then
echo "::error::test matrix did not all pass (result: $result)"
exit 1
fi
echo "Test matrix OK"
# QF-15: wire-shape contract CI. Blocks drift between Python SDK pydantic
# models and the OpenAPI specs that are the authoritative wire contract.
# Runs on every PR. Drift the baseline does not cover fails the check.
#
# The specs are fetched from the getaxonflow/axonflow community mirror
# pinned to the SHA recorded in tests/fixtures/wire_shape_baseline.json
# so the gate is deterministic — a given SDK commit always diffs against
# the same spec revision, independent of upstream activity. Changing the
# pinned SHA from the same PR that changes SDK models would bypass the
# gate, so the workflow also runs a SHA-bump guard that requires a
# 'spec-pin-bump' label on PRs that move the SHA.
#
# To pick up new spec changes, regenerate the baseline via
# scripts/refresh_wire_shape_baseline.py (ideally in a dedicated PR).
wire-shape-contract:
runs-on: ubuntu-latest
steps:
- name: Checkout SDK (full history for SHA-bump guard)
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Read pinned OpenAPI specs SHA from baseline
id: specs_sha
run: |
python3 - <<'PY' >> "$GITHUB_OUTPUT"
import json
import sys
path = "tests/fixtures/wire_shape_baseline.json"
data = json.load(open(path))
sha = data.get("openapi_specs_sha", "").strip()
if not sha:
print(
f"::error::{path} is missing openapi_specs_sha. "
"Regenerate via scripts/refresh_wire_shape_baseline.py.",
file=sys.stderr,
)
sys.exit(1)
print(f"sha={sha}")
PY
# SHA-bump guard: the pinned SHA is the contract's source of truth.
# A PR that both changes the SHA and the SDK models can silently
# retarget the gate away from the drift it should have caught. Require
# explicit 'spec-pin-bump' label to acknowledge the bump. First-time
# introductions (base branch has no pin yet) bypass the guard.
- name: Guard against unauthorized OpenAPI specs SHA bump
if: github.event_name == 'pull_request'
env:
PR_LABELS: ${{ toJSON(github.event.pull_request.labels.*.name) }}
BASE_REF: ${{ github.base_ref }}
PR_SHA: ${{ steps.specs_sha.outputs.sha }}
run: |
set -e
BASE_SHA=$(
git show "origin/${BASE_REF}:tests/fixtures/wire_shape_baseline.json" 2>/dev/null \
| python3 -c "import json, sys; print(json.load(sys.stdin).get('openapi_specs_sha','') or '')" \
|| true
)
if [ -z "$BASE_SHA" ]; then
echo "::notice::Base branch has no openapi_specs_sha yet; treating this PR as the first pin introduction."
exit 0
fi
if [ "$BASE_SHA" = "$PR_SHA" ]; then
echo "openapi_specs_sha unchanged (${PR_SHA})."
exit 0
fi
echo "SHA change detected: ${BASE_SHA} -> ${PR_SHA}"
HAS_LABEL=$(printf '%s' "$PR_LABELS" | python3 -c "import json, sys; print('spec-pin-bump' in json.load(sys.stdin))")
if [ "$HAS_LABEL" = "True" ]; then
echo "::notice::'spec-pin-bump' label present — SHA bump authorized."
exit 0
fi
echo "::error::openapi_specs_sha changed from ${BASE_SHA} to ${PR_SHA}."
echo "::error::The wire-shape contract's spec revision is pinned to preserve"
echo "::error::review integrity: a SHA change in the same PR as SDK changes"
echo "::error::can silence drift by retargeting the contract to a friendlier"
echo "::error::revision. Either split this into a dedicated SHA-bump PR, or"
echo "::error::apply the 'spec-pin-bump' label to this PR to acknowledge that"
echo "::error::the bump is intentional and has been reviewed independently."
exit 1
- name: Checkout OpenAPI specs (pinned to baseline SHA)
uses: actions/checkout@v4
with:
repository: getaxonflow/axonflow
ref: ${{ steps.specs_sha.outputs.sha }}
path: axonflow-community
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
cache-dependency-path: 'pyproject.toml'
- name: Install dependencies
run: pip install -e ".[dev]"
- name: Run wire-shape contract tests
env:
AXONFLOW_OPENAPI_SPECS_DIR: ${{ github.workspace }}/axonflow-community/docs/api
run: pytest tests/test_wire_shape.py -m wire_shape -v --no-cov
build:
runs-on: ubuntu-latest
needs: [lint, test, wire-shape-contract]
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
cache-dependency-path: 'pyproject.toml'
- name: Install build tools
run: pip install build twine
- name: Build package
run: python -m build
- name: Check package
run: twine check dist/*
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/