docs: replace the cutover plan with the phased one that matches reality

Phase 1 requires nothing from anyone: agents keep pushing to GitHub, a timer
syncs GitHub -> Windy Git every 15 minutes, CI runs on Veron against current
code. Phase 2 flips one repo at a time, only when that repo is idle.

Records the direction mistake honestly: the source of truth is wherever people
are actually typing, not wherever the plan says it should be.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Grant Whitmer
2026-08-12 22:14:21 -04:00
parent 51acf9f86e
commit b2f00821d7

View File

@@ -1,63 +1,65 @@
# Windy Git is the daily driver — 2026-08-13 # Migration plan — GitHub first, Windy Git second, flip per repo
Grant's call, 2026-08-12: **push to Windy Git; GitHub is the second copy.** **Superseded the 2026-08-13 "daily driver" cutover, which was premature.**
you ──push──▶ Windy Git (Veron 1) ──▶ CI on 24 cores ## What went wrong, recorded so it is not repeated
│
└──push-mirror on every commit──▶ GitHub
## 🔴 The one rule this creates Nine repos were migrated writable with **push-mirrors pointed at GitHub**. At
the same time a dozen agent sessions on the Mac mini were pushing to GitHub
continuously — so GitHub, not Windy Git, was where the live work actually was.
**Do not push directly to GitHub for a migrated repo.** A push-mirror force-updates refs. On its 8-hour timer it would have pushed Windy
Git's stale copy **over live work, silently, with no conflict to notice.**
A push mirror makes GitHub match Windy Git. Anything committed straight to All nine mirrors were removed before the first timer fired, and every GitHub
GitHub is **overwritten on the next sync**, silently, with no conflict and no repo was verified untouched (latest push predated the mirrors). **No work was
warning. That is the cost of having one writer, and one writer is the point — lost.** The mistake was direction, and the lesson is: *the source of truth is
two writers with no reconciliation is how you lose work you thought was saved. wherever people are actually typing, not wherever the plan says it should be.*
If you must hotfix on GitHub: push there, then immediately pull that commit into ## Phase 1 — now. Nothing changes for anyone.
Windy Git *before* anything triggers a mirror sync. Better: don't.
## Migrated (9) Mac mini agents ──push──▶ GitHub ──sync every 15 min──▶ Windy Git ──▶ CI on Veron
`windy-calendar` · `windy-search` · `windy-registry` · `Windy-Clone` · - **You do not have to tell your agents anything.** No remote changes, no
`WindyCloud` · `windy-cloud-sites` · `windy-mind` · `eternitas` · `windy-agent` coordination, no "everyone stop pushing." They keep working exactly as they
are.
- `windygit-sync.timer` runs `scripts/sync_from_github.sh` every 15 minutes.
- Windy Git is **force-updated** on purpose: it holds nothing anyone depends on,
so GitHub always wins and there is **no merge to reconcile**. That is the
whole point of not flipping until a repo is quiet.
- CI runs on Veron 1 against current code, on the 36 workflows that already say
`runs-on: [self-hosted, linux, x64]`.
All writable (`mirror=false`), all push-mirroring to GitHub with Tracked repos live in `REPOS` in the script (currently 9 of 141).
`sync_on_commit: true`. Clone from `https://app.windygit.com/windyadmin/<repo>.git`.
**Not migrated on purpose:** `windy-pro`. Six checkouts exist, the build counter ## Phase 2 — later, one repo at a time, only when that repo is idle
has forked three ways (main 12 / overnight 34 / wave-44 56), and two sessions
recorded different HEADs hours apart. Resolve which is current and write it
down first (G11.5). The import script refuses it by name.
## CI For a single repo, when nobody is mid-work on it:
The runner advertises `veron-1`, `linux-x64`, `self-hosted`, `linux`, `x64`. 1. Remove it from `REPOS` in `sync_from_github.sh` — **first**, or the sync will
**36 of 36 active workflows in the fleet already say fight its authors and win.
`runs-on: [self-hosted, linux, x64]`** — they were written for the self-hosted 2. Point that repo's sessions at Windy Git:
runners that died when the repos went private, so they run **as-is, unedited**. `git remote set-url origin https://app.windygit.com/windyadmin/<repo>.git`
3. Add a push-mirror back to GitHub with `sync_on_commit: true`, so GitHub stays
a current second copy.
Proven: `windy-calendar`'s existing `.github/workflows/ci.yml` ran on Veron 1 **Never flip more than one repo at a time, and never while an agent is working
and reported success with no changes. in it.** A dozen parallel sessions is exactly the situation where a big-bang
cutover produces the dirty-branch mess this plan exists to avoid.
**Per-repo secrets are not imported.** A repo whose CI needs a database URL or ## What is NOT on Windy Git
an API key will fail until those are set in its Gitea repo settings. Set them as
each repo needs them, not speculatively. **9 of 141 repos.** The whole GitHub account is 1.58 GB, so the rest is a
capacity non-issue — it simply has not been imported yet. Add repos to the
import list as they become useful to build.
**`windy-pro` is excluded on purpose.** Six checkouts, a build counter forked
three ways, two sessions recording different HEADs hours apart. Resolve which is
current and write it down before importing (G11.5). The import script refuses it
by name.
## Backups ## Backups
Nightly `windygit-backup.timer` at 04:17 (`Persistent=true`, so a window missed `windygit-backup.timer`, nightly 04:17, `git bundle --all` + verify + `windgit`
while the workstation is off is caught up rather than skipped). Every repo is schema dump to R2, 30-day retention. **Restore rehearsed:** a bundle was pulled
bundled `--all`, verified, and uploaded to R2 with the `windgit` schema. from R2, cloned, and its HEAD matched live `origin/main` exactly.
**Restore is rehearsed, not assumed:** a bundle was pulled back from R2, cloned,
and its HEAD matched live `origin/main` exactly.
## Verify the loop yourself
```bash
git clone https://app.windygit.com/windyadmin/windy-calendar.git
cd windy-calendar && git commit --allow-empty -m "probe" && git push
# CI runs on Veron 1; GitHub receives the commit within ~20s
```