Skip to main content
Last Updated: 2026-05-24 Status: Active — single source of truth for cross-repo sync (supersedes the retired CROSS-REPO-SYNC-POLICY.md).

Repository Topology

Verify your remotes match: git remote -v. The commands below assume encoreos = canonical and encoreos_lovable = the Lovable fork. If your clone names them differently, adjust accordingly.

Sync Direction (two-way reconciliation)

encoreos is canonical. Both repos stay active, so changes flow both ways and converge to identical development tips:
  1. Lovable -> canonical: merge Lovable’s commits into canonical via a CI-gated PR (npm run sync:pull).
  2. canonical -> Lovable: after that PR merges, fast-forward Lovable’s development up to canonical (npm run sync:mirror).
“In sync” is defined precisely: git rev-parse encoreos/development and git rev-parse encoreos_lovable/development resolve to the same SHA.

Commands

The scripts print outward commands (push / gh pr create) rather than running them — every remote write stays under human control.

Critical Rules

Never force-push development

Force-pushing development in either repo erases merged PR history — the #1 cause of lost work here (see the May 18 2026 incident below). The sync tooling never force-pushes; sync:mirror only ever does a fast-forward and refuses otherwise. If you genuinely must reset: create a backup branch first (git branch backup/development-YYYY-MM-DD), then proceed manually.

Pause Lovable during merges

lovable-dev[bot] pushes directly to the fork’s development. Merging canonical PRs while Lovable is actively editing diverges the histories immediately. Either pause Lovable editing before merging, or re-run npm run sync:pull to fold Lovable’s latest in before mirroring.
  • Block force pushes (most critical).
  • Require PR reviews before merge (recommended).
  • Require status checks (recommended).

Procedures

Drift check (run anytime)

Exit 0 = converged. Exit 2 = diverged (prints ahead/behind + merge-base).

Lovable -> canonical (bring Lovable work into canonical)

Let CI run (4-shard vitest, RLS, governance, baseline gate). Fix failures on the branch. Merge with a merge commit (not squash) so both parent histories are preserved and the merge-base advances.

canonical -> Lovable (converge the fork after merging)

sync:mirror refuses if the fork has diverged again — run sync:pull first. Never add --force.

Automation

.github/workflows/lovable-sync.yml runs weekly (and on demand). It performs the Lovable -> canonical merge and opens/updates a lovable-sync PR (or a conflicts-labeled PR with a checklist if the merge is no longer clean). It never auto-merges and never pushes to the fork — the merge and the mirror push stay human-driven, consistent with the repo’s “open PRs, humans merge” policy. Requires repo secret LOVABLE_SYNC_TOKEN (read the fork + open PRs on canonical).

Troubleshooting

  • sync:mirror says Lovable diverged / push rejected (non-fast-forward): the fork got new commits. Run sync:pull, merge that PR, then sync:mirror. Do not add --force.
  • sync:verify says NOT converged after mirror: the mirror push didn’t land — re-check npm run sync:check and re-run the push.

Incident: May 18, 2026 Force Push

On May 18 at 22:34 UTC, development on the Lovable fork was force-pushed from a state with 14 merged Cursor PRs to a reconciliation commit that didn’t include them. Root cause: the reconciliation PR was based on an older state of development, and the force push replaced the post-merge state. Recovery: all source branches were preserved; content was verified file-by-file and recovered via PRs #362 (encoreos) and #71 (fork). Prevention: block force pushes on development in both repos; the sync tooling never force-pushes.