Files
command-center/omp-docs/tools/live-sync.md
Frank 54f5555470 chore: run live-sync heartbeat hourly
Operator decision at review: 15 min is aggressive for config churn; hourly
keeps the stale-window acceptable (<=1 h) with a fifth of the wakeups.
Timer unit, tier law, and failure-table wording aligned.
2026-10-18 16:28:50 -07:00

76 lines
3.1 KiB
Markdown

---
type: reference
title: live-sync heartbeat
description: Auto-commit daemon for machine-written paths in the command-center checkout — the deployment is live, so symlinks make config churn dirty tracked files continuously.
tags:
- git
- automation
- systemd
- deployment
- fleet
verified: 2026-10-18
timestamp: 2026-10-18
---
# live-sync heartbeat
The command-center checkout IS the deployment, and several tracked files are
live state: the harness writes memories and managed-skills, the operator
edits `config.yml`/`models.yml` through the `cfg://` surface, and desktop
GUIs (Noctalia, niri) rewrite dotfiles through symlinks. Before Refs #11 this
machine churn just piled up unpushed — one disk holding the only copy of ~61
auto-learned skills, a settings fix stranded locally, and merge-refusals
because the dirty tree collided with incoming work.
`scripts/live-sync.sh` is the pressure valve: a heartbeat that commits the
machine's own writes on a schedule. Tier law (which paths it may touch) lives
in [AGENTS.md](../../AGENTS.md) § Live-sync tiers.
## Contract (black-box)
Run = one pass: flock → branch guard (`main` only) → stage allowlisted dirty
tiers → commit (hooks armed) → fetch + merge `origin/main` → push → reap
stale `wt/*` worktrees. Exit `0` = quiet heartbeat (synced/no-op/reaped);
exit `1` = an alert was raised. Pinned by `tests/live-sync.bats`.
Hard properties:
- **Allowlist only.** Task dirt (`plugins/`, `omp-docs/`, prose) is never
staged — merge conflicts with in-flight work become impossible by
construction.
- **Hooks stay armed.** A secret-gate refusal aborts the commit, leaves
changes staged for a human, and alerts. Never `--no-verify`, never force.
- **Never fights the remote.** Merge conflict → `merge --abort`, local
commit kept, alert. Retries are automatic next tick.
- **Branch guard.** On a non-`main` checkout it refuses and alerts — same
rule as the doctrine ("never end a session off main").
- **Polite reaper.** `wt/wt-*` worktrees untouched for 7+ days are removed
with their `wt/*` branch; dirty or process-occupied worktrees are skipped.
## Alerts
`notify()` writes stderr always; pushes to ntfy when the topic file
`~/.config/ntfy/live-sync` (mode 600, topic text only) exists, throttled to
one push per hour. Test seams: `LIVE_SYNC_REPO`, `LIVE_SYNC_NOTIFY`,
`LIVE_SYNC_NTFY_TOPIC_FILE`, `LIVE_SYNC_AGE_DAYS`.
## Install
Units ship in `dotfiles/systemd-user/.config/systemd/user/` and propagate
with the usual dotfiles chain:
```bash
systemctl --user enable --now live-sync.timer # after the unit is linked
systemctl --user start live-sync.service # one manual heartbeat
journalctl --user -u live-sync.service -n 20 # observe
```
## Failure modes
| Event | Result |
|-------|--------|
| Harness mid-write | commits a valid snapshot; remainder lands next heartbeat |
| Gitea down | commit safe locally; push retries next tick (≤1 h stale window) |
| Feature branch checked out in main checkout | refuses + alerts; protects the never-end-off-main rule |
| Secret shape in machine-written content | hook blocks, changes stay staged, alert |