feat(@projects/@magic-civilization): update apricot-run.sh for forge workflow

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Natalie 2026-05-03 04:40:43 -04:00
parent c365f17acd
commit 4048e4930e

View file

@ -1,16 +1,19 @@
#!/usr/bin/env bash
# apricot-run.sh — Isolated build + batch pipeline on apricot.
# apricot-run.sh — Isolated build + batch pipeline on apricot, sourced from forge.
#
# apricot is a multi-tenant RUN host. magic-civilization does NOT develop here —
# any persistent checkouts live under ~/Code/project-buildspace/ and are excluded
# from the autocommit daemon (commits.service). This script keeps even further
# clear and uses ~/.cache/ for the per-run scratch + results:
# Source-of-truth flow: forge → apricot canonical checkout → per-run worktree.
# Plum is NOT in this loop. Agents push their work via ACS (commits-tray on plum
# pushes every ~5 min), then this script builds the latest origin/main on apricot.
#
# 1. Rsync this EDIT-host source tree to ~/.cache/mc-src-<stamp>/ on apricot.
# 2. Build (cargo) in ~/.cache/mc-src-<stamp>/, target dir stays there (ephemeral).
# 3. Run the batch with RESULTS_DIR under ~/.cache/mc-batches/<stamp>/
# 1. Fetch latest origin/main into the canonical checkout
# (~/Code/project-buildspace/magic-civilization, hard-fenced via pre-commit hook).
# 2. `git worktree add` a per-run scratch tree at ~/.cache/mc-src-<stamp>/
# (shared object pool with canonical, isolated working tree, fast + reproducible).
# 3. Build (cargo) in the worktree, target dir stays there (ephemeral).
# 4. Run the batch with RESULTS_DIR under ~/.cache/mc-batches/<stamp>/
# (persistent, XDG cache convention, flatpak-visible via --filesystem=home).
# 4. Fetch verdict JSON back to EDIT host for review.
# 5. Fetch verdict JSON back to EDIT host for review.
# 6. Remove the worktree (canonical + objects retained for next run).
#
# Usage:
# scripts/apricot-run.sh smoke [seeds=10] [turns=300]
@ -20,6 +23,8 @@
# Environment:
# APRICOT_SSH_ALIAS — ssh alias for the RUN host (default: apricot).
# STAMP — override the timestamp (for reproducing a specific run).
# BUILD_REF — git ref to build (default: origin/main). Lets you reproduce
# a prior run by SHA without changing your local plum tree.
set -euo pipefail
@ -92,8 +97,9 @@ export RAYON_NUM_THREADS
# Source + build scratch lives under $HOME/.cache (flatpak-visible via
# --filesystem=home). /tmp was tried first but flatpak's sandbox can't see
# /tmp, so Godot rejected the --path argument with "Invalid project path".
# $HOME/.cache/ still satisfies the apricot-isolation rule (not under ~/Code,
# not shared with other devs) and is convention-cleanable.
# $HOME/.cache/ also satisfies the apricot-isolation rule (not under ~/Code/@projects,
# not under project-buildspace where the canonical checkout lives) and is
# convention-cleanable.
SCRATCH="\$HOME/.cache/mc-src-${STAMP}" # expanded on apricot
RESULTS="\$HOME/.cache/mc-batches/${STAMP}" # expanded on apricot
@ -101,11 +107,19 @@ RESULTS="\$HOME/.cache/mc-batches/${STAMP}" # expanded on apricot
SCRATCH_ABS="$(ssh "${APRICOT}" "echo \$HOME/.cache/mc-src-${STAMP}")"
RESULTS_ABS="$(ssh "${APRICOT}" "echo \$HOME/.cache/mc-batches/${STAMP}")"
# Canonical checkout: persistent clone of magicciv from forge, lives in the
# autocommit-excluded buildspace dir. Worktrees branch off this for per-run
# scratch trees with shared object pool — fast + reproducible.
CANONICAL_ABS="$(ssh "${APRICOT}" "echo \$HOME/Code/project-buildspace/magic-civilization")"
BUILD_REF="${BUILD_REF:-origin/main}"
echo "============================================================"
echo "apricot-run.sh mode=${MODE} stamp=${STAMP}"
echo " EDIT host: $(hostname)"
echo " RUN host: ${APRICOT}"
echo " SCRATCH: ${SCRATCH_ABS} (per-run source + build scratch)"
echo " CANONICAL: ${CANONICAL_ABS} (persistent clone of forge)"
echo " BUILD_REF: ${BUILD_REF}"
echo " SCRATCH: ${SCRATCH_ABS} (per-run worktree, ephemeral)"
echo " RESULTS: ${RESULTS_ABS} (persistent batch output)"
echo " PARALLEL: ${PARALLEL_EFFECTIVE} (source: ${PARALLEL_SOURCE})"
echo " RAYON_NUM_THREADS/instance: ${RAYON_NUM_THREADS} (source: ${RAYON_SOURCE})"
@ -113,17 +127,24 @@ echo " Total CPU saturation: ${PARALLEL_EFFECTIVE} × ${RAYON_NUM_THREADS} = $(
echo " AI_GPU_ROLLOUT: ${AI_GPU_ROLLOUT:-true (default on for smoke/clan)}"
echo "============================================================"
# ── Step 1: rsync EDIT → SCRATCH ─────────────────────────────────────────────
echo "[$(date +%H:%M:%S)] rsync EDIT source → ${SCRATCH_ABS}..."
rsync -a --delete \
--exclude='.git' \
--exclude='.local/build' \
--exclude='.local/iter' \
--exclude='.local/batches' \
--exclude='node_modules' \
--exclude='target' \
--exclude='*.dylib' \
"${PROJECT_DIR}/" "${APRICOT}:${SCRATCH_ABS}/"
# ── Step 1: fetch forge → canonical → per-run worktree ───────────────────────
# Source flow is forge → canonical → worktree. Plum is NOT in this path; agents
# push via ACS (commits-tray on plum pushes every ~5 min). To test a specific
# SHA, set BUILD_REF=<sha> in the environment.
echo "[$(date +%H:%M:%S)] fetch origin in canonical, then worktree ${BUILD_REF}${SCRATCH_ABS}..."
ssh "${APRICOT}" "set -euo pipefail; \
test -d '${CANONICAL_ABS}/.git' || { \
echo 'ERROR: canonical checkout missing at ${CANONICAL_ABS}' >&2; \
echo 'one-time setup: git clone http://forge.black.local:3000/magicciv/magicciv.git ${CANONICAL_ABS}' >&2; \
echo 'then: git -C ${CANONICAL_ABS} config core.hooksPath \$HOME/Code/project-buildspace/.hooks' >&2; \
exit 1; \
}; \
git -C '${CANONICAL_ABS}' fetch origin --quiet; \
git -C '${CANONICAL_ABS}' worktree add --detach '${SCRATCH_ABS}' '${BUILD_REF}'"
# Resolve the actual SHA we built (BUILD_REF may be a branch name).
BUILT_SHA="$(ssh "${APRICOT}" "git -C '${SCRATCH_ABS}' rev-parse --short HEAD")"
echo " built SHA: ${BUILT_SHA}"
# ── Step 2: build + deploy via build-gdext.sh ────────────────────────────────
# Canonical build script: runs `cargo build --release --target x86_64-unknown-linux-gnu`
@ -277,7 +298,14 @@ echo "[$(date +%H:%M:%S)] fetch verdict/summary to ${LOCAL_RESULTS}..."
scp -r "${APRICOT}:${RESULTS_ABS}/" "${LOCAL_RESULTS}/" 2>/dev/null || \
echo "WARN: scp returned non-zero; check manually on ${APRICOT}:${RESULTS_ABS}"
# ── Step 6: prune old local copies — keep only the 3 most recent ─────────────
# ── Step 6: remove the per-run worktree ──────────────────────────────────────
# Canonical .git/ + objects retained for the next run. Working tree + cargo
# target dir are gone. RESULTS dir under ~/.cache/mc-batches/ is untouched.
echo "[$(date +%H:%M:%S)] remove worktree ${SCRATCH_ABS}..."
ssh "${APRICOT}" "git -C '${CANONICAL_ABS}' worktree remove --force '${SCRATCH_ABS}' 2>&1 || \
rm -rf '${SCRATCH_ABS}'"
# ── Step 7: prune old local copies — keep only the 3 most recent ─────────────
ITER_ROOT="${PROJECT_DIR}/.local/iter"
if [[ -d "${ITER_ROOT}" ]]; then
# List apricot-* dirs newest-first, skip the first 3, delete the rest.