Add Forgejo tier-3 remote_url and sweep playbook

Document State Hub PATCH procedure, sweep implications, railiance01 host_paths,
state-hub image specifics, and rollback. Include batch patch helper; applied
tier-2.5 remote_url updates in hub DB.
This commit is contained in:
codex
2026-07-04 13:21:40 +02:00
parent dd0ee14f50
commit 5c63c2f354
3 changed files with 289 additions and 1 deletions

View File

@@ -149,7 +149,8 @@ Before `state-hub`, the ladder still needs:
- [x] Operator/user SSH identity on Forgejo (`tegwick` + workstation key)
- [x] Reusable workflow templates in `railiance-enablement` (incl. multi-repo / `hub-core` context template)
- [ ] State Hub `remote_url` + sweep checkout path update playbook
- [x] State Hub `remote_url` + sweep checkout path update playbook
`docs/forgejo-tier3-remote-url-sweep-playbook.md` (execute per repo on promotion)
- [ ] Gitea read-only mirror or push-disable policy for repos after cutover
- [ ] Scheduled Forgejo backups (disaster-control track; restore drill passed)

View File

@@ -0,0 +1,238 @@
# Forgejo Tier 3 — State Hub `remote_url` and Sweep Playbook
Date: 2026-07-04
Workplans: `RAIL-HO-WP-0005-T10`, `RAIL-HO-WP-0005-T11`, `CUST-WP-0054-T04`, `CUST-WP-0054-T05`
`no_secret_material_recorded: true`
## Purpose
Operational playbook for promoting a **registered** State Hub repo from Gitea
(`gitea-remote`) to Forgejo (`forgejo-remote`) without breaking the consistency
sweep, DoI checks, or agent attribution.
Applies to:
- **Tier 2.5** (done on Forgejo, hub `remote_url` may still say Gitea) — run
§4 after git promotion.
- **Tier 3** (`state-hub`, `issue-core`, production wave) — full §3§8 with
operator approval.
Does **not** perform cutover by itself. Gitea remains canonical until tier gates
and explicit approval per `RAIL-HO-WP-0005` safety contract.
## Preconditions (gates)
| Gate | Tier 2.5 | Tier 3 (`state-hub`) |
| --- | --- | --- |
| Forgejo repo exists + history mirrored | required | required |
| Workstation `origin=forgejo-remote`, `gitea` legacy remote | required | required |
| Operator SSH on Forgejo (`tegwick` or team keys) | required | required |
| CI smoke green on Forgejo (`.forgejo/workflows/ci-smoke.yaml`) | required | required |
| Image workflow if applicable | optional | required for `state-hub` |
| Restore drill passed | recommended | required |
| Scheduled backups automated | optional | required (disaster-control) |
| Operator approval recorded | not required | **required** |
| `CUST-WP-0011-T07` freeze/restore for hub primary | n/a | required before hub production |
## Canonical remote conventions
State Hub stores the **SSH remote name form** used on the operator workstation,
not the HTTPS URL. This matches existing registrations
(`gitea-remote:coulomb/<slug>.git`).
| Role | Remote name | Example |
| --- | --- | --- |
| Canonical (post-promotion) | `origin``forgejo-remote` | `forgejo-remote:coulomb/state-hub.git` |
| Rollback mirror | `gitea``gitea-remote` | `gitea-remote:coulomb/state-hub.git` |
| Hub `remote_url` field | same as `origin` | `forgejo-remote:coulomb/state-hub.git` |
HTTPS canonical URL for humans and archive CI:
`https://forgejo.coulomb.social/coulomb/<slug>.git`
SSH config block (workstation `~/.ssh/config`):
```ssh
Host forgejo-remote
HostName 92.205.62.239
Port 30022
User git
IdentityFile ~/.ssh/id_gitea
StrictHostKeyChecking accept-new
```
## Per-repo promotion procedure
### 1. Git forge (workstation)
Use `railiance-enablement/tools/promote-repo-to-forgejo.sh` or manually:
```bash
cd ~/REPO_SLUG
# Create empty repo on Forgejo if needed (org coulomb)
git push forgejo-remote:coulomb/REPO_SLUG.git main # first mirror
git remote rename origin gitea
git remote add origin forgejo-remote:coulomb/REPO_SLUG.git
git push -u origin main
# Optional: keep Gitea mirror current
git push gitea main
```
Add `.forgejo/workflows/ci-smoke.yaml` from
`railiance-enablement/workflows/ci-smoke.yaml`. For images, use
`container-build-push.yaml` or `container-build-push-multirepo.yaml` (state-hub +
hub-core).
### 2. Verify git + SSH
```bash
git remote -v
# origin forgejo-remote:coulomb/REPO_SLUG.git (fetch/push)
# gitea gitea-remote:coulomb/REPO_SLUG.git (fetch/push)
ssh forgejo-remote # expect: Hi there, tegwick!
git ls-remote origin # reachable
```
### 3. Patch State Hub registration
```bash
API=http://127.0.0.1:8000
SLUG=REPO_SLUG
NEW_URL="forgejo-remote:coulomb/${SLUG}.git"
curl -s -X PATCH "${API}/repos/${SLUG}" \
-H "Content-Type: application/json" \
-d "{\"remote_url\": \"${NEW_URL}\"}" | python3 -m json.tool
# Confirm
curl -s "${API}/repos/${SLUG}" | python3 -c \
"import json,sys; r=json.load(sys.stdin); print(r['slug'], r['remote_url'])"
```
Batch helper for tier-2.5 stack (skips slugs not registered in State Hub):
```bash
~/the-custodian/tools/patch-forgejo-remote-urls.sh --tier-25
```
Applied 2026-07-04 for registered tier-2.5 repos + `key-cape`. `glas-harness` is
not in State Hub registration — patch when/if registered.
### 4. Consistency sweep / fix-consistency
The sweep (`POST /consistency/sweep/remote-all` or `statehub fix-consistency`)
resolves repos by `host_paths[hostname]` or `local_path`, then `git pull
--ff-only` from the checkout's **tracking branch** (now Forgejo `origin`).
After `remote_url` patch:
```bash
cd ~/REPO_SLUG
git fetch origin
statehub fix-consistency --repo REPO_SLUG
# or from state-hub checkout:
cd ~/state-hub && make fix-consistency REPO=REPO_SLUG
```
**Attribution:** `consistency_check.py` matches repos by git fingerprint and
`remote_url` string. Stale `gitea-remote` in the hub causes mis-attribution when
multiple checkouts exist — patch hub **before** relying on sweep writebacks.
### 5. DoI verification
```bash
curl -s "http://127.0.0.1:8000/repos/REPO_SLUG/doi" | python3 -m json.tool
# C4 Remote URL set → pass
# C4 reachability → git ls-remote origin succeeds
```
## Railiance01 sweep checkout paths (`CUST-WP-0054-T05`)
Today sweeps write back from **workstation** `host_paths` (`bnt-lap001`). Wave 2
moves primary checkouts to **railiance01** so triage survives workstation loss.
When railiance01 clone tree exists (e.g. `/home/tegwick/<slug>` or agreed path):
```bash
API=http://127.0.0.1:8000
SLUG=REPO_SLUG
HOST=railiance01 # must match socket.gethostname() on that machine
PATH_ON_HOST=/home/tegwick/REPO_SLUG
curl -s -X POST "${API}/repos/${SLUG}/paths" \
-H "Content-Type: application/json" \
-d "{\"host\": \"${HOST}\", \"path\": \"${PATH_ON_HOST}\"}" | python3 -m json.tool
```
Clone on railiance01 **from Forgejo**:
```bash
git clone forgejo-remote:coulomb/REPO_SLUG.git /home/tegwick/REPO_SLUG
# or HTTPS with deploy key / token
```
Sweep on railiance01 then uses `host_paths[railiance01]`; workstation path
remains in map for dev but is no longer the production writeback source.
## Tier 3 — `state-hub` specifics
Before promoting `state-hub`:
1. **Multi-repo image workflow** — copy
`railiance-enablement/workflows/container-build-push-multirepo.yaml` to
`state-hub/.forgejo/workflows/image.yaml`; set `IMAGE_NAME=coulomb/state-hub`,
`EXTRA_REPOS="coulomb/hub-core@hub_core_src"`.
2. **Prove image pull** on railiance01 (`crictl pull` or deployment dry-run).
3. **Hub primary cutover** — follow `CUST-WP-0011-T07` (freeze → restore →
rewire); independent of forge remote but same maintenance window may apply.
4. **ArgoCD / GitOps** — repoint repository URLs to Forgejo (Wave 5 in
`docs/coulombcore-drain-placement-plan.md`).
5. **Record approval**`POST /decisions/` or workplan note with operator id.
`state-hub` promotion order:
```
mirror git → Forgejo remotes → CI image workflow green → PATCH remote_url →
fix-consistency → (later) railiance01 host_paths → CUST-WP-0011-T07 cutover
```
## Gitea read-only policy (post-cutover per repo)
After Forgejo is canonical **for that repo** and hub `remote_url` is patched:
1. Do **not** delete the Gitea repo (safety contract).
2. Org/repo setting: disable push for non-admin users, or maintenance flag.
3. Workstation: stop pushing to `gitea` except intentional rollback mirror.
4. Document rollback: `git push gitea main` from last known-good Forgejo SHA.
Org-wide Gitea read-only is an operator action (T11); per-repo is enough for
staged ladder.
## Rollback
| Step | Action |
| --- | --- |
| Git canonical | `git remote rename origin forgejo; git remote rename gitea origin` |
| Hub | `PATCH /repos/{slug}``gitea-remote:coulomb/<slug>.git` |
| Sweep | `statehub fix-consistency` on reverted checkout |
| Gitea | Re-enable push if read-only was set |
## Verification checklist
- [ ] `GET /repos/{slug}``remote_url` is `forgejo-remote:coulomb/<slug>.git`
- [ ] Workstation `git remote -v``origin` is Forgejo
- [ ] `ssh forgejo-remote` → operator user (not only `forgejo_admin`)
- [ ] `statehub fix-consistency --repo <slug>` → PASS
- [ ] Forgejo Actions `ci-smoke` → success (tier 1+)
- [ ] Gitea copy exists and matches SHA (optional `git push gitea` mirror)
- [ ] Tier 3 only: image workflow + pull smoke + operator approval on record
## References
- `docs/forgejo-repo-migration-pilot-glas-harness.md` (tiers 12.5)
- `railiance-enablement/docs/forgejo-actions-workflow-templates.md`
- `railiance-enablement/tools/promote-repo-to-forgejo.sh`
- `state-hub/docs/consistency-sweep-runbook.md`
- `state-hub/policies/repo-doi.md` (C4 remote URL)
- `docs/coulombcore-drain-placement-plan.md` (Wave 12)
- `disaster-control/history/2026-07-04-forgejo-backup-strategy-assessment.md`