coily GitHub and Forgejo mirrors have forked divergent feature work on both sides #148

Closed
opened 2026-05-28 11:04:07 +00:00 by coilysiren · 2 comments
Owner

Symptom

coily's origin has two push URLs (GitHub + Forgejo mirror), but git push origin main succeeds on GitHub and is rejected (fetch first) on Forgejo. The two remotes have forked, not merely fallen behind.

As of 2026-05-28, fetching both main tips shows divergent history:

  • Forgejo-only: dca52c5 chore(formula): bump to v2.46.0 [skip ci], 2822824 fix(forgejo): rename max var to avoid revive redefines-builtin-id, 2865833 feat(forgejo): add fj alias for coily ops forgejo, ebf6574 lockdown: sync to coily v2.45.0 [skip ci], 3a2ca1c chore(formula): bump to v2.45.0 [skip ci], df5a17f feat: add sync-lockdown release job, fix reserved FORGEJO_PAT secret name, 8be1ccd feat(forgejo): read actions task logs over HTTPS, drop SSH, plus a 9b96635 lockdown-sync.
  • GitHub-only: f6e9ba5 (this isolation-inversion bump), 1e4faf6 (expose consult surface), 96d828f (a .claude lockdown sync).

So real feature work (fj alias, forgejo actions-log reader, sync-lockdown release job) lives only on Forgejo, while the consult surface + dispatch isolation work lives only on GitHub.

Impact

  • closes #N trailers pushed to GitHub never auto-close the matching Forgejo issue (had to close coilysiren/coily#145 manually).
  • Dispatch worktrees are cut from the GitHub-tracking local checkout, so dispatched workers build on the GitHub line and silently miss the Forgejo-only feature work (and vice versa).
  • Any blunt "force-sync one onto the other" loses one side's commits.

Likely cause

Automated jobs ([skip ci] formula/lockdown syncs) and some feature commits land directly on Forgejo main without replaying to GitHub, while developer/dispatch work lands on GitHub. Neither remote is a strict ancestor of the other anymore.

Ask

Decide the single write source of truth for coily (GitHub vs Forgejo), reconcile the two main histories (merge the divergent commits, or replay one side), and fix the automation so the mirror stops forking. Sibling drift in cli-guard is filed as coilysiren/cli-guard#36. Surfaced while landing coilysiren/coily#145.

## Symptom `coily`'s `origin` has two push URLs (GitHub + Forgejo mirror), but `git push origin main` succeeds on GitHub and is rejected (`fetch first`) on Forgejo. The two remotes have **forked**, not merely fallen behind. As of 2026-05-28, fetching both `main` tips shows divergent history: - Forgejo-only: `dca52c5 chore(formula): bump to v2.46.0 [skip ci]`, `2822824 fix(forgejo): rename max var to avoid revive redefines-builtin-id`, `2865833 feat(forgejo): add fj alias for coily ops forgejo`, `ebf6574 lockdown: sync to coily v2.45.0 [skip ci]`, `3a2ca1c chore(formula): bump to v2.45.0 [skip ci]`, `df5a17f feat: add sync-lockdown release job, fix reserved FORGEJO_PAT secret name`, `8be1ccd feat(forgejo): read actions task logs over HTTPS, drop SSH`, plus a `9b96635` lockdown-sync. - GitHub-only: `f6e9ba5` (this isolation-inversion bump), `1e4faf6` (expose consult surface), `96d828f` (a .claude lockdown sync). So real feature work (fj alias, forgejo actions-log reader, sync-lockdown release job) lives only on Forgejo, while the consult surface + dispatch isolation work lives only on GitHub. ## Impact - `closes #N` trailers pushed to GitHub never auto-close the matching Forgejo issue (had to close coilysiren/coily#145 manually). - Dispatch worktrees are cut from the GitHub-tracking local checkout, so dispatched workers build on the GitHub line and silently miss the Forgejo-only feature work (and vice versa). - Any blunt "force-sync one onto the other" loses one side's commits. ## Likely cause Automated jobs (`[skip ci]` formula/lockdown syncs) and some feature commits land directly on Forgejo `main` without replaying to GitHub, while developer/dispatch work lands on GitHub. Neither remote is a strict ancestor of the other anymore. ## Ask Decide the single write source of truth for `coily` (GitHub vs Forgejo), reconcile the two `main` histories (merge the divergent commits, or replay one side), and fix the automation so the mirror stops forking. Sibling drift in cli-guard is filed as coilysiren/cli-guard#36. Surfaced while landing coilysiren/coily#145.
Author
Owner

History reconciled (merge 9ee11f8)

Merged the two forked main tips with a merge commit whose parents are the GitHub tip (f6e9ba5) and the Forgejo tip (dca52c5). Because each tip is an ancestor of the merge, pushing it fast-forwarded both remotes - no commits lost, no force-push.

