---
title: VPS Git Recovery Plan
date: 2026-06-11
type: ops-runbook
project: 11_OpsMan_LFCS
status: DRAFT — no execution until Rocky drives it. Scheduled: tonight 2026-06-11, 8:30pm block, WATCHED.
---

# VPS Git Recovery Plan — 2026-06-11

**Author:** claude-code-local. **Status:** DRAFT, nothing run. **Execution window:** tonight 8:30pm, watched, stepwise. Not before.

## TL;DR

VPS git broke **2026-05-06**: a root-run interactive rebase was abandoned mid-flight, leaving HEAD detached. The `*/30` auto-sync cron kept committing to the **detached HEAD**, so `main` froze at May 6 while 156 commits piled up off-branch. Laptop/origin and VPS diverged: **63 (laptop) vs 156 (VPS)** commits since common ancestor `a37ee90e`. Sync dead for 5 weeks.

Good news: laptop work (incl. today's edits) is **safe on origin/main `9690ccfe`**; VPS's 156 commits are **safe behind tag `vps-detached-safety-2026-06-11` → `ff0ca1d4`**. **Conflict surface is tiny: only 6 files changed on both chains, and 5 of those are trivial.** Nothing is lost.

## Verified facts (read-only diagnosis, 2026-06-11)

| Thing | Value |
|---|---|
| Common ancestor (merge-base = rebase `onto`) | `a37ee90e` "claude-code-opsman: log Task #9 Airtable PAT rotation ABANDONED per Rocky" |
| origin/main (laptop chain, incl. today's work) | `9690ccfe` — **63** ahead of ancestor, **688** files changed |
| VPS detached HEAD | `ff0ca1d4` "auto-sync: 2026-06-10 22:30" — **156** ahead, **78** files changed |
| VPS `refs/heads/main` (stale, frozen) | `f0b84dc5` "auto-sync: 2026-05-06 22:30" |
| Safety tag (set today) | `vps-detached-safety-2026-06-11` → `ff0ca1d4` |
| Stuck rebase | `.git/rebase-merge/` present, dated 2026-05-06 23:00, **root-owned** (repo is ccuser-owned) |
| VPS uncommitted WIP (3 files, blocked by append-only hook) | `01_Daily/2026-05-10.md` (append, benign no-newline-EOF flag); `_AgentLog/hermes-daily/2026-05-12.md` (appends + **1 inline rewrite**: `Mack Civil / Nihar Reddy` → `Homebush Solutions — Forest Rd...`, dropped contact); `_System/CuratorLog.md` (not append-only-gated) |

## Root cause

May-6 root-run `git rebase -i` onto `a37ee90e` stopped at "editing a commit", never finished/aborted → detached HEAD. `auto-sync.sh` (`*/30`) kept committing to detached HEAD, not `main`. 156 off-branch commits May 6 → Jun 10. Push/pull stopped reconciling; chains diverged. Surfaced today when a manual `auto-sync.sh` hit the append-only hook.

---

## STEP 1 — FREEZE FIRST (do BEFORE anything else)

A broken sync that keeps firing deepens the wound. Stop every automated writer to the repo/vault for the merge window.

**1a. Disable the two root cron jobs** (`crontab -e` as root — comment, don't delete):
```cron
# FROZEN 2026-06-11 for git recovery — re-enable after reconcile verified
#*/5  * * * * /usr/bin/node /home/ccuser/opsman-control-centre/scripts-live-sync.mjs >> /home/ccuser/opsman-control-centre/live-sync.log 2>&1
#*/30 * * * * /home/ccuser/rateright-growth/scripts/auto-sync.sh >> /home/ccuser/rateright-growth/logs/auto-sync.log 2>&1
```
(Line 6 = the git auto-sync, the direct cause. Line 3 = opsman live-sync every 5 min — freeze too; confirm whether it writes into the repo/vault before re-enabling.)

**1b. Stop the agent services that write the vault** (hermes-daily logs, CuratorLog, etc. originate here):
```bash
systemctl stop hermes-gateway.service clawdbot-opsman.service
systemctl status hermes-gateway.service clawdbot-opsman.service | grep Active   # confirm inactive
```

**1c. Confirm quiet** — no writers left:
```bash
cd /home/ccuser/rateright-growth && git status --porcelain   # should be only the known 3 WIP files
```

### RE-ENABLE (after STEP 7 verify passes — do NOT forget)
```bash
systemctl start hermes-gateway.service clawdbot-opsman.service
crontab -e   # un-comment the two lines above (only after confirming auto-sync.sh has the STEP 8 guard)
```

---

## STEP 2 — SAFETY SNAPSHOT
```bash
git tag --list vps-detached-safety-2026-06-11 && git rev-parse vps-detached-safety-2026-06-11   # must = ff0ca1d4
sudo tar czf /root/rrg-prebackup-2026-06-11.tar.gz -C /home/ccuser rateright-growth
```

---

## STEP 3 — CONFLICT INVENTORY (computed 2026-06-11, before strategy)

Files changed on **BOTH** chains since `a37ee90e` = the only real merge surface. Everything else (685 laptop-only, 72 VPS-only) auto-merges.

**TOTAL OVERLAP: 6 files.** Grouped:

| File | Laptop +/− | VPS +/− | Class | Strategy |
|---|---|---|---|---|
| `...2626-BOQ-Hasibul-Khan-2026-05-06_v-CW.md` | +147/0 | +147/0 | job doc | **IDENTICAL blob both sides → git auto-merges, no conflict.** No action. |
| `_Brain/_Log.md` | +25/0 | +2/0 | append log | **UNION** |
| `_System/AgentLog/events.ndjson` | +5/0 | +112/0 | append stream | **UNION** |
| `_System/CuratorLog.md` | +13/0 | +18/0 | append log | **UNION** |
| `_System/CuratorQueue.md` | +7/0 | +141/0 | queue (both append) | **UNION** |
| `_System/CLAUDE.md` | +1/0 | **+21/−11** | shared protocol | **REVIEW — the one real decision** (see Strategy) |

Note: the 3 VPS WIP files (2026-05-10, 2026-05-12, CuratorLog) are VPS-only-changed, NOT in the overlap — they don't conflict with laptop, they just need committing in STEP 6.

---

## STEP 4 — MERGE STRATEGY PER CONTENT CLASS

Applied to the inventory above (Rocky's rules):

- **Daily notes / `_Log.md` / `CuratorLog` / append streams (`events.ndjson`, `CuratorQueue`) → UNION.** Both sides true; keep every appended block from both, delete only the `<<<< ==== >>>>` markers. Covers `_Log.md`, `events.ndjson`, `CuratorLog.md`, `CuratorQueue.md`.
- **State / config files (`state.json`, `*.bak`, schema files) → NEWEST-WINS, named explicitly.** None of the 6 overlap files are state/config — so no newest-wins call needed in the conflict set. (State files changed on only one side auto-merge.) If any surface during the merge, list and take the newer mtime; do not hand-blend JSON.
- **CLAUDE.md tiers → LAPTOP WINS.** ⚠️ Caveat for `_System/CLAUDE.md`: this is the **shared AI Team Protocol**, not a personal global/tier-2/tier-3 file. Laptop changed only **+1 line**; VPS made the substantive edit (**+21/−11**). Blanket "laptop wins" would **discard real VPS protocol work**. RECOMMENDATION: at execution, read the VPS `+21/−11` diff; default to **take VPS's protocol body + re-apply laptop's 1-line add** (union-leaning), unless the VPS −11 removed something laptop deliberately set. This is the single file to eyeball tonight. (Today's actual verified CLAUDE.md fixes were to `~/.claude/tier-2-LFCS-CLAUDE.md`, which is OUTSIDE this repo — not in this merge at all.)
- **Hermes / site code on the VPS chain → VPS WINS.** Laptop never touched it; all such files are VPS-only-changed → auto-merge, no conflict.

---

## STEP 5 — EXECUTE THE RECONCILE (gated; run as ccuser unless noted)

```bash
# 5a. shelve WIP
git stash push -u -m "VPS WIP pre-recovery 2026-06-11" && git stash list

# 5b. clear the dead rebase (rebase-merge is root-owned → sudo rm if abort can't)
git rebase --abort 2>/dev/null || true
sudo rm -rf .git/rebase-merge
git status   # expect "On branch main", not "no branch"

# 5c. point main at the real VPS work (tag guarantees reachability)
git checkout main
git reset --hard vps-detached-safety-2026-06-11   # main = ff0ca1d4 (156 commits)

# 5d. the divergence merge
git fetch origin
git merge origin/main
#   -> resolve ONLY _System/CLAUDE.md by hand (STEP 4). The 4 union files: keep both blocks.
#      2626-BOQ: identical, no conflict.
for f in <resolved files>; do git add "$f"; done
git commit   # completes merge
```

---

## STEP 6 — RESTORE WIP
```bash
git stash pop
# 2026-05-12.md inline-rewrite decision (Rocky): accept "Homebush Solutions", OR restore
#   "Mack Civil / Nihar Reddy" + append the correction as a new dated note with backlink.
git add -A && git commit -m "vps-recovery: restore pre-recovery WIP 2026-06-11"
```

---

## STEP 7 — POST-MERGE VALIDATION (before re-enabling anything)

**7a. Curator pass on the merged vault:**
```bash
# run the weekly curator / vault-verify pass against the merged tree
bash scripts/vault-verify.sh 2>&1 | tail -30      # (confirm exact curator entrypoint at run time)
```
Expect: no broken links / no append-only violations / no orphan flags introduced by the merge.

**7b. File-count diff vs BOTH pre-merge heads** (catch any silent drop):
```bash
git ls-tree -r --name-only origin/main | sort > /tmp/cnt_laptop.txt
git ls-tree -r --name-only vps-detached-safety-2026-06-11 | sort > /tmp/cnt_vps.txt
git ls-tree -r --name-only HEAD | sort > /tmp/cnt_merged.txt
echo "laptop=$(wc -l </tmp/cnt_laptop.txt) vps=$(wc -l </tmp/cnt_vps.txt) merged=$(wc -l </tmp/cnt_merged.txt)"
echo "=== in a pre-merge head but MISSING from merge (should be EMPTY) ==="
comm -23 <(cat /tmp/cnt_laptop.txt /tmp/cnt_vps.txt | sort -u) /tmp/cnt_merged.txt
```
PASS = merged count ≈ union of both heads, and the "MISSING" list is empty. Any missing file = STOP, investigate, do not push.

**7c. Push only after 7a+7b pass:**
```bash
git push origin main   # NO --force. If rejected, STOP and re-diagnose.
```

**7d. Confirm both sides equal:**
```bash
# VPS:
git rev-parse main
# laptop:  git fetch origin && git rev-parse origin/main   (must match)
```

---

## STEP 8 — HARDEN auto-sync so this can't recur (before re-enabling cron)

Add a guard to `scripts/auto-sync.sh` that **refuses to commit and alerts Hermes** if any of these are true:
```bash
[ -d .git/rebase-merge ] || [ -d .git/rebase-apply ] || [ -f .git/MERGE_HEAD ] \
  || [ "$(git symbolic-ref -q HEAD)" = "" ]   # detached HEAD
```
Also: ensure the cron runs as **ccuser**, never root (root ownership in `.git` was the trigger). Then re-enable per STEP 1 RE-ENABLE.

---

## ABORT CRITERIA

- **Threshold:** if the conflicted-file set ever exceeds **~15 files**, or any single conflict needs more than ~200 lines of hand-reconciliation, STOP and split the merge (reconcile `_System/` first, then `Operations/Jobs/`, then the rest as separate merges off the tag).
- **Current state: 6 overlap files, 1 needing real review, max single change a 141-line append-union → FAR under threshold. One sitting is fine. Proceed.**
- Any STEP-7 validation failure (missing files, curator violations, push rejected) → STOP, roll back, re-plan.

## ROLLBACK
```bash
sudo rm -rf /home/ccuser/rateright-growth
sudo tar xzf /root/rrg-prebackup-2026-06-11.tar.gz -C /home/ccuser
sudo chown -R ccuser:ccuser /home/ccuser/rateright-growth
```
Tag `vps-detached-safety-2026-06-11` and origin/main are independent additional safety nets.

## OPEN DECISIONS FOR ROCKY (resolve at execution)
1. `_System/CLAUDE.md` — confirm union-lean (take VPS protocol body + laptop's 1 line), or strict laptop-wins?
2. `2026-05-12.md` inline rewrite — accept "Homebush Solutions" correction, or restore + append?
3. Confirm `opsman-control-centre/scripts-live-sync.mjs` (the `*/5` cron) does/doesn't write into the repo — affects re-enable order.

→ [[01_Daily/2026-06-11]] · [[Restart-Cheatsheet]] · [[VPS-State-2026-05-01]]
