From 29182480c20fc962aaf6cd9fbea97a29a6554259 Mon Sep 17 00:00:00 2001 From: ZDDC Date: Wed, 3 Jun 2026 12:37:04 -0500 Subject: [PATCH] feat(scripts): add migrate-toplevel-peers.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Idempotent migration from the old archive// layout to the flat top-level party-peer layout: moves the workspace/register slots (incoming/working/staging/reviewing/mdl/rsk) out to ///, moves archive//ssr.yaml → ssr/.yaml (the party registry), synthesizes a minimal ssr/.yaml for any archived party that lacks one, and leaves archive//{received,issued} in place (the WORM record). --dry-run flag; per-party summary; tested + idempotent. Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/migrate-toplevel-peers.sh | 143 ++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100755 scripts/migrate-toplevel-peers.sh diff --git a/scripts/migrate-toplevel-peers.sh b/scripts/migrate-toplevel-peers.sh new file mode 100755 index 0000000..15b2757 --- /dev/null +++ b/scripts/migrate-toplevel-peers.sh @@ -0,0 +1,143 @@ +#!/bin/sh +# migrate-toplevel-peers.sh — migrate a ZDDC root from the old +# "everything under archive//" layout to the flat top-level +# party-peer layout. +# +# Per project (a top-level dir containing archive/), for each +# archive//: +# - move archive//{incoming,working,staging,reviewing,mdl,rsk} +# → /// (the workspace/register peers) +# - move archive//ssr.yaml → /ssr/.yaml +# (this establishes the party registry — a party exists iff its +# ssr/.yaml exists) +# - if a party has no ssr.yaml, synthesize a minimal ssr/.yaml +# so it stays registered (else its workspaces can't be recreated) +# - LEAVE archive//{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] +# +# --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] " >&2 + exit 2 +fi + +WORKSPACE_SLOTS="incoming working staging reviewing mdl rsk" +moved=0 +synth=0 +skipped=0 + +say() { printf '%s\n' "$*"; } +act() { + # act + 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//ssr.yaml -> ssr/.yaml + move_file "${partydir}ssr.yaml" "${projectdir}ssr/${party}.yaml" + + # 2. Workspace/register slots -> // + 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