Files
command-center/agent/managed-skills/deployment-checkout-trunk-sync/SKILL.md
T

71 lines
4.2 KiB
Markdown

---
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-<date>/`, 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' <dangling>` to date
them → `git show <c>:<path>` 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).