> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Repository Sync Workflow

> How the Encore OS repositories stay in sync — canonical source, bidirectional flow, and how both repos converge to identical development tips.

**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

| Repo                          | Git remote (this clone)   | Role                            | Who pushes                                                     | Default branch |
| ----------------------------- | ------------------------- | ------------------------------- | -------------------------------------------------------------- | -------------- |
| `Encore-OS/encoreos`          | `encoreos` (and `origin`) | **Canonical / source of truth** | Cursor agents (via PR), Claude agents (via PR), manual commits | `development`  |
| `Encore-OS/encoreos-87a1bffc` | `encoreos_lovable`        | **Lovable fork**                | `lovable-dev[bot]` (direct push), Cursor agents (via PR)       | `development`  |

> 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:

```
  Lovable fork (encoreos_lovable/development)
        │  1. sync:pull  -> CI-gated PR into canonical
        v
  encoreos/development (canonical)  -- 2. sync:mirror (fast-forward) --> Lovable fork
```

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

| Command               | Effect                                                                                                                                                           |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `npm run sync:check`  | Report drift (ahead/behind) between the two `development` tips. Exit 0 = converged, exit 2 = diverged.                                                           |
| `npm run sync:pull`   | Lovable -> canonical: create `chore/sync-lovable-<date>` off `encoreos/development`, merge `encoreos_lovable/development`, print the gated push + PR commands.   |
| `npm run sync:mirror` | canonical -> Lovable: print the gated fast-forward push that brings `encoreos/development` onto `encoreos_lovable/development`. Refuses if Lovable has diverged. |
| `npm run sync:verify` | Assert both `development` tips are the identical SHA.                                                                                                            |

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.

### Branch protection (recommended on both repos' `development`)

* **Block force pushes** (most critical).
* Require PR reviews before merge (recommended).
* Require status checks (recommended).

## Procedures

### Drift check (run anytime)

```bash theme={null}
npm run sync:check
```

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

### Lovable -> canonical (bring Lovable work into canonical)

```bash theme={null}
npm run sync:pull        # creates chore/sync-lovable-<date>, merges Lovable
# resolve conflicts if any, then:
npm run validate && npm run test:baseline
git push encoreos chore/sync-lovable-<date>
gh pr create --base development --head chore/sync-lovable-<date> --label lovable-sync \
  --title "sync: Lovable -> canonical (<date>)" --body "<summary>"
```

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)

```bash theme={null}
npm run sync:mirror      # prints the fast-forward push command
git push encoreos_lovable encoreos/development:refs/heads/development
npm run sync:verify      # converged: both development at <sha>
```

`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.
