Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 19 additions & 72 deletions .github/workflows/runtime-pin-compat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,35 @@ name: Runtime Pin Compatibility
# 4. Every tenant workspace crashed; the canary tenant caught it but
# only after 5 hours of degraded staging
#
# Two jobs run independently:
# 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
#
# - pypi-latest-install: installs the CURRENTLY PUBLISHED runtime from
# PyPI on top of workspace/requirements.txt. Catches upstream PyPI
# yanks, bad re-releases, and our own already-shipped wheel that
# stops importing because a transitive dep moved underneath. This is
# what the daily cron exercises.
#
# - local-build-install: builds a wheel from THIS PR's workspace/
# directory using scripts/build_runtime_package.py (mirroring
# publish-runtime.yml exactly), installs that wheel, then imports.
# Closes the chicken-and-egg: a PR that adds a new import requiring
# a2a-sdk 1.5 would previously slip through (CI installs the OLD
# PyPI wheel that doesn't have the new import → smoke passes →
# merge → publish-runtime.yml ships the broken wheel → tenant
# images all crash on next boot). The local-build job tests the
# artifact that WOULD be published, not the artifact already on PyPI.
# 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:
# pypi-latest job is sensitive only to pin/workflow changes —
# the upstream artifact doesn't change with workspace/ edits.
# local-build job is sensitive to anything that changes the wheel.
# Listing the union here means both jobs evaluate; each job's
# internal logic decides whether to do real work.
- 'workspace/**'
- 'scripts/build_runtime_package.py'
# 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/**'
- 'scripts/build_runtime_package.py'
- '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
Expand Down Expand Up @@ -95,50 +89,3 @@ jobs:
WORKSPACE_ID: 00000000-0000-0000-0000-000000000001
run: |
/tmp/venv/bin/python -c "from molecule_runtime.main import main_sync; print('runtime imports OK')"

local-build-install:
# Builds the wheel from THIS PR's workspace/ + scripts/ and tests
# IT — the artifact that WOULD be published if this PR merges. The
# PyPI-latest job above only catches problems with the
# already-published artifact; this job catches problems introduced
# by the PR itself.
#
# No cron schedule: the same pre-merge run already covered the
# commit, and re-running daily wouldn't surface anything new
# (workspace/ doesn't change between cron firings unless a PR
# already passed this gate).
name: PR-built wheel + 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 build tooling
run: pip install build
- name: Build wheel from PR source (mirrors publish-runtime.yml)
# Use a fixed test version so the wheel filename is predictable.
# Doesn't reach PyPI — this build is local-only for the smoke.
# Keep the build invocation byte-identical with publish-runtime.yml's
# build step so we test the SAME artifact pipeline; if they drift,
# the gate stops catching what publish actually ships.
run: |
python scripts/build_runtime_package.py \
--version "0.0.0.dev0+pin-compat" \
--out /tmp/runtime-build
cd /tmp/runtime-build && python -m build
- name: Install built wheel + workspace requirements
run: |
python -m venv /tmp/venv-built
/tmp/venv-built/bin/pip install --upgrade pip
/tmp/venv-built/bin/pip install /tmp/runtime-build/dist/*.whl
/tmp/venv-built/bin/pip install -r workspace/requirements.txt
/tmp/venv-built/bin/pip show molecule-ai-workspace-runtime a2a-sdk \
| grep -E '^(Name|Version):'
- name: Smoke import the PR-built wheel
env:
WORKSPACE_ID: 00000000-0000-0000-0000-000000000001
run: |
/tmp/venv-built/bin/python -c "from molecule_runtime.main import main_sync; print('PR-built runtime imports OK')"
100 changes: 100 additions & 0 deletions .github/workflows/runtime-prbuild-compat.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: Runtime PR-Built Compatibility

# Companion to `runtime-pin-compat.yml`. That workflow tests what's
# CURRENTLY PUBLISHED on PyPI; this workflow tests what WOULD BE
# PUBLISHED if THIS PR merges.
#
# Why two workflows: the chicken-and-egg #128 fix added a "PR-built
# wheel" job to the original runtime-pin-compat.yml, but both jobs
# shared a `paths:` filter that was the union of their needs
# (`workspace/**`). That meant the PyPI-latest job ran on every doc
# edit even though the upstream PyPI artifact can't change with our
# workspace/ source. Splitting the two means each gets a narrow
# `paths:` filter that matches the inputs it actually depends on.
#
# Catches the failure mode where a PR adds an import requiring a newer
# SDK than `workspace/requirements.txt` pins:
# 1. Pip resolves the existing PyPI wheel + the old SDK pin → smoke
# passes (it imports the OLD main.py from the wheel, not the PR's
# new main.py).
# 2. Merge → publish-runtime.yml ships a wheel WITH the new import.
# 3. Tenant images redeploy → all crash on first boot with
# ImportError.
#
# By building from the PR's source and smoke-importing THAT wheel, we
# fail at PR-time instead of after publish.

on:
push:
branches: [main, staging]
paths:
# Broad filter: this workflow's verdict can change whenever any
# workspace/ source file changes (because the wheel we build is
# produced from those files), or when the build script itself
# changes (it controls the wheel layout).
- 'workspace/**'
- 'scripts/build_runtime_package.py'
- '.github/workflows/runtime-prbuild-compat.yml'
pull_request:
branches: [main, staging]
paths:
- 'workspace/**'
- 'scripts/build_runtime_package.py'
- '.github/workflows/runtime-prbuild-compat.yml'
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]
# No cron: the same pre-merge run already covered the commit, and
# re-running daily wouldn't surface anything new (workspace/ doesn't
# change between cron firings unless a PR already passed this gate).

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
local-build-install:
# Builds the wheel from THIS PR's workspace/ + scripts/ and tests
# IT — the artifact that WOULD be published if this PR merges.
name: PR-built wheel + 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 build tooling
run: pip install build
- name: Build wheel from PR source (mirrors publish-runtime.yml)
# Use a fixed test version so the wheel filename is predictable.
# Doesn't reach PyPI — this build is local-only for the smoke.
# Use the SAME build script with the SAME args as
# publish-runtime.yml's build step. The temp dir path differs
# (`/tmp/runtime-build` here vs `${{ runner.temp }}/runtime-build`
# in publish-runtime.yml — they coincide on ubuntu-latest but
# the call sites are not byte-identical). The smoke import is
# also intentionally narrower than publish's: this gate exists
# to catch SDK-version-import drift specifically; full invariant
# coverage lives in publish-runtime.yml's own pre-PyPI smoke.
run: |
python scripts/build_runtime_package.py \
--version "0.0.0.dev0+pin-compat" \
--out /tmp/runtime-build
cd /tmp/runtime-build && python -m build
- name: Install built wheel + workspace requirements
run: |
python -m venv /tmp/venv-built
/tmp/venv-built/bin/pip install --upgrade pip
/tmp/venv-built/bin/pip install /tmp/runtime-build/dist/*.whl
/tmp/venv-built/bin/pip install -r workspace/requirements.txt
/tmp/venv-built/bin/pip show molecule-ai-workspace-runtime a2a-sdk \
| grep -E '^(Name|Version):'
- name: Smoke import the PR-built wheel
env:
WORKSPACE_ID: 00000000-0000-0000-0000-000000000001
run: |
/tmp/venv-built/bin/python -c "from molecule_runtime.main import main_sync; print('PR-built runtime imports OK')"
Loading