guanghu-ice-heart/server-tools/persona-team-handshake/deploy-fifth-domain-daily-persona-systems.sh

301 lines
10 KiB
Shell
Executable file

#!/usr/bin/env bash
set -euo pipefail
expected_machine_id="caa7b1019517470f9d1368b6e79db49e"
expected_source_commit="${1:-}"
release_root="$(cd "$(dirname "$0")/../.." && pwd)"
source_commit_file="${release_root}/SOURCE-COMMIT"
state_root="/var/lib/guanghu/personas/guanghu/hlcc-v16.0.1"
repository_root="${state_root}/data/repositories/bingshuo"
runtime_root="/var/lib/guanghu/personas/guanghu/fifth-domain-daily"
receipt_root="/var/lib/guanghu/architecture-provision/receipts"
receipt="${receipt_root}/JD-PERSONA-FIFTH-DOMAIN-DAILY-20260806.json"
archive_root="/var/lib/guanghu/legacy-archives/persona-writers/20260806-fifth-domain-daily"
shared_secret_file="/etc/guanghu/persona-secrets/shared-deepseek.env"
temporary="$(mktemp -d)"
chmod 0711 "$temporary"
backup_root="${temporary}/units"
completed=0
writers=(
chenglu-agent.service
chenglu-daily.timer
guideng-agent.service
kezhou-daily.timer
)
oneshots=(
chenglu-daily.service
kezhou-daily.service
)
handshakes=(
chenglu-team-handshake.service
guideng-team-handshake.service
kezhou-team-handshake.service
)
new_units=(
chenglu-team-handshake.service
guideng-team-handshake.service
kezhou-team-handshake.service
zhuyuan-persona-fifth-domain-daily.service
zhuyuan-persona-fifth-domain-daily.timer
)
declare -A old_repositories=(
[chenglu-agent]="/var/lib/guanghu/forgejo/repositories/bingshuo/chenglu-agent.git"
[guideng]="/var/lib/guanghu/forgejo/repositories/bingshuo/guideng.git"
[kezhou]="/var/lib/guanghu/forgejo/repositories/bingshuo/kezhou.git"
)
restore_units() {
for unit in "${new_units[@]}"; do
if test -f "${backup_root}/${unit}"; then
cp "${backup_root}/${unit}" "/etc/systemd/system/${unit}"
else
rm -f "/etc/systemd/system/${unit}"
fi
done
systemctl daemon-reload
}
rollback() {
systemctl disable --now zhuyuan-persona-fifth-domain-daily.timer \
>/dev/null 2>&1 || true
systemctl stop zhuyuan-persona-fifth-domain-daily.service \
>/dev/null 2>&1 || true
restore_units
if test -f "${temporary}/shared-deepseek.env"; then
cp "${temporary}/shared-deepseek.env" "$shared_secret_file"
chmod 0600 "$shared_secret_file"
fi
systemctl enable --now guanghu-forgejo.service >/dev/null 2>&1 || true
for unit in "${writers[@]}"; do
systemctl enable --now "$unit" >/dev/null 2>&1 || true
done
for unit in "${handshakes[@]}"; do
systemctl restart "$unit" >/dev/null 2>&1 || true
done
}
on_exit() {
status=$?
trap - EXIT
if test "$completed" = 0; then
rollback
fi
rm -rf "$temporary"
exit "$status"
}
trap on_exit EXIT
test "$(id -u)" = "0"
test "$(cat /etc/machine-id)" = "$expected_machine_id"
test -n "$expected_source_commit"
test "$expected_source_commit" = "$(tr -d '\n' <"$source_commit_file")"
test "$(basename "$release_root")" = "$expected_source_commit"
test -f "${release_root}/server-tools/persona-team-handshake/fifth-domain-daily-orchestrator.mjs"
test -f "${release_root}/server-tools/persona-team-handshake/fifth-domain-daily.config.server.json"
test -f "$shared_secret_file"
test "$(systemctl is-active hlcc-jd-candidate.service)" = "active"
test "$(curl -fsS http://127.0.0.1:3341/health | jq -r .ready)" = "true"
mkdir -p "$backup_root" "$archive_root" "$receipt_root" "$runtime_root"
cp "$shared_secret_file" "${temporary}/shared-deepseek.env"
chmod 0600 "${temporary}/shared-deepseek.env"
if ! grep -q '^PERSONA_TEAM_CONTROLLER_TOKEN=' "$shared_secret_file"; then
controller_token="$(openssl rand -hex 32)"
test "${#controller_token}" = "64"
printf '\nPERSONA_TEAM_CONTROLLER_TOKEN=%s\n' "$controller_token" \
>>"$shared_secret_file"
chmod 0600 "$shared_secret_file"
fi
chown guanghu:guanghu "$runtime_root"
chmod 0700 "$runtime_root"
for unit in "${new_units[@]}"; do
if test -f "/etc/systemd/system/${unit}"; then
cp "/etc/systemd/system/${unit}" "${backup_root}/${unit}"
fi
done
for unit in "${writers[@]}" "${oneshots[@]}" guanghu-forgejo.service; do
systemctl cat "$unit" >"${archive_root}/${unit}.txt" 2>&1 || true
done
source_paths=()
for candidate in /opt/chenglu-agent /opt/guideng/agent /opt/kezhou/agent; do
if test -e "$candidate"; then
source_paths+=("$candidate")
fi
done
if test "${#source_paths[@]}" -gt 0; then
tar -czf "${archive_root}/legacy-persona-writer-source.tar.gz" \
"${source_paths[@]}"
sha256sum "${archive_root}/legacy-persona-writer-source.tar.gz" \
>"${archive_root}/legacy-persona-writer-source.tar.gz.sha256"
fi
for name in chenglu-agent guideng kezhou; do
test -d "${old_repositories[$name]}"
test -d "${repository_root}/${name}.git"
git --git-dir="${old_repositories[$name]}" \
fsck --connectivity-only --no-dangling
git --git-dir="${repository_root}/${name}.git" \
fsck --connectivity-only --no-dangling
done
for unit in "${writers[@]}"; do
systemctl disable --now "$unit"
done
for unit in "${oneshots[@]}"; do
systemctl stop "$unit" || true
done
for unit in "${writers[@]}" "${oneshots[@]}"; do
test "$(systemctl is-active "$unit" || true)" != "active"
done
for name in chenglu-agent guideng kezhou; do
bundle="${temporary}/${name}.bundle"
git --git-dir="${old_repositories[$name]}" bundle create "$bundle" \
--branches --tags
chown guanghu:guanghu "$bundle"
runuser -u guanghu -- git --git-dir="${repository_root}/${name}.git" \
fetch "$bundle" \
"+refs/heads/*:refs/heads/*" \
"+refs/tags/*:refs/tags/*"
old_refs="$(
git --git-dir="${old_repositories[$name]}" for-each-ref \
--format='%(refname) %(objectname)' refs/heads refs/tags |
sort
)"
new_refs="$(
git --git-dir="${repository_root}/${name}.git" for-each-ref \
--format='%(refname) %(objectname)' refs/heads refs/tags |
sort
)"
test "$new_refs" = "$old_refs"
done
for unit in "${handshakes[@]}"; do
sed "s|__RELEASE_ROOT__|${release_root}|g" \
"${release_root}/server-tools/persona-team-handshake/${unit}" \
>"/etc/systemd/system/${unit}"
done
for unit in \
zhuyuan-persona-fifth-domain-daily.service \
zhuyuan-persona-fifth-domain-daily.timer; do
sed "s|__RELEASE_ROOT__|${release_root}|g" \
"${release_root}/server-tools/persona-team-handshake/${unit}" \
>"/etc/systemd/system/${unit}"
done
systemctl daemon-reload
for unit in "${handshakes[@]}"; do
systemctl restart "$unit"
done
for port in 3932 3933 3934; do
ready=0
for attempt in $(seq 1 30); do
if test "$(curl -fsS "http://127.0.0.1:${port}/health" 2>/dev/null | jq -r .ok 2>/dev/null)" = "true"; then
ready=1
break
fi
sleep 1
done
test "$ready" = 1
done
before_chenglu="$(git --git-dir="${repository_root}/chenglu-agent.git" rev-parse main)"
before_guideng="$(git --git-dir="${repository_root}/guideng.git" rev-parse main)"
before_kezhou="$(git --git-dir="${repository_root}/kezhou.git" rev-parse main)"
systemctl enable --now zhuyuan-persona-fifth-domain-daily.timer
systemctl start zhuyuan-persona-fifth-domain-daily.service
test "$(systemctl is-active zhuyuan-persona-fifth-domain-daily.timer)" = "active"
after_chenglu="$(git --git-dir="${repository_root}/chenglu-agent.git" rev-parse main)"
after_guideng="$(git --git-dir="${repository_root}/guideng.git" rev-parse main)"
after_kezhou="$(git --git-dir="${repository_root}/kezhou.git" rev-parse main)"
test "$after_chenglu" != "$before_chenglu"
test "$after_guideng" != "$before_guideng"
test "$after_kezhou" != "$before_kezhou"
source_sha="$(git --git-dir="${repository_root}/guanghu-ice-heart.git" rev-parse main)"
for name in chenglu-agent guideng kezhou; do
observed="$(
git --git-dir="${repository_root}/${name}.git" \
show main:persona-system/fifth-domain/CURRENT.json |
jq -r .last_source_sha
)"
test "$observed" = "$source_sha"
runuser -u guanghu -- git \
-c "safe.directory=${repository_root}/${name}.git" \
--git-dir="${repository_root}/${name}.git" \
fsck --connectivity-only --no-dangling
done
systemctl disable --now guanghu-forgejo.service
test "$(systemctl is-active guanghu-forgejo.service || true)" != "active"
if ss -ltnH | awk '{print $4}' | grep -Eq '(^|:)3001$'; then
exit 41
fi
test "$(curl -fsS http://127.0.0.1:3341/health | jq -r .ready)" = "true"
for unit in "${handshakes[@]}"; do
test "$(systemctl is-active "$unit")" = "active"
done
latest_daily_receipt="$(
find "${runtime_root}/receipts" -maxdepth 1 -type f \
-name 'ZY-PERSONA-DAILY-*.json' -printf '%T@ %p\n' |
sort -nr |
head -n 1 |
cut -d' ' -f2-
)"
test -n "$latest_daily_receipt"
test "$(jq -r .result "$latest_daily_receipt")" = "PASS"
test "$(jq '[.results[] | select(.status == "FIFTH_DOMAIN_UPDATE_COMMITTED")] | length' "$latest_daily_receipt")" = "3"
jq -n \
--arg completed_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--arg source_commit "$expected_source_commit" \
--arg source_sha "$source_sha" \
--arg before_chenglu "$before_chenglu" \
--arg after_chenglu "$after_chenglu" \
--arg before_guideng "$before_guideng" \
--arg after_guideng "$after_guideng" \
--arg before_kezhou "$before_kezhou" \
--arg after_kezhou "$after_kezhou" \
--arg daily_receipt "$latest_daily_receipt" \
--arg source_archive_sha "$(
awk '{print $1}' "${archive_root}/legacy-persona-writer-source.tar.gz.sha256" \
2>/dev/null || printf 'NO_SOURCE_ARCHIVE'
)" \
'{
schema: "guanghu.persona-fifth-domain-daily-deployment-receipt/v1",
receipt_id: "JD-PERSONA-FIFTH-DOMAIN-DAILY-20260806",
target_node: "JD-FD-PRIMARY",
completed_at: $completed_at,
source_commit: $source_commit,
source_fifth_domain_sha: $source_sha,
result: "THREE_ROLE_PERSONA_SYSTEMS_DAILY_FIFTH_DOMAIN_LOOP_DEPLOYED_AND_VERIFIED",
controller: "ICE-P-ZY001",
human_authority: "ICE-GL∞",
repositories: [
{name:"bingshuo/chenglu-agent", before:$before_chenglu, after:$after_chenglu},
{name:"bingshuo/guideng", before:$before_guideng, after:$after_guideng},
{name:"bingshuo/kezhou", before:$before_kezhou, after:$after_kezhou}
],
old_periodic_writers: "DISABLED_AND_INACTIVE",
old_repository_service: "DISABLED_AND_INACTIVE",
daily_timer: "ACTIVE",
role_handshake_services: "ALL_ACTIVE",
current_code_channel: "HEALTHY",
daily_dispatch_receipt: $daily_receipt,
legacy_data_deleted: false,
source_archive_sha256: $source_archive_sha,
rule: "Each daily wake reads exact REPO-012 main deltas and writes a signed role-specific update only when Fifth Domain advances."
}' >"${receipt}.tmp"
chmod 0600 "${receipt}.tmp"
mv "${receipt}.tmp" "$receipt"
completed=1
rm -rf "$temporary"
trap - EXIT
printf 'THREE_ROLE_PERSONA_SYSTEMS_DAILY_FIFTH_DOMAIN_LOOP_DEPLOYED receipt=%s\n' \
"$receipt"