forked from molecule-ai/molecule-core
Closes #134. The post-merge review of #2196 flagged that the combined workflow's `paths:` filter (the union of both jobs' needs: `workspace/**` + `scripts/build_runtime_package.py` + the workflow itself) caused the `pypi-latest-install` job to fire on every doc-only / adapter-only / unrelated workspace/ edit. The PyPI artifact that job tests against can't change based on our workspace/ source — only on actual PyPI publishes — so those runs add noise without information. Splits the previously-merged combined workflow: runtime-pin-compat.yml (kept): - PyPI-latest install + import smoke (was: pypi-latest-install) - Narrow `paths:` filter — only fires when workspace/requirements.txt or this workflow file changes - Cron-driven daily for upstream-yank detection (unchanged) runtime-prbuild-compat.yml (new): - PR-built wheel + import smoke (was: local-build-install) - Broad `paths:` filter — fires on any workspace/ source change, scripts/build_runtime_package.py, or this workflow file - No cron (workspace/ doesn't change between firings) Behavior identical to before for content; only the trigger surface is narrower per-job. Each workflow's name is its own status check, so branch protection (which currently lists neither as required) can gate them independently in future. The prior comment in the combined file explicitly acknowledged the asymmetry and proposed this split as a follow-up; this is that follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
92 lines
4.1 KiB
YAML
92 lines
4.1 KiB
YAML
name: Runtime Pin Compatibility
|
|
|
|
# CI gate that prevents the 5-hour staging outage from 2026-04-24 from
|
|
# recurring (controlplane#253). The original failure mode:
|
|
# 1. molecule-ai-workspace-runtime 0.1.13 declared `a2a-sdk<1.0` in its
|
|
# requires_dist metadata (incorrect — it actually imports
|
|
# a2a.server.routes which only exists in a2a-sdk 1.0+)
|
|
# 2. `pip install molecule-ai-workspace-runtime` resolved cleanly
|
|
# 3. `from molecule_runtime.main import main_sync` raised ImportError
|
|
# 4. Every tenant workspace crashed; the canary tenant caught it but
|
|
# only after 5 hours of degraded staging
|
|
#
|
|
# This workflow installs the CURRENTLY PUBLISHED runtime from PyPI on
|
|
# top of `workspace/requirements.txt` and smoke-imports. Catches:
|
|
# - Upstream PyPI yanks
|
|
# - Bad re-releases of molecule-ai-workspace-runtime
|
|
# - Already-shipped wheels that stop importing because a transitive
|
|
# dep moved underneath
|
|
#
|
|
# This is the "PyPI artifact health" half of pin compatibility. The
|
|
# companion workflow `runtime-prbuild-compat.yml` covers the
|
|
# "PR-introduced breakage" half by building the wheel from THIS PR's
|
|
# workspace/ source. Splitting the two means each gets a narrow
|
|
# `paths:` filter — the pypi-latest job no longer fires on doc-only
|
|
# workspace/ edits whose content can't change what's currently on PyPI.
|
|
|
|
on:
|
|
push:
|
|
branches: [main, staging]
|
|
paths:
|
|
# Narrow filter: pypi-latest is sensitive only to changes that
|
|
# affect what we're INSTALLING (requirements.txt) or WHAT THE
|
|
# CHECK ITSELF DOES (this workflow file). Edits to workspace/
|
|
# source code don't change what's on PyPI right now, so they
|
|
# don't change this gate's verdict.
|
|
- 'workspace/requirements.txt'
|
|
- '.github/workflows/runtime-pin-compat.yml'
|
|
pull_request:
|
|
branches: [main, staging]
|
|
paths:
|
|
- 'workspace/requirements.txt'
|
|
- '.github/workflows/runtime-pin-compat.yml'
|
|
# Daily catch for upstream PyPI publishes that break the pin combo
|
|
# without any change in our repo (e.g. someone re-yanks an a2a-sdk
|
|
# release or molecule-ai-workspace-runtime publishes a bad bump).
|
|
schedule:
|
|
- cron: '0 13 * * *' # 06:00 PT
|
|
workflow_dispatch:
|
|
# Required-check support: when this becomes a branch-protection gate,
|
|
# merge_group runs let the queue green-check this in addition to PRs.
|
|
merge_group:
|
|
types: [checks_requested]
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
pypi-latest-install:
|
|
name: PyPI-latest install + import smoke
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.11'
|
|
cache: pip
|
|
cache-dependency-path: workspace/requirements.txt
|
|
- name: Install runtime + workspace requirements
|
|
# Install order is load-bearing: install the runtime FIRST so pip
|
|
# honors whatever a2a-sdk constraint the runtime metadata declares
|
|
# (this is the surface that broke in 2026-04-24 — runtime declared
|
|
# `a2a-sdk<1.0` but actually needed >=1.0). The follow-up install
|
|
# of workspace/requirements.txt then upgrades a2a-sdk to the
|
|
# constraint our runtime image actually pins. The import smoke
|
|
# below verifies the upgraded combination is consistent.
|
|
run: |
|
|
python -m venv /tmp/venv
|
|
/tmp/venv/bin/pip install --upgrade pip
|
|
/tmp/venv/bin/pip install molecule-ai-workspace-runtime
|
|
/tmp/venv/bin/pip install -r workspace/requirements.txt
|
|
/tmp/venv/bin/pip show molecule-ai-workspace-runtime a2a-sdk \
|
|
| grep -E '^(Name|Version):'
|
|
- name: Smoke import — fail if metadata declares deps that don't satisfy real imports
|
|
# WORKSPACE_ID is validated at import time by platform_auth.py — EC2
|
|
# user-data sets it from the cloud-init template; set a placeholder
|
|
# here so the import smoke doesn't trip on the env-var guard.
|
|
env:
|
|
WORKSPACE_ID: 00000000-0000-0000-0000-000000000001
|
|
run: |
|
|
/tmp/venv/bin/python -c "from molecule_runtime.main import main_sync; print('runtime imports OK')"
|