test: add git-branch divergence matrix + replay fidelity guards (D1, D4, D5) · Entire

test: add git-branch divergence matrix + replay fidelity guards (D1, D4, D5)

ea4cc21·

Soph·1w ago·2 files·+505 added/-0 removed

Systematize the local-v1 divergence & recovery matrix (the most re-broken area, #953/#1251/#1252/#1260) plus the specifically-untested replay edges.

D1 (integration, git-branch)

drive the local-v1 state {ahead, behind, diverged, disconnected} through the real triggers end-to-end:

D4 (strategy unit)

replay fidelity edges. A no-op commit must not clobber the remote tip's accumulated tree (regression 743c43f4c); a root-commit chain replays cleanly. Plus a KNOWN BUG pin: >1000-commit replay is still capped (collectCommitsSince) because the cap-removal (4cf01edb3) lives on the unmerged branch origin/no-limit; flip the assertion when it lands.

D5 (strategy)

TOCTOU guard for 1e8628ade -- fetchAndRebaseRefCommon replays onto the freshly fetched remote tip, not a stale earlier hash. The literal ls-remote seam the fix patched no longer exists (fix is an ancestor), so this pins the behavioural invariant.

Sessions

b19f4c2ff3bdView transcript

Changes

2

//go:build integration

package integration

import (
    "os/exec"
    "strings"
    "testing"
    "github.com/entireio/cli/cmd/entire/cli/paths"
    "github.com/entireio/cli/cmd/entire/cli/testutil"
    "github.com/stretchr/testify/require"
)

// =============================================================================
// D1 -- git-branch divergence & recovery matrix
// Systematizes the local-v1 state {ahead, behind, diverged, disconnected}
// missing} x trigger {pre-push, explain fetch-on-miss, doctor} matrix that the
// #953/#1251/#1252/#1260 fixes patched piecemeal.
// The reconcile engine itself
// (SafelyAdvanceLocalRef, ReconcileDisconnectedMetadataRef, cherryPickOnto) is
// unit-tested exhaustively in the strategy package (safely_advance_local_ref_test.go,
// metadata_reconcile_test.go);

func advanceRemoteV1(t *testing.T, srcEnv *TestEnv, bareDir, prompt string) string {
    t.Helper()

other := srcEnv.CloneFrom(bareDir)
    other.GitCheckoutNewBranch("feature/remote-advance")
    cp := createCheckpointedCommit(t, other, prompt, "remote_adv.go", "package remoteadv", prompt)
    require.NotEmpty(t, cp, "remote-advance clone should produce a checkpoint")
    other.RunPrePush("origin")
    require.True(t, srcEnv.CheckpointExistsOnRemote(bareDir, cp),
        "remote v1 should carry the advanced checkpoint after the clone pushed")
    return cp
}

func TestDivergedV1_PrePushMatrix(t *testing.T) {
    t.Parallel()

for _, state := range []string{"ahead", "behind", "diverged", "disconnected"} {
        t.Run(state, func(t *testing.T) {
            t.Parallel()

env := NewFeatureBranchEnv(t)
            bareDir := env.SetupBareRemote()

baseCP := createCheckpointedCommit(t, env, "base work", "base.go", "package base", "base work")
            require.NotEmpty(t, baseCP)
            env.GitPush("origin", "HEAD")
            env.RunPrePush("origin")

var localCP, remoteCP string
            switch state {
            case "ahead":
                localCP = createCheckpointedCommit(t, env, "local ahead", "ahead.go", "package ahead", "local ahead")
            case "behind":
                remoteCP = advanceRemoteV1(t, env, bareDir, "remote behind work")
            case "diverged":
                localCP = createCheckpointedCommit(t, env, "local diverge", "diverge.go", "package diverge", "local diverge")
                remoteCP = advanceRemoteV1(t, env, bareDir, "remote diverge work")
            case "disconnected":
                localCP = "abcdef012345"
                forceLocalV1Orphan(t, env, localCP)
            }

trigger := "push-trigger-" + state + ".txt"
            env.WriteFile(trigger, "x")
            env.GitAdd(trigger)
            env.GitCommit("push trigger (" + state + ")")

env.GitPushWithHooks("origin", "HEAD")

require.True(t, env.CheckpointExistsOnRemote(bareDir, baseCP),
                "[%s] base checkpoint must always survive on the remote", state)
            switch state {
            case "ahead":
                require.True(t, env.CheckpointExistsOnRemote(bareDir, localCP),
                "ahead: local-only checkpoint should fast-forward onto the remote")
            case "behind":
                require.True(t, env.CheckpointExistsOnRemote(bareDir, remoteCP),
                "behind: the remote's checkpoint must remain")
            case "diverged":
                require.True(t, env.CheckpointExistsOnRemote(bareDir, localCP),
                "diverged: local checkpoint must be replayed onto the remote")
                require.True(t, env.CheckpointExistsOnRemote(bareDir, remoteCP),
                "diverged: remote checkpoint must be preserved (not overwritten)")
                require.Equal(t, 1, env.GetBranchTipParentCount(paths.MetadataBranchName),
                "diverged: local v1 tip must be linear after replay (double-replay guard, #1260)")
            case "disconnected":
                require.True(t, env.CheckpointExistsOnRemote(bareDir, localCP),
                "disconnected: orphaned local checkpoint must be cherry-picked onto the remote")
            }

before := env.RemoteCheckpointState(bareDir)
            env.RunPrePush("origin")
            after := env.RemoteCheckpointState(bareDir)
            require.Equal(t, before, after,
                "[%s] a repeated pre-push must not re-replay or otherwise mutate the remote", state)
        })
    }
}

func TestDivergedV1_DoctorReconcilesDisconnected(t *testing.T) {
    t.Parallel()

env := NewFeatureBranchEnv(t)
    bareDir := env.SetupBareRemote()

baseCP := createCheckpointedCommit(t, env, "base work", "base.go", "package base", "base work")
    require.NotEmpty(t, baseCP)
    env.GitPush("origin", "HEAD")
    env.RunPrePush("origin")
    require.True(t, env.CheckpointExistsOnRemote(bareDir, baseCP))

env.FetchMetadataBranch(bareDir)
    orphanCP := "abcdef012345"
    forceLocalV1Orphan(t, env, orphanCP)

out := env.RunCLI("doctor", "--force")
    require.Contains(t, out, "reconciled", "doctor should report it reconciled the disconnected branches")

require.True(t, env.FileExistsInBranch(paths.MetadataBranchName, CheckpointSummaryPath(baseCP)),
    "doctor: remote base checkpoint must be present locally after reconcile")
    require.True(t, env.FileExistsInBranch(paths.MetadataBranchName, CheckpointSummaryPath(orphanCP)),
    "doctor: orphaned local checkpoint must survive the reconcile")
}