ZDDC/scripts/migrate-toplevel-peers.sh
ZDDC 29182480c2 feat(scripts): add migrate-toplevel-peers.sh
Idempotent migration from the old archive/<party>/<slot> layout to the
flat top-level party-peer layout: moves the workspace/register slots
(incoming/working/staging/reviewing/mdl/rsk) out to <project>/<slot>/<party>/,
moves archive/<party>/ssr.yaml → ssr/<party>.yaml (the party registry),
synthesizes a minimal ssr/<party>.yaml for any archived party that lacks
one, and leaves archive/<party>/{received,issued} in place (the WORM
record). --dry-run flag; per-party summary; tested + idempotent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 12:37:04 -05:00

143 lines
3.6 KiB
Bash
Executable file

#!/bin/sh
# migrate-toplevel-peers.sh — migrate a ZDDC root from the old
# "everything under archive/<party>/" layout to the flat top-level
# party-peer layout.
#
# Per project (a top-level dir containing archive/), for each
# archive/<party>/:
# - move archive/<party>/{incoming,working,staging,reviewing,mdl,rsk}
# → <project>/<slot>/<party>/ (the workspace/register peers)
# - move archive/<party>/ssr.yaml → <project>/ssr/<party>.yaml
# (this establishes the party registry — a party exists iff its
# ssr/<party>.yaml exists)
# - if a party has no ssr.yaml, synthesize a minimal ssr/<party>.yaml
# so it stays registered (else its workspaces can't be recreated)
# - LEAVE archive/<party>/{received,issued} in place (the WORM record)
#
# Per-folder .zddc files travel with their directory (the whole slot dir
# is moved). Idempotent: already-migrated paths are skipped. Run with the
# server stopped (or accept it's a plain filesystem move).
#
# Usage:
# migrate-toplevel-peers.sh [--dry-run] <ZDDC_ROOT>
#
# --dry-run prints what would happen and changes nothing.
set -eu
DRY=0
ROOT=""
for arg in "$@"; do
case "$arg" in
--dry-run) DRY=1 ;;
-h|--help)
sed -n '2,30p' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
-*)
echo "unknown flag: $arg" >&2
exit 2
;;
*) ROOT="$arg" ;;
esac
done
if [ -z "$ROOT" ] || [ ! -d "$ROOT" ]; then
echo "usage: $0 [--dry-run] <ZDDC_ROOT>" >&2
exit 2
fi
WORKSPACE_SLOTS="incoming working staging reviewing mdl rsk"
moved=0
synth=0
skipped=0
say() { printf '%s\n' "$*"; }
act() {
# act <description> <command...>
desc=$1
shift
if [ "$DRY" -eq 1 ]; then
say "DRY $desc"
else
say " -> $desc"
"$@"
fi
}
# move_dir SRC DST — move a directory, creating DST's parent. Skips when
# SRC is absent (nothing to do) or DST already exists (already migrated).
move_dir() {
src=$1
dst=$2
[ -d "$src" ] || return 0
if [ -e "$dst" ]; then
say " .. skip (dest exists): $dst"
skipped=$((skipped + 1))
return 0
fi
parent=$(dirname "$dst")
act "mkdir -p $parent" mkdir -p "$parent"
act "mv $src -> $dst" mv "$src" "$dst"
moved=$((moved + 1))
}
# move_file SRC DST — same shape, for the ssr.yaml registry row.
move_file() {
src=$1
dst=$2
[ -f "$src" ] || return 0
if [ -e "$dst" ]; then
say " .. skip (dest exists): $dst"
skipped=$((skipped + 1))
return 0
fi
parent=$(dirname "$dst")
act "mkdir -p $parent" mkdir -p "$parent"
act "mv $src -> $dst" mv "$src" "$dst"
moved=$((moved + 1))
}
synth_registry() {
dst=$1
[ -e "$dst" ] && return 0
parent=$(dirname "$dst")
act "mkdir -p $parent" mkdir -p "$parent"
if [ "$DRY" -eq 1 ]; then
say "DRY synthesize $dst (kind: SSR)"
else
say " -> synthesize $dst (kind: SSR)"
printf 'kind: SSR\n' >"$dst"
fi
synth=$((synth + 1))
}
for projectdir in "$ROOT"/*/; do
[ -d "$projectdir/archive" ] || continue
project=$(basename "$projectdir")
case "$project" in .* | _*) continue ;; esac
say "project: $project"
for partydir in "$projectdir"archive/*/; do
[ -d "$partydir" ] || continue
party=$(basename "$partydir")
case "$party" in .* | _*) continue ;; esac
say " party: $party"
# 1. Registry row: archive/<party>/ssr.yaml -> ssr/<party>.yaml
move_file "${partydir}ssr.yaml" "${projectdir}ssr/${party}.yaml"
# 2. Workspace/register slots -> <slot>/<party>/
for slot in $WORKSPACE_SLOTS; do
move_dir "${partydir}${slot}" "${projectdir}${slot}/${party}"
done
# 3. Guarantee a registry entry so the party stays registered.
synth_registry "${projectdir}ssr/${party}.yaml"
done
done
say ""
say "summary: moved=$moved synthesized=$synth skipped=$skipped"
[ "$DRY" -eq 1 ] && say "(dry-run — nothing changed)"
exit 0