# ADR-003: Force-with-Lease for Forward Sync **Status:** Accepted **Date:** 2026-01 ## Context Forward sync pushes monorepo changes to the subrepo. If someone pushes directly to the subrepo between when josh-sync reads its HEAD and when josh-sync pushes, a naive `git push` would overwrite their work. A `git push --force` would be worse — it would silently destroy concurrent changes. ## Decision Use `git push --force-with-lease=refs/heads/:` for all forward sync pushes. The expected SHA is recorded at the start of the sync operation (the "lease"). ### How it works 1. Record subrepo HEAD SHA before any operations: `subrepo_sha=$(subrepo_ls_remote "$branch")` 2. Perform merge of monorepo changes onto subrepo state 3. Push with explicit lease: `--force-with-lease=refs/heads/main:` 4. If the subrepo HEAD changed since step 1, git rejects the push 5. Josh-sync reports `lease-rejected` and retries on the next run ## Consequences **Positive:** - Never overwrites concurrent changes — git atomically checks the expected SHA - Explicit SHA lease (not just "current tracking ref") prevents stale-ref bugs - Failed leases are retried on the next sync run — no data loss, just delay - Works correctly with josh-proxy's SHA mapping **Negative:** - Lease-rejected means the sync run did work that gets discarded (clone, merge, etc.) - Persistent lease failures indicate a concurrent push pattern that needs investigation - Requires the `--force-with-lease` flag with explicit SHA — the shorthand form (`--force-with-lease` without `=`) is unsafe because it uses the local tracking ref, which may be stale