# Preserve Local Checkpoint Policy Ahead State

`9e881cb` → [main](/content/gh/entireio/cli/commits/main/index.html) ·  pfleidi · 3w ago · 2 files · +38 added / -5 removed

Teach checkpoint policy sync to treat a local policy ref ahead of the remote as local state instead of divergence.

Add regression coverage for the linear unpushed policy case.

## Sessions

e35d103fb746 View transcript

## Changes

2

- cmd/entire/cli/checkpointpolicy

- Mremote.go +9
  
  - Mremote_test.go +29 / -5

```
92 unmodified lines

93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

92 unmodified lines

return baseline, nil
	}

baselineAncestor, err := isAncestorOf(ctx, repo, baseline.Hash, local.Hash)
	if err != nil {
		return State{}, err
	}
	if baselineAncestor {
		local.RemoteHash = baseline.RemoteHash
		return local, nil
	}

local.Source = SourceLocalDiverged
	local.RemoteHash = baseline.RemoteHash
	return local, nil
}
```

Mcmd/entire/cli/checkpointpolicy/remote.go +9

```
54 unmodified lines

55
56
57
58
58
59
60
61
24 unmodified lines

86
87
88
89
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
4 unmodified lines

121
122
123
100
124
125
126
127
88 unmodified lines

216
217
218
195
219
220
197
221
222
223

54 unmodified lines

require.Equal(t, checkpointpolicy.SourceRemote, got.Source)
	require.Equal(t, localHash, got.Hash)
	require.Equal(t, localHash, got.RemoteHash)
	requireNoRef(t, repo, "refs/entire/policies/checkpoint-fetch")
	requireNoPolicyFetchRef(t, repo)
}

func TestSyncRemotePolicyKeepsDivergedLocalRef(t *testing.T) {
24 unmodified lines

localState, err := checkpointpolicy.ReadLocal(t.Context(), localRepo)
	require.NoError(t, err)
	require.Equal(t, localHash, localState.Hash)
	requireNoRef(t, localRepo, "refs/entire/policies/checkpoint-fetch")
	requireNoPolicyFetchRef(t, localRepo)
}

func TestSyncRemotePolicyKeepsLocalRefAheadOfRemote(t *testing.T) {
	remoteDir, remoteRepo, bareDir := initPolicyRemoteFixture(t)
	baseHash, err := checkpointpolicy.WriteLocal(t.Context(), remoteRepo, plumbing.ZeroHash, checkpointpolicy.DefaultPolicy())
	require.NoError(t, err)
	pushPolicyRefWithGit(t, remoteDir, bareDir)

localDir, localRepo := initPolicyRepoWithDir(t)
	_, err = checkpointpolicy.Sync(t.Context(), localRepo, checkpointpolicy.Target{Remote: bareDir, Dir: localDir})
	require.NoError(t, err)
	localHash, err := checkpointpolicy.WriteLocal(t.Context(), localRepo, baseHash, checkpointpolicy.DefaultPolicy())
	require.NoError(t, err)

got, err := checkpointpolicy.Sync(t.Context(), localRepo, checkpointpolicy.Target{Remote: bareDir, Dir: localDir})
	require.NoError(t, err)
	require.Equal(t, checkpointpolicy.SourceLocal, got.Source)
	require.Equal(t, localHash, got.Hash)
	require.Equal(t, baseHash, got.RemoteHash)

localState, err := checkpointpolicy.ReadLocal(t.Context(), localRepo)
	require.NoError(t, err)
	require.Equal(t, localHash, localState.Hash)
	requireNoPolicyFetchRef(t, localRepo)
}

func TestSyncRemotePolicyRemovesTempRefWhenFetchedPolicyCannotBeRead(t *testing.T) {
4 unmodified lines

localDir, localRepo := initPolicyRepoWithDir(t)
	_, err := checkpointpolicy.Sync(t.Context(), localRepo, checkpointpolicy.Target{Remote: bareDir, Dir: localDir})
	require.ErrorContains(t, err, "parse policy.json")
	requireNoRef(t, localRepo, "refs/entire/policies/checkpoint-fetch")
	requireNoPolicyFetchRef(t, localRepo)
}

func TestPushPolicyRejectsNonFastForward(t *testing.T) {
88 unmodified lines

require.NoError(t, err, string(output))
}

func requireNoRef(t *testing.T, repo *git.Repository, refName plumbing.ReferenceName) {
func requireNoPolicyFetchRef(t *testing.T, repo *git.Repository) {
	t.Helper()
	_, err := repo.Reference(refName, true)
	_, err := repo.Reference("refs/entire/policies/checkpoint-fetch", true)
	require.ErrorIs(t, err, plumbing.ErrReferenceNotFound)
}