Both remotes now point at 9ee11f8 (verified via git ls-remote on each). Both feature lines are reachable from HEAD:

  • Forgejo-only work preserved: fj alias, forgejo actions-log reader over HTTPS, sync-lockdown release job, formula v2.45/2.46 bumps, lockdown syncs.
  • GitHub-only work preserved: consult surface, dispatch isolation inversion (#145).

The file sets were disjoint except .claude/settings.json. That is a generated lockdown artifact, so I resolved it by keeping the stricter render (the larger fine-grained deny list + vault Read allows). The only delta vs the Forgejo render was Forgejo's Bash(mcporter:*) allow entry, which is dropped - losing an allow fails safe (mcporter will prompt), never fail-open. I did not regenerate settings.json from the merged binary: that would rewrite the lockdown permission posture, which is out of scope here and a separate lockdown-sync concern.

Merged tree verified green: tidy, build, test, vet, lint all pass (Forgejo's ops_forgejo* code builds fine against the GitHub-side cli-guard bump).

Still open: the automation that lets the mirrors fork

This merge unifies history once, but it does not stop the recurrence. The root cause stands: automated jobs ([skip ci] formula/lockdown syncs) and some feature commits land directly on one remote without replaying to the other, so the next such commit re-forks main. Keeping this issue open, narrowed to that fix:

  • Pick one write source of truth for coily (GitHub vs Forgejo) and make the other a strict read-only mirror, or
  • Wire the automated jobs / release workflow to push to both remotes (the same way a manual git push origin main does, via the two origin push URLs), or run a scheduled mirror-sync.

Two follow-on details worth a look while fixing the automation:

  1. The committed .claude/settings.json render drifts from what the current merged binary produces (coarser Bash(git:*) vs per-subcommand denies, etc.). That is the recurring "sync committed .claude lockdown files to coily vX render" chore, orthogonal to the mirror fork but visible here.
  2. Sibling drift in cli-guard is filed as coilysiren/cli-guard#36 and has the same automation root cause.
## History reconciled (merge `9ee11f8`) Merged the two forked `main` tips with a merge commit whose parents are the GitHub tip (`f6e9ba5`) and the Forgejo tip (`dca52c5`). Because each tip is an ancestor of the merge, pushing it **fast-forwarded both remotes** - no commits lost, no force-push. Both remotes now point at `9ee11f8` (verified via `git ls-remote` on each). Both feature lines are reachable from `HEAD`: - Forgejo-only work preserved: `fj` alias, forgejo actions-log reader over HTTPS, sync-lockdown release job, formula v2.45/2.46 bumps, lockdown syncs. - GitHub-only work preserved: consult surface, dispatch isolation inversion (#145). The file sets were disjoint except `.claude/settings.json`. That is a generated lockdown artifact, so I resolved it by keeping the stricter render (the larger fine-grained deny list + vault Read allows). The only delta vs the Forgejo render was Forgejo's `Bash(mcporter:*)` *allow* entry, which is dropped - losing an allow fails safe (mcporter will prompt), never fail-open. I did **not** regenerate `settings.json` from the merged binary: that would rewrite the lockdown permission posture, which is out of scope here and a separate lockdown-sync concern. Merged tree verified green: `tidy`, `build`, `test`, `vet`, `lint` all pass (Forgejo's `ops_forgejo*` code builds fine against the GitHub-side cli-guard bump). ## Still open: the automation that lets the mirrors fork This merge unifies history once, but it does **not** stop the recurrence. The root cause stands: automated jobs (`[skip ci]` formula/lockdown syncs) and some feature commits land directly on **one** remote without replaying to the other, so the next such commit re-forks `main`. Keeping this issue open, narrowed to that fix: - Pick one write source of truth for `coily` (GitHub vs Forgejo) and make the other a strict read-only mirror, or - Wire the automated jobs / release workflow to push to **both** remotes (the same way a manual `git push origin main` does, via the two `origin` push URLs), or run a scheduled mirror-sync. Two follow-on details worth a look while fixing the automation: 1. The committed `.claude/settings.json` render drifts from what the current merged binary produces (coarser `Bash(git:*)` vs per-subcommand denies, etc.). That is the recurring "sync committed .claude lockdown files to coily vX render" chore, orthogonal to the mirror fork but visible here. 2. Sibling drift in cli-guard is filed as coilysiren/cli-guard#36 and has the same automation root cause.
Author
Owner

Merged into #5 in the 2026-05-29 backlog burn-down. Same multi-URL origin push divergence (GitHub vs Forgejo) Reopen if it should stand alone.

Merged into #5 in the 2026-05-29 backlog burn-down. Same multi-URL origin push divergence (GitHub vs Forgejo) Reopen if it should stand alone.
Sign in to join this conversation.
No labels
P0
P1
P2
P3
P4
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-bridge/coily#148
No description provided.