--- name: deployment-checkout-trunk-sync description: Use when the live deployment checkout (~/.omp main) must merge a moved origin/main while dirty tracked files block the merge and workspace policy blocks git checkout. --- --- name: deployment-checkout-trunk-sync description: Use when the live deployment checkout (~/.omp main) must merge a moved origin/main while dirty tracked files block the merge and workspace policy blocks git checkout. --- # Sync a dirty live checkout to a deployment (checkout blocked) Situation: the checkout IS the deployment; months of machine/hand writes sit uncommitted; `origin/main` has moved; `git checkout`/discard is BLOCKED by workspace policy ("edit forward"; exemption only during active conflict). ## Procedure 1. `git fetch`; trial `git merge --no-commit --no-ff origin/main` to enumerate exact blockers (dirty files the merge would overwrite + untracked collisions). Untracked blockers: `cp -a` to `.AGENTTRASH/pre-merge-/`, then `mv` aside. 2. **Preservation commit:** `git add` ONLY the blocking paths (not the whole tree) and commit them as-is: `chore: adopt pre-existing working-tree state before trunk merge`. Nothing is discarded; the secret gate still runs. Include EVERY dirty deployment-state path (dotfiles/live tiers too) — a dirty file that is neither committed nor trashed is unprotected from step 3. 3. `git merge --no-ff origin/main`. Conflicts are now resolvable — the policy exemption is active during a merge. 4. Resolution law: - **live machine config** (`agent/config.yml`, `models.yml`, dotfiles live state like noctalia `settings.toml`) → `--ours`: the running box is its own authority; the remote copy is a snapshot. - **prose/law/docs** (`AGENTS.md`, KB) → `--theirs` (upstream canonical; local variants survive in the preservation commit). - **append-mostly logs** → union: cut only the three marker lines (`<<<<<<<`/`=======` range + `>>>>>>>`), keep both sides' entries. 5. `git commit --no-edit`, push trunk, verify `main == origin/main`. 6. Pre-merge byte-compare every dirty file vs `origin/main` (`git show origin/main:$f | diff -q - $f`): SUPERSEDED (identical → discardable), DIVERGED (resolve), untracked-in-upstream (collision). ## Gotchas - **NEVER `git stash` to unblock a deployment sync, NEVER `git stash clear`/ `drop` afterward.** Observed 2026-10-18: a sync stashed the dirty tree, the stash entry was later destroyed, and months of GUI-built bar layout (noctalia settings.toml, never committed) vanished with it — recovered only via dangling-object archaeology (below). Step 2's preservation commit exists precisely so stashing is never needed. - **Stash-and-retry loops are a red flag**: three `WIP on main` stash commits within ~60s of each other means the operator was fighting the dirty tree, not resolving it. - **Recovery from destroyed stashes** (objects survive entry deletion until gc): `git fsck --lost-found` → `git log -1 --format='%ci %s' ` to date them → `git show :` to dump candidates; newest `WIP on` commit is usually the last good state. Validate before deploying (e.g. `noctalia config validate`), back up the clobbered file to `.AGENTTRASH/`, then restore through the symlink target. - Never wrap `git checkout` in `2>/dev/null` here: the policy-block error was swallowed and the loop silently no-op'd; the merge then failed identically. - `git add` a directory pathspec stages its untracked children (fine for allowlist dirs; never for prose dirs). - The live-sync heartbeat (#11) commits machine tiers hourly, so this sync is a rare operation post-deployment — mostly memories/dotfiles stragglers. Remember the heartbeat can lag up to an hour behind GUI edits: the tree between heartbeats is the ONLY copy of fresh GUI work. - **Frank's accepted risk posture (2026-10-18):** hourly sweep + the preservation-commit law + fsck recovery is defense-in-depth ENOUGH. Do not re-propose faster heartbeats or path/event triggers to shrink the GUI-edit-to-commit window; he chose status quo after measuring (heartbeat itself is 57 ms CPU — cost was never the objection; un-debounced DirectoryNotEmpty triggering was, and path-unit proposals are vetoed).