Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 48 additions & 3 deletions docs/runbooks/org-migration-rename.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,49 @@ gh api repos/smartwatermelon/dotfiles --jq '.owner.login + " " + .owner.type' #
cd ~/Developer/dotfiles && gh pr list --limit 1 # identity guard passes, no error
```

## Stop: the transfer happens outside this runbook

Parts A–E cover **Step 2** of the design only: the rename and the org. No
repo has moved yet. Parts F and G below verify a transfer, so do not run
them here — every repo would still report `owner is twistedmelonman (User)`,
which is correct for this moment and looks like 31 failures.

Go to `docs/superpowers/specs/2026-09-03-org-migration-design.md` and do:

- **Step 3** — transfer `github-workflows` alone and prove one consumer per
org still runs green. It is the cross-org dependency: both orgs reference
`uses: smartwatermelon/github-workflows/...`. Read the run log to confirm
the reusable workflow resolved from the new owner; a green check by itself
is not evidence.

```bash
bash scripts/org-migration/transfer.sh scripts/org-migration/move-list.txt \
--only github-workflows --dry-run
bash scripts/org-migration/transfer.sh scripts/org-migration/move-list.txt \
--only github-workflows
```

- **Step 4** — transfer the remaining repos:

```bash
bash scripts/org-migration/transfer.sh scripts/org-migration/move-list.txt --dry-run
bash scripts/org-migration/transfer.sh scripts/org-migration/move-list.txt
```

Come back to Part F when Step 4 is done.

## F. Verify the transfer (`verify.sh`)

Run this **after** design Steps 3 and 4, not before.

```bash
bash scripts/org-migration/verify.sh scripts/org-migration/move-list.txt \
docs/data/org-migration/baseline "$(mktemp -d)"
docs/data/org-migration/2026-09-04-baseline "$(mktemp -d)"
```

The baseline directory is dated. `verify.sh` fails and names the path if you
get it wrong, rather than reporting every repo as a missing snapshot.

**Always give `verify.sh` a fresh, empty after-dir.** It refuses a directory
that already holds files, because a leftover JSON from an earlier run would be
compared as though this run had just written it — a repo whose snapshot failed
Expand All @@ -103,8 +139,17 @@ real drift.

## G. The other two machines (TILSIT, MIMOLETTE)

Run section D on each, before the alias-removal PR (plan Task 12) merges.
Until then the alias keeps the old `hosts.yml` name working.
Run section D on each, before the alias-removal PR (plan Task 12, design
Step 6) merges. Until then the alias keeps the old `hosts.yml` name working.

Section D re-logins the keyring. On a machine whose shell was already open
before the rename, the sourced `gh` wrapper is also stale: reload it with
`exec bash -l` before verifying, or the old wrapper still tries to switch to
`smartwatermelon` and fails closed. `which gh` and `hash -t gh` show the
staleness; `command -v` does not.

Steps 5–7 of the design (org secret, cleanup, docs) are not covered by this
runbook.

## Undo

Expand Down
26 changes: 26 additions & 0 deletions scripts/org-migration/tests/test-verify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,30 @@ else
_fail "nested clone broken: rc=${rc} err=${err}"
fi

# Case 10: a baseline dir that does not exist must fail on the path, not
# degrade into a "missing snapshot" line per repo. A mistyped baseline path
# otherwise reads as total drift across the whole move list.
out="$(OM_TEST_CORE="${WORK}/core-good" PATH="${WORK}/bin:${PATH}" bash "${VERIFY}" \
"${WORK}/list" "${WORK}/nonexistent-baseline" "${WORK}/after-missing-base" \
--clones "${WORK}/clones-good" 2>&1)"
rc=$?
if [[ "${rc}" -eq 1 && "${out}" == *"does not exist"* && "${out}" != *"missing snapshot"* ]]; then
_pass "missing baseline dir: named as the failure, exit 1"
else
_fail "missing baseline dir: rc=${rc} out=${out}"
fi

# Case 11: an empty baseline dir is the same class of mistake -- a path that
# exists but holds no snapshots.
mkdir -p "${WORK}/empty-baseline"
out="$(OM_TEST_CORE="${WORK}/core-good" PATH="${WORK}/bin:${PATH}" bash "${VERIFY}" \
"${WORK}/list" "${WORK}/empty-baseline" "${WORK}/after-empty-base" \
--clones "${WORK}/clones-good" 2>&1)"
rc=$?
if [[ "${rc}" -eq 1 && "${out}" == *"is empty"* && "${out}" != *"missing snapshot"* ]]; then
_pass "empty baseline dir: named as the failure, exit 1"
else
_fail "empty baseline dir: rc=${rc} out=${out}"
fi

exit "${fail}"
14 changes: 14 additions & 0 deletions scripts/org-migration/verify.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ base="${positional[1]}"
after="${positional[2]}"
fail=0

# The baseline dir must exist and hold snapshots. Without this check a wrong
# path is not an error: every repo simply misses its baseline file and the
# comparison loop reports "missing snapshot" for the whole move list, which
# reads as catastrophic drift rather than as a typo. Fail on the path itself
# so the message names the real problem.
if [[ ! -d "${base}" ]]; then
echo "verify: baseline-dir ${base} does not exist" >&2
exit 1
fi
if [[ -z "$(ls -A "${base}" 2>/dev/null || true)" ]]; then
echo "verify: baseline-dir ${base} is empty" >&2
exit 1
fi

# The after-dir must be ours alone. A leftover JSON from an earlier run would
# be compared as though this run had just written it, so a repo whose snapshot
# failed now could still be reported ok from stale state.
Expand Down
Loading