From 73f1f0193714add37fee29e27751619bacbbc401 Mon Sep 17 00:00:00 2001 From: "Molecule AI Dev Engineer A (Kimi)" Date: Mon, 22 Jun 2026 04:29:37 +0000 Subject: [PATCH] ci(mcp-plugin-delivery-contract-drift): include workspace-runtime in drift gate Extend the cross-repo drift gate to also fetch and byte-compare molecule-ai-workspace-runtime's vendored copy of contracts/mcp-plugin-delivery.contract.json against core's local copy. The runtime's literal drift caused RCA#2970; adding it closes the SSOT loop between core, template, and runtime. Mirrors the existing template fetch+diff block with the same 404-main fallback and fail-closed behavior. No continue-on-error or bp-required change; the gate remains soak-then-promote per #3080. Closes #3095 Co-Authored-By: Claude --- .../mcp-plugin-delivery-contract-drift.yml | 83 +++++++++++++++++-- 1 file changed, 77 insertions(+), 6 deletions(-) diff --git a/.gitea/workflows/mcp-plugin-delivery-contract-drift.yml b/.gitea/workflows/mcp-plugin-delivery-contract-drift.yml index e78815bd..5223daf0 100644 --- a/.gitea/workflows/mcp-plugin-delivery-contract-drift.yml +++ b/.gitea/workflows/mcp-plugin-delivery-contract-drift.yml @@ -3,11 +3,13 @@ name: mcp-plugin-delivery-contract-drift # Cross-repo drift gate for the MCP-plugin delivery contract (core#3080). # # The contract file contracts/mcp-plugin-delivery.contract.json is the SSOT -# shared between molecule-core (producer side) and -# molecule-ai-workspace-template-claude-code (consumer side). This workflow -# fetches the template's copy via the Gitea raw endpoint and byte-compares it -# against core's local copy. RED if they differ — the two repos must stay -# byte-identical so the drift gate and runtime agree on the same contract. +# shared between molecule-core (producer side), +# molecule-ai-workspace-template-claude-code (consumer side), and +# molecule-ai-workspace-runtime (runtime party; its literal drift caused +# RCA#2970). This workflow fetches the template's and runtime's copies via +# the Gitea raw endpoint and byte-compares each against core's local copy. +# RED if any differ — the three repos must stay byte-identical so the drift +# gate and runtime agree on the same contract. # # ENFORCEMENT GATING: standalone workflow, NOT a job in ci.yml and NOT in # branch protection (soak-then-promote; mirrors sync-providers-yaml.yml). @@ -43,7 +45,7 @@ concurrency: jobs: # bp-required: pending #3080 — soak-then-promote; standalone drift gate, not in branch protection yet. compare: - name: Compare MCP plugin delivery contract against template canonical + name: Compare MCP plugin delivery contract against template and runtime canonicals runs-on: ubuntu-latest timeout-minutes: 6 steps: @@ -117,3 +119,72 @@ jobs: echo "Re-sync: copy molecule-ai-workspace-template-claude-code contracts/mcp-plugin-delivery.contract.json verbatim over $LOCAL." exit 1 fi + + - name: Fetch workspace-runtime contract and byte-compare + env: + AUTO_SYNC_TOKEN: ${{ secrets.AUTO_SYNC_TOKEN }} + API_ROOT: ${{ github.server_url }}/api/v1 + run: | + set -euo pipefail + case "${{ github.event_name }}" in + push|schedule|workflow_dispatch) + is_trusted=true + ;; + pull_request) + if [ "${{ github.event.pull_request.head.repo.fork }}" = "false" ]; then + is_trusted=true + else + is_trusted=false + fi + ;; + *) + is_trusted=true + ;; + esac + if [ -z "${AUTO_SYNC_TOKEN:-}" ]; then + if [ "$is_trusted" = "true" ]; then + echo "::error::AUTO_SYNC_TOKEN secret missing on trusted context (${{ github.event_name }}). Live cross-repo contract-drift detection cannot run." + exit 1 + fi + echo "::warning::AUTO_SYNC_TOKEN secret missing on untrusted fork PR — skipping live cross-repo compare." + exit 0 + fi + REF="${{ github.head_ref || github.ref_name }}" + CANON_URL="${API_ROOT}/repos/molecule-ai/molecule-ai-workspace-runtime/raw/contracts/mcp-plugin-delivery.contract.json?ref=${REF}" + set +e + curl -fsS \ + -H "Authorization: token ${AUTO_SYNC_TOKEN}" \ + "${CANON_URL}" -o /tmp/canonical-runtime-mcp-plugin-delivery.contract.json + curl_status=$? + set -e + if [ "$curl_status" -ne 0 ]; then + if [ "$curl_status" -eq 22 ]; then + echo "::warning::Runtime contract not found on ref ${REF} (HTTP 404); falling back to main." + CANON_URL="${API_ROOT}/repos/molecule-ai/molecule-ai-workspace-runtime/raw/contracts/mcp-plugin-delivery.contract.json?ref=main" + set +e + curl -fsS \ + -H "Authorization: token ${AUTO_SYNC_TOKEN}" \ + "${CANON_URL}" -o /tmp/canonical-runtime-mcp-plugin-delivery.contract.json + curl_status=$? + set -e + if [ "$curl_status" -eq 22 ]; then + echo "::warning::Runtime contract not found on runtime main either (HTTP 404) — expected during bootstrap. Skipping drift check." + exit 0 + fi + if [ "$curl_status" -ne 0 ]; then + echo "::error::Failed to fetch runtime contract from main (exit $curl_status)." + exit 1 + fi + else + echo "::error::Failed to fetch runtime contract (exit $curl_status)." + exit 1 + fi + fi + LOCAL=contracts/mcp-plugin-delivery.contract.json + if diff -u /tmp/canonical-runtime-mcp-plugin-delivery.contract.json "$LOCAL"; then + echo "OK — core's contract is byte-identical to the runtime canonical." + else + echo "::error::core's mcp-plugin-delivery.contract.json DRIFTED from the runtime canonical." + echo "Re-sync: copy molecule-ai-workspace-runtime contracts/mcp-plugin-delivery.contract.json verbatim over $LOCAL." + exit 1 + fi -- 2.52.0