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

4.2 KiB

name, description
name description
deployment-checkout-trunk-sync 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).