# ============================================================================= # AI Software Factory — clean-clone reproducibility gate (TASK-0012) # # A fresh `git clone` of the Phase 0 branch is driven through the entire # developer runbook end-to-end by scripts/verify-clean-clone.sh: # preflight → install → infra up → wait deps → migrate → seed → verify → # apps up → poll app health → (build gates, skippable) → PASS/FAIL. # # Triggers on pushes to `develop` + manual dispatch. Per the task contract this # blocks Phase 0 sign-off, NOT the pull-request pipeline (which is ci.yml), so # it lives in its own workflow and does not `needs:`/`need:` any ci.yml job. # # The build gates (typecheck/test/lint/test:perf) are already enforced by # ci.yml, so the clean-clone job runs the script with `--skip-build` for CI # speed; its unique value is infra + health + reproducibility. # ============================================================================= name: clean-clone on: push: branches: [develop] workflow_dispatch: # One clean-clone run per ref at a time; a newer push supersedes it. concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: clean-clone: name: Clean-clone runbook (fresh git clone) runs-on: ubuntu-24.04 timeout-minutes: 15 steps: - name: Clone to a scratch dir (never touch the CI checkout) env: GH_TOKEN: ${{ github.token }} run: | set -euo pipefail SCRATCH="$(mktemp -d /tmp/factory-clone-XXXXXX)" # A truly fresh clone of the ref, independent of actions/checkout. git clone --branch "${GITHUB_REF_NAME}" "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "${SCRATCH}" # Hand the scratch dir to the job via a file the next step reads. echo "${SCRATCH}" > /tmp/factory-clone-dir.txt echo "cloned ${GITHUB_REF_NAME} into ${SCRATCH}" - name: Run the clean-clone runbook run: | set -euo pipefail SCRATCH="$(cat /tmp/factory-clone-dir.txt)" # --skip-build: the build gates are enforced by ci.yml; here we prove # the infra + health + reproducibility runbook on a fresh clone. bash "${SCRATCH}/scripts/verify-clean-clone.sh" "${SCRATCH}" --skip-build - name: Confirm no leftover apps-profile containers if: always() run: | set -euo pipefail # The script cleans up its own apps-profile containers on exit; this # is a belt-and-braces assertion that none of the four are left up. LEFTOVER="$(docker ps --filter "name=factory-web" --filter "name=factory-api" \ --filter "name=factory-worker" --filter "name=factory-realtime" \ --format '{{.Names}}' | tr '\n' ' ' || true)" if [ -n "${LEFTOVER}" ]; then echo "leftover apps-profile containers: ${LEFTOVER}" >&2 exit 1 fi echo "no leftover apps-profile containers" - name: Clean up scratch clone if: always() run: rm -rf "$(cat /tmp/factory-clone-dir.txt)" /tmp/factory-clone-dir.txt