2f9bf0bf5b
- Add tests/test_boot_routes_subprocess.py that exercises build_routes in child Python processes (no conftest a2a stubs) across all 4 branches: A executor happy-path, B not-configured fallback, C error surfacing, D empty-input defensive guard. - Add an explicit CI step so the gate is visible and a missing real a2a-sdk shows up as a loud skip, not a silent green. Fixes molecule-ai-workspace-runtime#88 Co-Authored-By: Claude <noreply@anthropic.com>
189 lines
7.3 KiB
YAML
189 lines
7.3 KiB
YAML
name: ci
|
|
|
|
# Standalone-as-SSOT CI (post-migration 2026-05-20).
|
|
#
|
|
# This repo became the single source of truth for the molecule-runtime
|
|
# Python package as of the standalone-as-SSOT migration (issue #87
|
|
# follow-on, CTO-GO 2026-05-20). Edit Python under molecule_runtime/
|
|
# directly here; the monorepo workspace-server pins this wheel by
|
|
# version.
|
|
#
|
|
# Old mirror-guard CI removed — direct PRs are the canonical edit path.
|
|
|
|
on:
|
|
push:
|
|
branches: [main, staging]
|
|
pull_request:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
unit-tests:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
with:
|
|
python-version: "3.11"
|
|
cache: pip
|
|
|
|
- name: Install test dependencies
|
|
env:
|
|
PIP_INDEX_URL: https://git.moleculesai.app/api/packages/molecule-ai/pypi/simple/
|
|
run: |
|
|
# Install the editable package so CI exercises pyproject.toml's
|
|
# runtime dependency contract. This intentionally catches SDK/API
|
|
# drift in package-local adapter tests, not only tests under tests/.
|
|
pip install -e . pytest pytest-asyncio
|
|
|
|
- name: Run unit tests
|
|
# Exclude the over-the-wire responsiveness e2e (its own job below) —
|
|
# it boots real uvicorn servers and a 50s busy window, too slow for
|
|
# the fast unit lane.
|
|
run: pytest -q --ignore=tests/integration
|
|
|
|
- name: Run build_routes real-subprocess regression gate
|
|
# Explicit, loud step for issue #88: the 4-branch build_routes contract
|
|
# must be exercised against the REAL a2a-sdk in child processes. A skip
|
|
# here means the real SDK is missing and the gate is inert.
|
|
run: pytest -v -rs tests/test_boot_routes_subprocess.py
|
|
|
|
responsiveness-e2e:
|
|
# Deterministic, merge-BLOCKING integration gate for the "busy agent
|
|
# becomes unreachable / blocks ~300s" regression class (2026-06-10).
|
|
#
|
|
# It drives a REAL RuntimeA2AExecutor mounted in REAL a2a-sdk JSON-RPC
|
|
# Starlette routes served by REAL uvicorn, over REAL HTTP, and asserts:
|
|
# (a) a concurrent same-context POST fast-acks (no head-of-line block)
|
|
# — locks in the non-blocking flip (#116);
|
|
# (b) the agent never goes 'stale' across a busy window that EXCEEDS
|
|
# the old 45s stale threshold — locks in the stale-window fix;
|
|
# (c) both turns complete + the agent recovers to idle;
|
|
# (d) a tool that hangs past the per-turn idle cap is bounded and the
|
|
# executor recovers instead of wedging — locks in A1 tool-timeout.
|
|
#
|
|
# No external creds / infra (localhost only + a scripted, LLM-free
|
|
# agent), so it is a deterministic merge gate — NOT a gated-nightly.
|
|
# The integration conftest LOUD-SKIPS (never silent-passes) if the real
|
|
# a2a-sdk wheel is somehow absent.
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
with:
|
|
python-version: "3.11"
|
|
cache: pip
|
|
|
|
- name: Install test dependencies
|
|
env:
|
|
PIP_INDEX_URL: https://git.moleculesai.app/api/packages/molecule-ai/pypi/simple/
|
|
run: |
|
|
# -e . pulls the REAL a2a-sdk[http-server] + starlette + uvicorn +
|
|
# httpx so the e2e exercises the production wire, not stubs.
|
|
pip install -e . pytest pytest-asyncio
|
|
|
|
- name: Run agent-responsiveness-under-load e2e
|
|
# CI-tuned timings: the busy window (50s) still comfortably EXCEEDS
|
|
# the asserted stale window (20s), so the >45s-stale-window contract
|
|
# is genuinely exercised, while keeping the job ~1 min. All timings
|
|
# are env-tunable so a slower runner can widen slack without code
|
|
# edits.
|
|
env:
|
|
RESP_E2E_A_BUSY_SECONDS: "50"
|
|
RESP_E2E_STALE_WINDOW_SECONDS: "20"
|
|
RESP_E2E_HEARTBEAT_INTERVAL: "4"
|
|
RESP_E2E_FAST_ACK_CEILING: "5"
|
|
RESP_E2E_IDLE_CAP: "3"
|
|
RESP_E2E_POLL_DEADLINE: "25"
|
|
run: pytest -q tests/integration
|
|
|
|
lint:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
with:
|
|
python-version: "3.11"
|
|
cache: pip
|
|
|
|
- name: Install ruff
|
|
env:
|
|
PIP_INDEX_URL: https://git.moleculesai.app/api/packages/molecule-ai/pypi/simple/
|
|
run: pip install ruff
|
|
|
|
- name: Lint with ruff (syntax + obvious errors only)
|
|
# Initial lint scope is intentionally narrow — E9 (syntax), F (pyflakes
|
|
# errors only, not warnings). Broadening to full ruff rules is a
|
|
# follow-up task once the SSOT settles.
|
|
run: ruff check --select=E9,F63,F7,F82 molecule_runtime/
|
|
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
with:
|
|
python-version: "3.11"
|
|
cache: pip
|
|
|
|
- name: Install build tooling
|
|
env:
|
|
PIP_INDEX_URL: https://git.moleculesai.app/api/packages/molecule-ai/pypi/simple/
|
|
run: pip install build twine
|
|
|
|
- name: Build wheel + sdist
|
|
run: python -m build
|
|
|
|
- name: Verify package metadata
|
|
run: python -m twine check dist/*
|
|
|
|
- name: Upload wheel artifact
|
|
uses: actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5 # v3
|
|
with:
|
|
name: wheel
|
|
path: dist/*.whl
|
|
retention-days: 7
|
|
|
|
smoke-install:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
with:
|
|
python-version: "3.11"
|
|
cache: pip
|
|
|
|
- name: Build local wheel for smoke install
|
|
env:
|
|
PIP_INDEX_URL: https://git.moleculesai.app/api/packages/molecule-ai/pypi/simple/
|
|
run: |
|
|
pip install build
|
|
python -m build --wheel
|
|
|
|
- name: Install wheel in clean venv + smoke-import
|
|
env:
|
|
PIP_INDEX_URL: https://git.moleculesai.app/api/packages/molecule-ai/pypi/simple/
|
|
run: |
|
|
set -eu
|
|
python -m venv /tmp/smoke-venv
|
|
/tmp/smoke-venv/bin/pip install --quiet dist/*.whl
|
|
# Verify the package + the canonical multi-WS / runtime imports.
|
|
/tmp/smoke-venv/bin/python -c "
|
|
from molecule_runtime import executor_helpers
|
|
from molecule_runtime.mcp_workspace_resolver import resolve_workspaces
|
|
from molecule_runtime import mcp_cli
|
|
from molecule_runtime.executor_helpers import extract_attached_files
|
|
from molecule_runtime.llm_auth import normalise_llm_env
|
|
from molecule_runtime.credential_helper import install_credential_helper
|
|
from molecule_runtime.precommit_hook import install_pre_commit_hook
|
|
print('smoke-import: all canonical surfaces import cleanly')
|
|
"
|
|
# CLI entry-point — molecule-mcp must be installed + show help.
|
|
/tmp/smoke-venv/bin/molecule-mcp --help | head -5
|