Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions docs/backlog/P1/B-0110-acehack-mirror-protocol-drift-2026-04-30.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
---
id: B-0110
priority: P1
status: open
title: AceHack mirror-refresh protocol drift — three sources, three different shapes (Aaron + Amara 2026-04-30)
tier: drift-resolution
effort: S
ask: Maintainer decision required — three sources contradict on AceHack mirror-refresh shape; no autonomous resolution per host-mutation receipt discipline
created: 2026-04-30
last_updated: 2026-04-30
composes_with: [B-0109]
Comment thread
AceHack marked this conversation as resolved.
Comment thread
AceHack marked this conversation as resolved.
tags: [doctrine-drift, acehack, mirror-refresh, branch-protection, host-vs-doctrine, urgent-when-mirror-needed]
---

# AceHack mirror-refresh protocol drift

Three sources currently disagree on how to refresh AceHack/Zeta
main from LFG/Zeta main. Surfaced 2026-04-30 when Aaron asked
for a mirror-refresh and the force-with-lease push was rejected
by AceHack's branch protection. Filed per Amara's discipline
that drift not be parked only on the maintainer's chat history.

## The three sources

### CLAUDE.md (current text)

> *"AceHack = dev-mirror fork; LFG = project-trunk fork."*
>
> *"AceHack main re-mirrors LFG main at the close of every
> paired-sync round (force-push to AceHack main is part of the
> protocol)."*
>
> *"Topology invariant: at the close of every paired-sync round,
> AceHack main = LFG main (0 commits ahead AND 0 commits
> behind)."*

CLAUDE.md asserts force-push is the protocol AND that 0/0/0 is
the maintained invariant.

### `memory/feedback_lfg_only_development_flow_acehack_is_mirror_aaron_amara_2026_04_29.md`

> *"LFG is the factory. AceHack is the mirror."*
>
> *"Stop optimizing the fork topology. We are LFG-first now.
> Mirror AceHack daily and move on."* — Amara 2026-04-29
>
> Daily AceHack sync policy:
>
> - Once per day, sync AceHack/main to LFG/main.
> - Preferred path: fast-forward AceHack/main to LFG/main.
> - If AceHack/main has diverged, hard-reset to LFG/main after
> recording the pre-reset SHA.
> - No Aaron approval needed for routine daily mirror sync
> (this policy is the consent).

This 2026-04-29 memory says: daily mirror sync, preferred
fast-forward, hard-reset if diverged, routine consent.

### AceHack host configuration (verified 2026-04-30T11:46Z)

`gh api repos/AceHack/Zeta/rulesets/15524390` shows the
"Default" ruleset includes `non_fast_forward` rule with
`bypass_actors: []`. The host blocks force-push from any
actor, including repo admins, on the default branch.

LFG ruleset 15256879 has identical `non_fast_forward` +
`bypass_actors: []` shape, intentional uniformity.

## What the drift produces operationally

When `acehack/main` has diverged from `lfg/main` (which is the
expected post-double-hop residue, e.g., the current 1-commit
divergence at `0a1db1a`), the three sources prescribe three
different actions:

- **CLAUDE.md**: force-push LFG main → AceHack main. **Blocked
by host.**
- **LFG-only memory (2026-04-29)**: hard-reset AceHack/main to
LFG/main. Hard-reset on the server-side is also force-push.
**Blocked by host.**
- **AceHack ruleset**: open a PR with linear-history,
required-conversation-resolution, squash-only merge.
Cannot resolve a non-fast-forward via PR (the 1-commit
divergence makes it non-FF, and `required_linear_history`
blocks merge commits).
Comment thread
AceHack marked this conversation as resolved.
Outdated

So the actual operation has no clean path under the current
host config. The reset on 2026-04-29 (visible as the
`archive/acehack-main-pre-000-reset-2026-04-29` branch) must
have happened either through a temporary ruleset relaxation
or as a post-hoc archive marker — that history is itself
worth recovering as part of resolving this drift.

## Decision needed (maintainer call)
Comment thread
AceHack marked this conversation as resolved.
Outdated

One of the three:

1. **Add a bypass actor to AceHack ruleset 15524390** — restore
force-push capability scoped to a specific actor (repo
admin or named bypass). Smallest host mutation; aligns host
with doctrine. Files a host-mutation receipt per the
receipt discipline.
2. **Update CLAUDE.md and the LFG-only memory to a PR-based
mirror protocol** — accept the host as canonical,
adjust doctrine to a PR-shape that doesn't require
force-push (e.g., a "sentinel PR" pattern that resets
AceHack via a series of PRs, OR explicit acceptance that
AceHack will diverge until a manual maintainer reset).
3. **Accept current divergence indefinitely** — pause the 0/0/0
invariant entirely. Document this as the post-2026-04-29
reality. AceHack becomes a distant-cousin mirror, not a
mathematically-equal one.

I'd lean toward **(1)** because it's the smallest mutation
that aligns host with doctrine and preserves the LFG-only
memory's daily-sync semantics. But the host-mutation receipt
discipline (`memory/feedback_host_mutation_receipt_2026_04_29_ruleset_15256879_code_quality_removed.md`)
explicitly says *"do NOT broaden `gh api ... rulesets/PUT`
permission"* — so this is exactly the maintainer-decision
class of mutation, not the autonomous-action class.

## Out of scope for this row

- Implementing the chosen path. Implementation lands as a
separate row + receipt once the maintainer decides.
- Routine mirror-refresh attempts. Until decision, the mirror
stays where it is; the daily-sync clause from the LFG-only
memory cannot fire because the host blocks the only known
mechanism.
- Modifying the AceHack ruleset autonomously. Per the
host-mutation receipt rule, ruleset PUTs need explicit
authorization beyond the standing branch-protection-is-agent-call
rule (which covers settings management, not bypass-actor
definitions for force-push protections).

## Composes with

- **B-0109** — dependency-status surface. AceHack mirror-refresh
is a sub-case of "dependencies we depend on for canonical
factory state"; the drift here is doctrine-vs-host, parallel
to the GitHub-incident class B-0109 covers.
Comment thread
AceHack marked this conversation as resolved.
Outdated
- `memory/feedback_lfg_only_development_flow_acehack_is_mirror_aaron_amara_2026_04_29.md`
— the 2026-04-29 framing this row references.
- `memory/feedback_host_mutation_receipt_2026_04_29_ruleset_15256879_code_quality_removed.md`
— the ruleset-mutation receipt discipline that gates path (1).
- `memory/feedback_branch_protection_settings_are_agent_call_external_contribution_ready_2026_04_23.md`
— the standing agent-decision authority on branch
protection. Bypass-actor changes for force-push protections
fall outside this standing authority because they affect
destructive-operation gating.
- CLAUDE.md AceHack-LFG topology section — currently
out of date with respect to the LFG-only directive; will
need a paired edit once this row resolves.

## Origin

Aaron 2026-04-30 (autonomous-loop maintainer channel):

> can you refresh the acehack mirror whenever you get a
> minute, this is our first time i think so might need a
> force push, i know our rules say something softer but up
> to you

Followed by:

> force-push-to-AceHack-main i think amara said force push
> lease is better becasue then you know if something
> accidently changed next time you update

Attempt: `git push --force-with-lease=main:0a1db1a acehack
origin/main:main`. Result: rejected by ruleset
`non_fast_forward` rule with no bypass actors.

Amara 2026-04-30 review:

> AceHack mirror drift should not stay parked only on Aaron.
> [...] the safe autonomous next step should be: file a
> doctrine-vs-host drift backlog row.

This row is that filing.
Loading