fix(cial-push): fetch + reset before rsync to avoid non-fast-forward

Whenever the Forgejo fork advanced after boot-fork.sh cloned it
(e.g. Pull Upstream from the dashboard, or a parallel cial-push from
another harness instance), /cial/data/repo lags the remote. cial-push
would then commit on top of the stale HEAD and the push was rejected
with `! [rejected] main -> main (fetch first)`.

The semantic insight: /cial/data/repo is a *derived view*. The actual
source of truth is /cial/core + /cial/platform — the running tree the
agent edits. Resetting the view to origin/main and rsyncing the
running tree on top produces a clean fast-forward commit that
captures exactly the diff between current fork HEAD and what's in the
running tree.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Eliot MAURICE 2026-05-12 17:59:09 +00:00
parent 893ca512ab
commit 64c1c97fdf

View file

@ -53,6 +53,27 @@ SSH_PORT=$(printf '%s' "$CIAL_REPO_URL" | sed -E 's#^ssh://git@[^:]+:?([0-9]*).*
GIT_SSH_COMMAND="ssh -i $KEY_PATH -o UserKnownHostsFile=$KNOWN_HOSTS -o StrictHostKeyChecking=accept-new -o IdentitiesOnly=yes -p $SSH_PORT"
export GIT_SSH_COMMAND
# git ops run as the cial user.
runs_as_cial() {
if [ "$(id -u)" -eq 1000 ]; then "$@"; else gosu cial:cial "$@"; fi
}
cd "$REPO_DIR" || exit 1
# /cial/data/repo is a DERIVED view — the running tree at /cial/core +
# /cial/platform is the actual source of truth. The fork on Forgejo may have
# advanced ahead of /cial/data/repo (e.g. via a Pull Upstream from the
# dashboard), in which case a naive `git push` is rejected as non-fast-
# forward. Resetting the local view to origin/main before rsyncing the
# running tree on top guarantees the commit we create is a fast-forward
# from whatever the fork currently has.
log "fetching origin to align local repo with fork HEAD"
runs_as_cial git fetch --quiet origin main 2>>"$LOG" || \
log "WARN: git fetch failed; pushing may still fail with non-fast-forward"
log "resetting /cial/data/repo to origin/main"
runs_as_cial git reset --hard origin/main 2>>"$LOG" || \
log "WARN: git reset --hard origin/main failed"
# Mirror /cial/core and /cial/platform back into the source-of-truth repo.
# Same exclude set as boot-fork.sh so dist/ + node_modules don't leak in.
log "syncing /cial/core/ and /cial/platform/ → $REPO_DIR/"
@ -62,13 +83,6 @@ rsync -a "${RSYNC_EXCLUDES[@]}" /cial/core/ "$REPO_DIR/core/" 2>>"$LOG"
rsync -a "${RSYNC_EXCLUDES[@]}" /cial/platform/ "$REPO_DIR/platform/" 2>>"$LOG" || \
{ log "ERROR: rsync platform → repo failed"; exit 1; }
# git ops run as the cial user.
runs_as_cial() {
if [ "$(id -u)" -eq 1000 ]; then "$@"; else gosu cial:cial "$@"; fi
}
cd "$REPO_DIR" || exit 1
# Configure identity (idempotent).
runs_as_cial git config user.email "agent@${CIAL_INSTANCE_ID:-cial}.cial.local" || true
runs_as_cial git config user.name "Cial Agent" || true