Skip to content

Sync from upstream + auto-regen intarweb-dev #586

Sync from upstream + auto-regen intarweb-dev

Sync from upstream + auto-regen intarweb-dev #586

Workflow file for this run

name: Sync from upstream + auto-regen intarweb-dev
on:
schedule:
- cron: '0 * * * *' # hourly wakeup. ACTUAL sync work is gated by a runtime cadence
# check (vars.SYNC_CADENCE_HOURS, default=1). GitHub does NOT
# allow expression substitution in on.schedule.cron — confirmed
# via docs + empirical: 22 fleet forks all use literal crons.
# So cadence is a GATE inside the job, not a schedule swap.
# Dead upstreams set SYNC_CADENCE_HOURS=168 (weekly) etc.
workflow_dispatch:
workflow_call: # invoked by fold-on-push.yml when a PR head branch is pushed
# (push event on intarweb-side feat/*, fix/*, test/*, docs/* etc).
# workflow_call bypasses the cadence gate — pushes always rebuild.
permissions:
actions: write # REQUIRED — the workflow_dispatch publish-trigger step 403s without it (honest-fact #27)
contents: write
pull-requests: read
# One sync at a time per fork. Without this, a workflow_dispatch and a schedule
# tick can race — both fold cleanly, both attempt force-with-lease push, one
# wins, the loser fails the push with "failed to push some refs" and emits a
# false-failure alert. Concurrency group serializes them; cancel-in-progress
# false keeps the earlier run going (don't waste the cherry-pick work).
# Burned 2026-06-10 during fleet rollout on vllm-jukebox.
concurrency:
group: sync-upstream-${{ github.repository }}
cancel-in-progress: false
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: 🤖 Mint org-bot app token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ vars.SYNC_APP_ID }}
private-key: ${{ secrets.SYNC_APP_PRIVATE_KEY }}
- name: 📥 Checkout fork
uses: actions/checkout@v4
with:
fetch-depth: 0
# Org-wide GitHub App token (1h short-lived, auto-rotated).
# Has workflows:write so it CAN push under .github/workflows/ —
# GITHUB_TOKEN can't (honest-fact #26). Replaces per-repo
# SYNC_WORKFLOW_TOKEN PATs campaign-wide (honest-fact #53).
token: ${{ steps.app-token.outputs.token }}
- name: ⏱️ Cadence gate (skip schedule wakeup if too soon)
id: cadence
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
# Per-fork cadence config: vars.SYNC_CADENCE_HOURS (default 1, i.e. every hourly
# wakeup runs). Increase for dead/slow upstreams: 24=daily, 168=weekly.
# Gate only suppresses SCHEDULE events — workflow_dispatch and workflow_call
# always run regardless of cadence (those are explicit asks).
#
# last_sync is derived live from `gh run list` (no persisted state needed),
# filtered to successful runs of this workflow. The current run is in-progress,
# so it doesn't count toward "last success".
set -euo pipefail
CADENCE="${{ vars.SYNC_CADENCE_HOURS || '1' }}"
EVENT="${{ github.event_name }}"
if [ "$EVENT" != "schedule" ]; then
echo " cadence gate: event=$EVENT (non-schedule) → bypass gate, running"
echo "skip=false" >> "$GITHUB_OUTPUT"
exit 0
fi
LAST=$(gh run list --workflow sync-upstream.yml --status success --limit 1 \
--json createdAt --jq '.[0].createdAt // ""')
if [ -z "$LAST" ]; then
echo " cadence gate: no prior successful sync — running"
echo "skip=false" >> "$GITHUB_OUTPUT"
exit 0
fi
NOW=$(date -u +%s)
LAST_TS=$(date -u -d "$LAST" +%s)
AGE_H=$(( (NOW - LAST_TS) / 3600 ))
if [ "$AGE_H" -ge "$CADENCE" ]; then
echo " cadence gate: last sync ${AGE_H}h ago ≥ cadence ${CADENCE}h → running"
echo "skip=false" >> "$GITHUB_OUTPUT"
else
echo " cadence gate: last sync ${AGE_H}h ago < cadence ${CADENCE}h → skipping wakeup"
echo "skip=true" >> "$GITHUB_OUTPUT"
fi
- name: ⚙️ Configure git identity
if: steps.cadence.outputs.skip != 'true'
run: |
git config user.email "actions@github.com"
git config user.name "intarweb sync bot"
- name: 🔗 Add upstream remote
if: steps.cadence.outputs.skip != 'true'
run: git remote add upstream https://github.com/yzfly/mcp-python-interpreter.git
- name: 🔄 Fetch upstream + all fork branches
if: steps.cadence.outputs.skip != 'true'
run: |
git fetch upstream main --tags
git fetch origin --prune
- name: 🔁 Hard-reset default branch to upstream + re-apply ops overlay
if: steps.cadence.outputs.skip != 'true'
run: |
# Burned 2026-06-09 with intarweb/bifrost: `git rebase upstream/dev`
# PRESERVES commits on our default branch that aren't on upstream —
# so when upstream FORCE-PUSHED and dropped 23 commits (a half-baked
# modelcatalogresolver plugin with incomplete go.sum), those commits
# got TRAPPED on intarweb/bifrost/main forever. Build started failing
# because go.sum referenced packages upstream had since removed.
# Honest-fact #62 (and vllm-bot diagnosis in claude/forker-queue/).
#
# Fix: hard-reset to upstream. Accept upstream's history as authoritative.
# Then re-apply our 4 workflow files + FORK_INFO.md (which legitimately
# live on main so schedules can fire) from the pre-reset working tree.
# This means intarweb/main = upstream/<branch> + exactly N legit ops
# commits — no untracked drift, no force-push survivors.
git checkout main
# Save ops overlay BEFORE the reset
mkdir -p /tmp/ops-overlay/.github/workflows
for F in .github/workflows/sync-upstream.yml \
.github/workflows/build-from-source.yml \
.github/workflows/build-overlay.yml \
.github/workflows/fork-publish.yml \
.github/workflows/update-fork-info.yml \
.github/workflows/fold-on-push.yml \
FORK_INFO.md; do
if [ -f "$F" ]; then
mkdir -p "/tmp/ops-overlay/$(dirname $F)"
cp -p "$F" "/tmp/ops-overlay/$F"
fi
done
# Hard-reset — drops any trapped-from-force-push commits
git reset --hard upstream/main
# Restore ops overlay
for F in .github/workflows/sync-upstream.yml \
.github/workflows/build-from-source.yml \
.github/workflows/build-overlay.yml \
.github/workflows/fork-publish.yml \
.github/workflows/update-fork-info.yml \
.github/workflows/fold-on-push.yml \
FORK_INFO.md; do
if [ -f "/tmp/ops-overlay/$F" ]; then
mkdir -p "$(dirname $F)"
cp -p "/tmp/ops-overlay/$F" "$F"
fi
done
if ! git status --porcelain -- .github/workflows FORK_INFO.md | grep -q .; then
echo " no ops overlay to re-apply (none existed pre-reset)"
else
git add -A .github/workflows
[ -f FORK_INFO.md ] && git add FORK_INFO.md
git commit -m "ci: re-apply ops overlay after hard-reset to upstream/main"
fi
git push --force-with-lease origin main
- name: 🔍 Discover open PRs from intarweb to upstream
id: prs
if: steps.cadence.outputs.skip != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Use GitHub's search/issues API instead of paginating /pulls?state=open.
# The old approach paginated EVERY open PR on upstream then jq-filtered
# client-side: on NousResearch/hermes-agent (MEASURED 13,295 open PRs
# 2026-06-10), that's 133 API calls per sync just to find our 1-2.
# search/issues with `author:terafin` gives the answer in 1 call.
#
# Caveats verified MEASURED on intarweb/vllm 2026-06-10 (6/6 parity vs
# paginate):
# - All intarweb-authored upstream PRs are by `terafin` today. If a
# co-contributor opens one, broaden the author qualifier OR fall
# back to a per-PR head.repo.owner.login == intarweb verification.
# - search/issues doesn't return head.ref; we fetch it per result
# (N small extra calls, where N = our PR count, typically 1-6).
# - The result set is far below search API's 1000-result cap.
#
# Defensive: after the search, re-verify each PR's head.repo.owner.login
# before adding. Drops anything that shouldn't be cherry-picked even if
# search returns extras.
# SEMANTIC CONTRACT: this filter is `author:<user>` (PRs THAT user authored,
# from anywhere), NOT `head:<org>` (PRs from any author whose branch lives
# in that org). GitHub's search API has no head-org qualifier; only REST
# /pulls supports head=user:branch (literal, no wildcard). These two
# filters coincide TODAY because every intarweb PR is both terafin-authored
# AND from an intarweb branch, but they diverge the first time a
# co-contributor opens a PR from an intarweb branch under a different
# account — that PR would be silently MISSED by this discovery.
#
# Defense: the per-PR re-check below enforces head.repo.owner.login ==
# ${{ github.repository_owner }}, so the search can never accept a PR from
# the wrong head repo. It just can't see beyond the author qualifier.
#
# vars.SYNC_PR_AUTHOR override: defaults to `terafin` (current sole author).
# If a co-contributor joins, set this var to a space-separated list and the
# query expands. Empty value → fall back to defensive: full /pulls scan
# (slow, accurate). Honest-fact #65.
PR_AUTHORS="${{ vars.SYNC_PR_AUTHOR || 'terafin' }}"
: > /tmp/pr-nums.txt
if [ -z "$PR_AUTHORS" ]; then
# Fallback: paginate /pulls and filter client-side. Slow on big upstreams
# but provably complete.
gh api --paginate "repos/yzfly/mcp-python-interpreter/pulls?state=open&per_page=100" \
--jq '.[] | select(.head.repo.owner.login == "${{ github.repository_owner }}") | .number' \
>> /tmp/pr-nums.txt
else
for AUTH in $PR_AUTHORS; do
gh api "search/issues?q=repo:yzfly/mcp-python-interpreter+is:pr+is:open+author:${AUTH}&per_page=100" \
--jq '.items[].number' >> /tmp/pr-nums.txt
done
sort -u /tmp/pr-nums.txt -o /tmp/pr-nums.txt
fi
: > /tmp/prs.txt
while read -r num; do
[ -z "$num" ] && continue
META=$(gh api "repos/yzfly/mcp-python-interpreter/pulls/$num" \
--jq '"\(.head.repo.owner.login)|\(.head.ref)|\(.title)"' 2>/dev/null)
OWN="${META%%|*}"
REST="${META#*|}"
REF="${REST%%|*}"
TITLE="${REST#*|}"
if [ "$OWN" != "${{ github.repository_owner }}" ]; then
echo " - skipping PR #$num — head.repo.owner=$OWN (expected ${{ github.repository_owner }})"
continue
fi
echo "$num $REF $TITLE" >> /tmp/prs.txt
done < /tmp/pr-nums.txt
sort -n -o /tmp/prs.txt /tmp/prs.txt
if [ ! -s /tmp/prs.txt ]; then
echo " No open PRs from ${{ github.repository_owner }} to upstream — intarweb-dev will == main"
else
echo " Open PRs to cherry-pick onto intarweb-dev:"
sed 's/^/ /' /tmp/prs.txt
fi
- name: 🚨 Warn on intarweb-dev workflow drift (about to be wiped)
# The regen step below does `git checkout -B intarweb-dev main`
# which OVERWRITES intarweb-dev with main's tree, then re-cherry-picks
# the open-PR set. Any workflow edits made directly to intarweb-dev that
# aren't in main AND aren't in an open PR's cherry-pick set get SILENTLY
# WIPED here.
#
# Live burn 2026-06-11 on intarweb/vllm: prior agent committed
# `f1bdf3e33` (TORCH_CUDA_ARCH_LIST trim + 720min timeout) to
# intarweb-dev directly. The next sync regen wiped it without alarm; six
# subsequent build attempts ran with the stale 3-arch list, all
# cancelled at the 360-min wall. Honest-fact #97.
#
# The wipe IS the feature (uniformity contract). The silence is the
# bug. This step makes it visible BEFORE the wipe runs: yellow
# ::warning:: in the Actions UI + diff in the run log. Operator sees
# "I edited intarweb-dev directly and the sync is about to undo it"
# and can re-edit on main (where it survives via the ops-overlay
# save/restore above).
if: steps.cadence.outputs.skip != 'true'
run: |
git fetch origin intarweb-dev 2>/dev/null || {
echo " (no remote intarweb-dev yet — first sync, nothing to wipe)"
exit 0
}
ANY_DRIFT=0
for F in .github/workflows/sync-upstream.yml \
.github/workflows/build-from-source.yml \
.github/workflows/build-overlay.yml \
.github/workflows/fork-publish.yml \
.github/workflows/update-fork-info.yml \
.github/workflows/fold-on-push.yml \
FORK_INFO.md; do
# Get both sides; skip cleanly if either lacks the file.
MAIN_BLOB=$(git show "HEAD:$F" 2>/dev/null || echo "")
DEV_BLOB=$(git show "origin/intarweb-dev:$F" 2>/dev/null || echo "")
if [ -z "$MAIN_BLOB" ] && [ -z "$DEV_BLOB" ]; then
continue
fi
if [ "$MAIN_BLOB" = "$DEV_BLOB" ]; then
continue
fi
ANY_DRIFT=1
echo "::warning::ops-overlay restore will wipe intarweb-dev's $F — differs from main."
echo " If you intended this drift to persist across syncs, commit it to MAIN."
echo " Diff (intarweb-dev → main, head -20):"
diff <(echo "$DEV_BLOB") <(echo "$MAIN_BLOB") 2>/dev/null | head -20 | sed 's/^/ /'
echo ""
done
if [ "$ANY_DRIFT" = "0" ]; then
echo " ✓ no intarweb-dev ops-overlay drift detected"
fi
- name: 🌿 Regenerate intarweb-dev = main + open-PR cherry-picks
id: regen
if: steps.cadence.outputs.skip != 'true'
# FORK_CARRIED_COMMITS step (below the PR loop) calls `gh api` to
# check carrier-PR / upstream-PR state. GITHUB_TOKEN read scope is
# sufficient — we only read PR state, never write here.
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git checkout -B intarweb-dev main
while read num branch title; do
[ -z "$num" ] && continue
echo "::group::PR #$num — $branch ($title)"
git fetch origin "$branch" || { echo " ✗ failed to fetch origin/$branch"; exit 1; }
# ── Precompiled-wheel guard: SKIP PRs that touch compiled-code files ──
# On precompiled-wheel forks (PRECOMPILED_WHEEL_BASE_URL set) the
# runtime image is an UPSTREAM-prebuilt wheel; csrc/CUDA/kernels
# binaries cannot be relinked at runtime. Carrying a PR that edits
# compiled code would layer Python on a stale .so and silently
# produce wrong binaries — and the post-cherry-pick carry-drift
# guard (below) would then FAIL-CLOSE the whole sync, blocking ALL
# carries (including unrelated Python-only ones). This EARLY skip
# drops only the offending PR via `gh pr files`, BEFORE cherry-pick,
# so the Python carries still land. Logs each skip loudly.
#
# The extension set + path prefixes are kept BYTE-IDENTICAL to the
# carry-drift guard (search ".(cu|cuh|...)") so a PR that passes
# this skip can never trip the guard, and vice-versa.
#
# Belt-and-suspenders: PRECOMPILED_WHEEL_SKIP_PRS (space-separated
# PR numbers) force-skips a PR even if its file query is flaky.
# General rule above is primary; the explicit list is a fallback.
#
# Gated on vars.PRECOMPILED_WHEEL_BASE_URL → byte-identical no-op on
# the 21 source-build forks where that Variable is unset.
if [ -n "${{ vars.PRECOMPILED_WHEEL_BASE_URL }}" ]; then
FORCE_SKIP=" ${{ vars.PRECOMPILED_WHEEL_SKIP_PRS || '' }} "
if [ "$FORCE_SKIP" != " " ] && printf '%s' "$FORCE_SKIP" | grep -qw "$num"; then
echo "::warning::skipping PR #$num — listed in PRECOMPILED_WHEEL_SKIP_PRS (operator force-skip)"
echo "::endgroup::"
continue
fi
PR_FILES=$(gh api --paginate "repos/yzfly/mcp-python-interpreter/pulls/$num/files?per_page=100" \
--jq '.[].filename' 2>/dev/null || true)
COMPILED=$(printf '%s\n' "$PR_FILES" \
| grep -iE '\.(cu|cuh|cpp|cxx|cc|c|hpp|hxx|hh|h|pyx|pxd|s|S)$|^(csrc|kernels)/' || true)
if [ -n "$COMPILED" ]; then
echo "::warning::skipping PR #$num — touches compiled code, cannot carry into precompiled-wheel fork: $(printf '%s' "$COMPILED" | tr '\n' ' ')"
echo "$COMPILED" | sed 's/^/ /'
echo "::endgroup::"
continue
fi
fi
# Range "intarweb-dev..origin/$branch" = commits on branch not yet on intarweb-dev.
# As we apply more PRs, intarweb-dev grows; later branches only contribute their NEW commits.
# If a PR was merged upstream, its commits are now on main (and thus intarweb-dev), so this is empty.
COMMITS=$(git log --reverse --format=%H "intarweb-dev..origin/$branch")
if [ -z "$COMMITS" ]; then
echo " - no unique commits — already on intarweb-dev (likely merged upstream); skipping"
else
for c in $COMMITS; do
# -X theirs: when a PR's content is a superset of an earlier PR's content
# (common when PRs are stacked), take the cherry-picked version. Honest-fact #54.
# -m 1: tolerate upstream-merge-commits (honest-fact #45).
# --allow-empty --keep-redundant-commits: tolerate the no-op case where the
# commit's changes are already present (e.g. via another PR's superset).
if ! git cherry-pick -X theirs -m 1 --allow-empty --keep-redundant-commits "$c" 2>/dev/null; then
# FAIL-CLOSED (changed 2026-06-10, replacing Heal C silent-drop).
# The previous behavior — `git cherry-pick --abort; break; continue with next PR`
# silently dropped the conflicting PR and kept publishing :latest WITHOUT it.
# Consumers pinning :latest had no signal that PR #N was being silently
# excluded. New behavior: FAIL THE JOB. Subsequent steps (force-push,
# build dispatch) do not run. The previous :latest stays in place, serving.
# Operator notification: ::error:: annotation in the run, the run shows
# red in the actions tab, and portfolio-audit's daily digest catches
# sync_conclusion=="failure" (portfolio-audit.yml line 147 "FAILED_SYNC").
# Operator must manually rebase the offending PR head branch and force-push
# it before the next sync will succeed.
echo "::error::FOLD FAILED — PR #$num cherry-pick conflict on $c survived -X theirs. intarweb-dev WILL NOT be advanced; :latest remains at last-good. Rebase $branch onto upstream/main + push to recover."
git cherry-pick --abort || true
exit 1
fi
done
echo " ✓ applied $(echo "$COMMITS" | wc -w) commits from PR #$num"
fi
echo "::endgroup::"
done < /tmp/prs.txt
# FORK_CARRIED_COMMITS — re-apply long-lived fork-carried patches
# that aren't bound to an OPEN PR's lifecycle. Honest-fact #98.
#
# Why this exists: the open-PR cherry-pick loop above only re-applies
# commits that live on terafin-authored OPEN PRs. If the carrier PR
# closes (unmerged OR superseded), the cherry-pick stops happening
# next sync and the fork SILENTLY REGRESSES to upstream/main's
# behavior. That's catastrophic for patches we depend on at runtime
# (e.g. cumem accounting fix for KV-OOM-free wakes).
#
# Format (per-fork repo Variable FORK_CARRIED_COMMITS, multi-line,
# one record per line, pipe-separated):
# <commit-sha>|<upstream-pr-to-watch>|<optional-carrier-pr>|<optional-disposition>
#
# Fields:
# commit-sha short or long SHA on the fork's working tree
# upstream-pr-to-watch PR # in upstream that, when MERGED, makes
# this patch redundant. Step emits a yellow
# WARNING when merged (operator should drop
# the entry); harmless empty cherry-pick if
# left in (upstream's version is already in
# the hard-reset main, so cherry-pick is no-op).
# carrier-pr optional. PR # under our fork that hosts
# this rebase. If carrier is CLOSED-UNMERGED,
# this step FAILS LOUDLY rather than silently
# dropping the patch — UNLESS disposition is
# skip-on-conflict (see below).
# disposition optional. Default `fail-closed` (current
# behavior — used for OUR PRs that we own and
# are responsible for rebasing). Set to
# `skip-on-conflict` for SPECULATIVE third-
# party carries (PRs from other authors that
# we ride for early bug coverage). Behavior on
# conflict OR carrier-closed-unmerged:
# - fail-closed: emit ::error::, abort sync,
# :latest stays at last-good. Operator
# must intervene.
# - skip-on-conflict: emit ::warning::, drop
# the carry this run, continue regen with
# remaining carries. Wheel-resolver still
# runs. Builds advance with reduced
# coverage. Re-attempts next sync if the
# upstream PR rebases. Honest-fact #100.
#
# When to use skip-on-conflict: a PR from a third-party author you
# don't have rebase-rights on. Silently dropping is the SAME outcome
# as "we never picked it up" — strictly safer than blocking the whole
# pipeline on a carry we don't own.
#
# Examples (intarweb/vllm at 2026-06-12):
# # Our PRs — fail-closed (default, current behavior)
# c9427de62|37111|45208 # cumem OOM fix; we own #45208
# 88af8e6b0|45097 # /health/decode; we own #45097
#
# # Third-party speculative — skip-on-conflict
# 54a52c948|45268|45326|skip-on-conflict # waynehacking8's hang fix
# f61febf66|45268|45363|skip-on-conflict # AlejandroParedesLT's drain fix
#
# Comments (lines starting with #) and blank lines are skipped.
if [ -n "${{ vars.FORK_CARRIED_COMMITS }}" ]; then
echo "::group::FORK_CARRIED_COMMITS — re-applying long-lived patches"
echo "${{ vars.FORK_CARRIED_COMMITS }}" > /tmp/fork-carried.txt
while IFS='|' read -r CSHA UPSTREAM_PR CARRIER_PR DISPOSITION; do
CSHA="$(echo "$CSHA" | xargs)"
UPSTREAM_PR="$(echo "$UPSTREAM_PR" | xargs)"
CARRIER_PR="$(echo "$CARRIER_PR" | xargs)"
DISPOSITION="$(echo "${DISPOSITION:-}" | xargs)"
# Skip blanks + comments
[ -z "$CSHA" ] && continue
case "$CSHA" in \#*) continue ;; esac
# Default disposition: fail-closed (preserves prior behavior for
# all existing 3-column entries). Only `skip-on-conflict` enables
# the new degraded-but-non-blocking path.
[ -z "$DISPOSITION" ] && DISPOSITION="fail-closed"
# Check carrier-PR state (if specified). On closed-unmerged:
# - fail-closed → fail loudly (silent-regression class the
# mechanism exists to prevent for OWNED carries).
# - skip-on-conflict → warn + drop (third-party PRs we don't
# own; same outcome as never picking it up; safer than
# blocking the pipeline). Operator should remove the entry
# when convenient.
#
# On open-and-rebased: AUTO-REFRESH the cherry-pick SHA to the
# carrier PR's CURRENT head. The most common stale-SHA failure
# mode in this whole subsystem is "carrier PR rebased
# upstream-side, pinned SHA in FORK_CARRIED_COMMITS now points
# at a commit that's been GC'd or whose parent moved, cherry-
# pick fails or applies the wrong content" — burned 2026-06-12
# on intarweb/vllm with PR #45453 (head moved 85129770b →
# 24020531f after a rebase, pinned SHA collided with the open-
# PR auto-cherry-pick loop). Resolving live each sync makes
# this self-healing for owned carriers and surfaces it for
# third-party. fetch-then-resolve so the local repo has the
# commit; fall back to pinned SHA if API query fails (network
# blip or PR temporarily unreachable).
if [ -n "$CARRIER_PR" ]; then
CARRIER_META=$(gh api "repos/yzfly/mcp-python-interpreter/pulls/$CARRIER_PR" \
--jq '"\(.state)|\(.merged)|\(.head.sha)"' 2>/dev/null || echo "unknown||")
C_STATE="${CARRIER_META%%|*}"
C_REST="${CARRIER_META#*|}"
C_MERGED="${C_REST%%|*}"
C_HEAD="${C_REST#*|}"
if [ "$C_STATE" = "closed" ] && [ "$C_MERGED" != "true" ]; then
if [ "$DISPOSITION" = "skip-on-conflict" ]; then
echo "::warning::FORK_CARRIED_COMMITS: speculative carry $CSHA — carrier PR #$CARRIER_PR is CLOSED-UNMERGED. Skipping this run (disposition=skip-on-conflict). Remove the entry from FORK_CARRIED_COMMITS when convenient."
continue
fi
echo "::error::FORK_CARRIED_COMMITS: carrier PR #$CARRIER_PR for commit $CSHA is CLOSED-UNMERGED. Without intervention this patch would silently drop from the next image. ABORTING sync to surface the regression."
echo "::error:: Fix: (a) re-open #$CARRIER_PR and rebase, OR (b) file a new carrier PR and update FORK_CARRIED_COMMITS to point at it, OR (c) if the patch is genuinely no-longer-needed, remove the entire entry from FORK_CARRIED_COMMITS, OR (d) if this is a speculative third-party carry you don't own, change disposition to skip-on-conflict."
exit 1
fi
# Auto-refresh SHA when carrier is open + rebased. Normalizes
# both pinned + resolved to long-form for prefix-safe compare
# (pinned is often abbreviated, resolved is always 40-char).
if [ "$C_STATE" = "open" ] && [ -n "$C_HEAD" ]; then
CSHA_PREFIX_LEN=${#CSHA}
C_HEAD_PREFIX="${C_HEAD:0:$CSHA_PREFIX_LEN}"
if [ "$C_HEAD_PREFIX" != "$CSHA" ]; then
echo "::notice::FORK_CARRIED_COMMITS: carrier PR #$CARRIER_PR head moved $CSHA → $C_HEAD (auto-refresh). Update FORK_CARRIED_COMMITS at convenience to suppress this notice."
CSHA="$C_HEAD"
# Fetch the new head so cherry-pick can find it (the
# fork's git history may not have it from the earlier
# `git fetch origin --prune`, since carrier branches in
# upstream live on upstream-side). Try upstream remote
# first; if it's an intarweb-side branch, origin already
# has it from the earlier fetch.
git fetch upstream "$C_HEAD" 2>/dev/null || \
git fetch origin "$C_HEAD" 2>/dev/null || \
echo "::warning::FORK_CARRIED_COMMITS: failed to fetch resolved head $C_HEAD for carrier PR #$CARRIER_PR — cherry-pick may fail. Retrying with pinned SHA $CSHA as fallback would mask drift; not falling back."
fi
fi
fi
# Check upstream-PR state (always required) — warn on merged
# (operator should drop the entry; the cherry-pick will be an
# empty no-op below).
UPSTREAM_STATE=$(gh api "repos/yzfly/mcp-python-interpreter/pulls/$UPSTREAM_PR" \
--jq '"\(.state)|\(.merged)"' 2>/dev/null || echo "unknown|")
U_STATE="${UPSTREAM_STATE%%|*}"
U_MERGED="${UPSTREAM_STATE#*|}"
if [ "$U_MERGED" = "true" ]; then
echo "::warning::FORK_CARRIED_COMMITS: upstream PR #$UPSTREAM_PR has MERGED. Commit $CSHA is now redundant — please remove this entry from FORK_CARRIED_COMMITS. Cherry-pick below will no-op."
fi
# Apply (or empty no-op if already present from main or open-PR loop).
if git cherry-pick -X theirs -m 1 --allow-empty --keep-redundant-commits "$CSHA" 2>/dev/null; then
echo " ✓ applied carried commit $CSHA (upstream-pr=$UPSTREAM_PR carrier=$CARRIER_PR disposition=$DISPOSITION)"
else
git cherry-pick --abort || true
if [ "$DISPOSITION" = "skip-on-conflict" ]; then
# Speculative third-party carry rotted (e.g. another upstream
# PR merged that touches the same files). Drop this run; sync
# continues with remaining carries; wheel-resolver runs as
# normal; :latest can still advance for unrelated reasons.
# Re-attempts next sync (author may rebase upstream-side).
echo "::warning::FORK_CARRIED_COMMITS: speculative carry $CSHA (upstream PR #$UPSTREAM_PR) conflicts with current main this cycle — skipping. Re-attempts on next sync after author rebases."
continue
fi
# default: fail-closed. Same posture as the open-PR loop.
echo "::error::FORK_CARRIED_COMMITS: cherry-pick conflict on $CSHA survived -X theirs. intarweb-dev WILL NOT be advanced; :latest remains at last-good. Operator must rebase the carrier (#$CARRIER_PR) or update FORK_CARRIED_COMMITS to a current SHA. (For speculative third-party carries you don't own, set disposition=skip-on-conflict to degrade gracefully instead.)"
exit 1
fi
done < /tmp/fork-carried.txt
echo "::endgroup::"
fi
# Did intarweb-dev's TREE actually change vs the existing remote?
# Compare trees (content), not SHAs (which differ each run because
# cherry-pick rewrites committer timestamps).
if git rev-parse origin/intarweb-dev^{tree} >/dev/null 2>&1; then
OLD_TREE=$(git rev-parse origin/intarweb-dev^{tree})
NEW_TREE=$(git rev-parse intarweb-dev^{tree})
if [ "$OLD_TREE" = "$NEW_TREE" ]; then
echo " - intarweb-dev tree unchanged; skipping push + publish trigger"
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo " - intarweb-dev tree changed; will push + trigger publish"
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
else
echo " - intarweb-dev did not exist on origin; will push + trigger publish"
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
- name: 🛡️ Carry-drift guard (precompiled-wheel forks only)
# Forks that opt into the upstream-prebuilt-wheel build path (via
# PRECOMPILED_WHEEL_BASE_URL Variable) MUST keep their carry stack
# 100% non-compiled. If a cherry-pick or FORK_CARRIED_COMMIT introduces
# a compiled-code file, the fork's Python carries would be layering
# on stale upstream-compiled-`.so`s and produce wrong binaries silently.
# This guard fails the sync loud at the moment of regression rather
# than at runtime. No-op for forks without the master Variable set.
#
# Detected file extensions: .cu, .cuh, .cpp, .cxx, .cc, .c, .hpp, .hxx,
# .hh, .h, .pyx, .pxd, .s, .S (broadened from the initial .cu/.cpp/.h/.cuh
# after architect-review #1 flagged the gap). --diff-filter=AM excludes
# pure deletions and renames so an upstream `.cu` rename doesn't false-fire.
#
# build-system hint files (setup.py / CMakeLists.txt / pyproject.toml /
# *.cmake) emit a WARNING but don't fail — a Python-only carry that
# touches setup.py to register a `build_ext` hook IS a precompiled-path
# invalidator, but most setup.py edits are harmless.
#
# Escape valve: set CARRY_DRIFT_ALLOW=true on the fork to bypass with a
# loud warning (use for one-shot testing of a compiled-code cherry-pick
# under operator supervision; CLEAR THE VARIABLE after).
# Honest-fact #99.
if: steps.cadence.outputs.skip != 'true' && success() && vars.PRECOMPILED_WHEEL_BASE_URL != ''
run: |
set -euo pipefail
DRIFT=$(git diff --name-only --diff-filter=AM "upstream/main..intarweb-dev" \
| grep -iE '\.(cu|cuh|cpp|cxx|cc|c|hpp|hxx|hh|h|pyx|pxd|s|S)$' || true)
BUILD_HINTS=$(git diff --name-only --diff-filter=AM "upstream/main..intarweb-dev" \
| grep -E '(^|/)setup\.py$|(^|/)pyproject\.toml$|CMakeLists\.txt$|\.cmake$' || true)
if [ -n "$BUILD_HINTS" ]; then
echo "::warning::carry stack touches build-system files (setup.py / pyproject.toml / CMake) — review whether they re-enable C++/CUDA compilation:"
echo "$BUILD_HINTS" | sed 's/^/ /'
fi
if [ -n "$DRIFT" ]; then
if [ "${{ vars.CARRY_DRIFT_ALLOW || '' }}" = "true" ]; then
echo "::warning::CARRY-DRIFT detected but CARRY_DRIFT_ALLOW=true is set — proceeding under operator override. CLEAR the variable after this sync:"
echo "$DRIFT" | sed 's/^/ /'
else
# Single retry after 30s — most drift trips are races where a
# carry-bot (vllm-bot et al.) is force-pushing a rebased branch
# mid-sync, so the cherry-picked tree briefly disagrees with the
# upstream HEAD we just fetched. Wait, re-fetch, re-check.
# Honest-fact #112: real-corruption drift persists; race-drift
# resolves on next read. Single retry kills the noise without
# losing the safety net.
echo "::warning::CARRY-DRIFT detected — race-condition possible (carry-bot may be mid-rebase). Retrying in 30s before failing loud:"
echo "$DRIFT" | sed 's/^/ /'
sleep 30
git fetch upstream "main" --quiet
DRIFT=$(git diff --name-only --diff-filter=AM "upstream/main..intarweb-dev" \
| grep -iE '\.(cu|cuh|cpp|cxx|cc|c|hpp|hxx|hh|h|pyx|pxd|s|S)$' || true)
if [ -n "$DRIFT" ]; then
echo "::error::CARRY-DRIFT persisted across 30s retry — this is real, not a race. precompiled-wheel forks require 100% non-compiled carries — these compiled-code files appeared in intarweb-dev:"
echo "$DRIFT" | sed 's/^/ /'
echo "::error::Recovery options (pick one):"
echo "::error:: (a) revert the offending commit and rebase the carry"
echo "::error:: (b) clear PRECOMPILED_WHEEL_BASE_URL to fall back to source build (slow but correct)"
echo "::error:: (c) set CARRY_DRIFT_ALLOW=true on this fork to bypass once under operator override (clear after)"
echo "::error:: (d) test on a feature branch first by clearing PRECOMPILED_WHEEL_BASE_URL temporarily on a fork clone"
exit 1
else
echo " ✓ carry-drift guard cleared on retry — was a transient race"
fi
fi
else
echo " ✓ carry-drift guard clean — no compiled-code carries"
fi
- name: 🎯 Resolve precompiled wheel SHA + variant (precompiled-wheel forks only)
# Writes PRECOMPILED_WHEEL_COMMIT = current upstream HEAD SHA so the
# build workflow's bargs synth step picks it up. Does NOT pre-verify
# the wheel URL — wheels.vllm.ai (and presumably similar wheel CDNs)
# 403 on directory probes, making sync-time availability checks
# impossible without knowing the exact .whl filename convention. The
# real safety net is the fork-side Dockerfile carry's hard fail-loud
# contract (vllm-bot hardening req #3): when VLLM_USE_PRECOMPILED=1
# is set but the wheel fetch fails at build time, the build exits
# non-zero immediately rather than silently falling through to a
# multi-hour source compile. Honest-fact #99/#103.
#
# Updates the PRECOMPILED_WHEEL_VARIANT only if the operator's
# PRECOMPILED_WHEEL_VARIANT_CHAIN suggests a different first-choice
# (no — actually we just trust the operator's VARIANT setting).
# Variant fallback would require build-time re-attempt which the
# Dockerfile carry can implement; the resolver writes single VARIANT.
#
# Freeze mode: if PRECOMPILED_WHEEL_COMMIT_FROZEN=true, the resolver
# skips writes entirely (operator pinned for testing or rollback).
#
# gh variable set wrapped survivable: if the SYNC_APP token lacks
# `Variables: Write` permission, the call 403s but the sync continues
# with a warning rather than hard-failing the entire fork's sync.
# Operator grants the app permission, next sync succeeds.
#
# No-op for forks without the master Variable set. Honest-fact #99/#103.
if: steps.cadence.outputs.skip != 'true' && success() && vars.PRECOMPILED_WHEEL_BASE_URL != ''
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
set -uo pipefail # NOT -e — we handle variable-write failures survivably below
SHA=$(git rev-parse upstream/main)
CUR_COMMIT="${{ vars.PRECOMPILED_WHEEL_COMMIT }}"
FROZEN="${{ vars.PRECOMPILED_WHEEL_COMMIT_FROZEN || '' }}"
CUR_VARIANT="${{ vars.PRECOMPILED_WHEEL_VARIANT }}"
if [ "$FROZEN" = "true" ]; then
echo "::warning::PRECOMPILED_WHEEL_COMMIT_FROZEN=true — skipping wheel-SHA resolution. Pinned to commit=$CUR_COMMIT variant=$CUR_VARIANT."
exit 0
fi
# Helper: survivable variable-set. Echoes the run URL into the audit log.
set_var() {
local name="$1" value="$2"
if gh variable set "$name" -b "$value" 2>&1; then
echo " ✓ set $name=$value (audit: $RUN_URL)"
return 0
else
echo "::warning::failed to write $name (likely SYNC_APP lacks 'Variables: Write' permission — grant via app settings to enable wheel-SHA auto-management). Continuing with prior value."
return 1
fi
}
echo " setting PRECOMPILED_WHEEL_COMMIT=$SHA (variant=$CUR_VARIANT — build-time will fail-loud if wheel not actually published per fork-side Dockerfile carry contract)"
if [ "$CUR_COMMIT" != "$SHA" ]; then
set_var PRECOMPILED_WHEEL_COMMIT "$SHA" || true
echo " → PRECOMPILED_WHEEL_COMMIT: $CUR_COMMIT → $SHA"
else
echo " → PRECOMPILED_WHEEL_COMMIT already at $SHA, no change"
fi
- name: 📤 Force-push intarweb-dev
# Gated on (a) cadence-not-skipped, (b) regen succeeded (implicit via default
# `success()`), (c) tree actually changed. If the cherry-pick loop hit a
# conflict, regen exits 1 → this step does not run → prior intarweb-dev stays
# at last-good → :latest is not republished → fail-closed contract holds.
if: steps.cadence.outputs.skip != 'true' && success() && steps.regen.outputs.changed == 'true'
run: git push --force-with-lease origin intarweb-dev
- name: 🚀 Trigger publish on intarweb-dev
if: steps.cadence.outputs.skip != 'true' && success() && steps.regen.outputs.changed == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Required because GitHub blocks the normal push→workflow cascade
# when the push is authored by GITHUB_TOKEN (anti-loop safety rule).
# workflow_dispatch IS allowed to fire from GITHUB_TOKEN, so we
# explicitly dispatch the publish workflow here. UNIVERSAL name
# — every Model B fork's build workflow is named exactly this
# via the build-from-source.yml template (honest-fact #52).
gh workflow run "Build from source → GHCR" --repo ${{ github.repository }} --ref intarweb-dev || true
- name: ✅ Show final state
if: steps.cadence.outputs.skip != 'true' && success()
run: |
echo " main HEAD: $(git log main --oneline -1)"
echo " intarweb-dev HEAD: $(git log intarweb-dev --oneline -1)"
echo " intarweb-dev commits ahead of upstream/main:"
git log --oneline upstream/main..intarweb-dev | sed 's/^/ /' || true